Java: 언제 어디서나 마시는 커피처럼 어디서나 동작 가능한, 자바 커피에서 이름을 따서 만든 언어
- 공통 실행환경 → JVM
- 클래스와 객체가 중요 → 대표적인 객체 지향 언어
cf)System : input에 output이 있음
- 공통 실행환경이 있어 여러 기기에서 실행 가능
- 세상과 닮아있는 개발언어로 유지 보수가 용이 (객체는 특징과 행동이 있음)
- 안정성이 높아 오류를 방지하고 보안상 안전
- 대규모 앱 개발 가능
- 다양한 개발 도구와 라이브러리(도서관에 꽂혀있는 책같은 느낌으로 개발자들이 계속 만들어냄) 사용 가능
가상의 기기를 만들어주는 것
여러 기기 위에 Java 프로그램을 실행할 수 있는 가상의 기기를 만들어주는 것
Jvm이 없다면 기기별로 설정해주어야 할 수 있음
- 바이트 코드: 내가 작성한 코드에서 운영체제가 이해할 수 있는 코드로 변환
(Compiler: java파일을 class로 바꾸는 역할 수행)- 인터프리터: 운영체제가 읽은 바이트 코드를 기계가 실행 가능한 기계어로 번역
- JIT 컴파일러: 인터프리터의 효율을 높여주는 서포터 해석기
- 메모리 영역: 운영체제로부터 JVM이 할당받은 메모리 영역
- 클래스 로더: 바이트 코드를 메모리 영역에 담는 운반기
- 가비지 컬렉터: 메모리 영역에서 쓰지 않는 데이터를 주기적으로 흡수해가는 청소기
값을 다루기 위해서 값을 저장해둘 저장공간(그릇)의 선언 필요
선언 시 저장공간(그릇)에 담을 값의 타입과 이름을 명시하여 선언
- 값의 타입: 저장공간의 종류
- 값의 이름: 저장공간의 이름
저장공간에 값을 저장하는 2가지 방법
- 초기화: 선언과 동시에 값을 저장
int num = 4;
- 덮어쓰기: 선언 이후에 값을 저장
int num; num = 4;
- Java 프로그램에서 저장하는 대부분의 값은 변하는 것
- '수'로 끝나지만 하나의 값을 저장할 수 있는 저장공간을 의미 → 변하는 것 이라는 의미에 맞게 저장하고 있는 값이 달라질 수 있음
- 저장공간에 이름(변수명)을 붙여 필요한 값을 저장함
- 변수는 저장되는 값의 형태에 따라 여러 모습을 지님
- Java 프로그램에서는 변하지 않을 값을 변하지 않는 저장공간에 저장함
- '변하지 않을 저장공간'은 저장 효율을 위해 '변하지 않을 값'을 따로 저장하는 공간이 존재하기 때문
- 상수 또한 저장되는 값의 형태에 따라 여러 모습을 지님
final int num = 4; // 상수로 선언(데이터 타입 앞에 final 붙이기) num = 5; // 변수 값을 바꾸려고 할 경우 에러 발생
기본형 변수
- 논리형 변수: Boolean
boolean flag = true; // 논리형 변수 boolean으로 선언 및 true 값으로 초기화 flag = false; // false 값으로도 저장 가능
- 문자형 변수: char
char alphabet = 'A'; // 문자 하나 저장
- 정수형 변수: byte, short, int, long
- 0, 1, 22와 같은 정수형 숫자 저장
- 정수형 변수 표현 범위
- byte: -128 ~ 127 범위의 숫자만 저장 가능
- short (2byte): -32,768~32,767 범위의 숫자만 저장 가능
- int (4byte): -21억 ~ 21억 범위의 숫자만 저장 가능
- long (8byte): 9백경 정도의 매우 큰 수 저장 가능
byte byteNum = 127; short shortNum = 32767; int intNum = 2147483647; long longNum = 2147483647L; // int와 데이터값(리터럴)을 구분하기 위해 뒤에 L(접미사)을 붙임
- 실수형 변수: float, double
- 0.123, 0.9999와 같은 소수점 실수값 저장
- 실수는 표현범위가 매우 넓어 정수형 변수에서 담지 못할 수 있음
- float (4byte): 3.4 -10^38 ~ 3.4 10^38(long 보다 큼) 범위의 숫자 저장 가능
- double (8byte): 1.7 -10^308 ~ 1.7 10^308(long 보다 큼) 범위의 숫자 저장 가능
float floatNum = 0.123f; double doubleNum = 0.123123123;
- 실수형 리터럴 구분값 (리터럴 = 데이터값)
- float와 double의 데이터값(리터럴)을 구분하기 위한 구분자로 float으로 담을 숫자 뒤에 f(접미사)를 붙임
- float는 소수점 7자리까지 double은 소수점 16자리까지 저장(표현) 가능
참조형 변수 (어느 공간에 있는 주소값을 바라보고 있는 변수 / 길이 예측 불가)
- 문자열 변수: String
- "Apple", "사과" 와 같은 문장 저장
String message = "Hi";
- 그 외; Object, Array, List ...
- 객체, 배열, 리스트와 같은 단일 저장공간에 담을 수 없는 값 저장
List<int> alphabet = [0,1,2,3]; // 기본형 변수 여러 개 저장
래퍼 클래스 변수
- 기본형 변수를 클래스로 한 번 랩핑(감싸는) 변수
- 박싱: 기본 타입에서 래퍼 클래스 변수로 변수를 감싸는 것
- 언박싱: 래퍼 클래스 변수를 기본 타입 변수로 가져오는 것
- 저장공간에 저장하는 값은 0, 1을 통한 숫자값을 저장
- 문자를 숫자로 저장하는 방법은?
- 숫자를 문자로 짝 지어서(매핑해서) 표현
- Java에서는 기본적으로 아스키코드 라는 규칙으로 문자를 저장(표현)
// 숫자 → 문자 Scanner sc = new Scanner(System.in); int asciiNum = sc.nextInt(); char ch = (char)asciiNum; System.out.println(ch); // 입력: 97 | 출력: a
// 문자 → 숫자 Scanner sc = new Scanner(System.in); char letter = sc.nextLine().charAt(0); // 첫 번째 글자만 받아오기 int asciiNum = (int)letter; // 숫자로 형변환 하면 저장된 아스키 코드 숫자값으로 표현 System.out.println(asciiNum); // 입력: a | 출력: 97
- 선언 관점에서의 차이점
- 문자(char): 문자 한 개만 저장하며 따옴표를 사용해 값 저장 (ex. 'A')
char alphabet = 'A'; // 문자 하나 저장
- 문자열(String): 문자 여러개를 문장 형태로 저장하며 쌍따옴표를 사용해 범위 지정 (ex. "ABC")
String message = "Hi ~"; // 문자열 저장
- 저장 관점에서의 차이점
- 문자(char): 문자 뒤에 \0(널문자)가 없음
(1byte만 쓰기 때문에 끝을 알아 데이터만 저장하면 됨)- 문자열(String): 문자 뒤에 \0(널문자)가 함께 저장됨
(몇 개의 byte를 쓸지 모르기 때문에 끝 표시 필요)
참조형 변수 = 주소형 변수: 별도의 영역에 저장하고, 그 주소를 Get해서 주소값을 저장
- 저장 관점에서 차이점
- 기본형 변수: 원본값이 Stack 영역에 있음
- 참조형 변수: 원본값이 Heap 영역에 있음
- Stack 영역에는 따로 저장해둔 원본값의 Heap 영역주소를 저장
- Stack vs Heap
- Stack의 경우 정적으로 할당된 메모리 영역
- 항상 그 크기가 정해서 있는 기본형 변수 저장
- 크기가 정해져 있는 참조형 변수의 주소 값 저장
- Heap의 경우 동적으로 할당된 메모리 영역
- 정해진 크기를 알 수 없는, 크기에 맞게 계속해서 늘어나야 하는 참조형 변수의 원본 저장
- 입력: 기본적으로 Scanner.in 객체의 next() 명령 사용
Scanner sc = new Scanner(System.in); // Scanner 객체를 new 명령어로 생성 String input = sc.next(); // sc의 .next()를 실행하면 input 변수에 입력한 글자를 받음
- 출력: 기본적으로 System.out 객체의 println() 명령 사용
System.out.println("입력값 :" + input); // 입력한 글자 출력 // 결과 // {입력} // 입력값: 입력
변수는 그릇이라고 지칭한 byte(바이트)에 나누어서 저장함
그 byte(바이트)는 8개의 bit(비트)로 구성됨
- Bit
- Bit(비트)는 0과 1 형태의 2진수 데이터로써 컴퓨터가 저장할 수 있는 최소 단위
- 정수형 값: 10진수 숫자이며 2진수 Bit로 저장
- 4개의 Bit로 16진수 숫자를 2진수 Bit로 저장
- Byte = 8Bit
- Byte는 8개의 Bit로 구성
- 1 Byte 내에서 숫자 변수는 Bit 2진수를 10진수로 저장
- 10진수로는 0~255까지 정
- 1 Byte 내에서 문자 변수의 경우만 Bit 2진수를 16진수로 저장
- Double / Float to Int
// (int) 캐스팅 방식으로 실수를 정수로 치환 (실수형의 소수점 아래자리는 버려짐) double doubleNum = 10.101010; float floatNum = 10.1010f; int intNum; intNum = (int)doubleNum; // double → int intNum = (int)floatNum; // float → int
- Int to Double / Float
// (double) / (float) 캐스팅으로 정수형을 실수형으로 변환 int intNum = 10; double doubleNum = (double)intNum; // int → double float floatNum = (float)intNum; // int → float
Java 프로그래밍에서 형변환을 직접적으로 캐스팅 하지 않아도 자동으로 형변환되는 케이스
프로그램 실행 도중 값 저장 혹은 계산 시 자동으로 타입 변환
- 자동 타입변환은 작은 크기의 타입에서 큰 크기의 타입으로 저장될 때 큰 크기로 형변환 발생
// byte → int byte byteNum = 10; int intNum = byteNum; System.out.println(intNum); // 10 // char → int char charAlphabet = 'A'; intNum = (int)charAlphabet; System.out.println(intNum); // 65 // int → long intNum = 100; long longNum = intNum; System.out.println(longNum); // 100.0 // int → double intNum = 200; double doubleNum = intNum; System.out.println(doubleNum); // 200.0
- 작은 크기의 타입이 큰 크기의 타입과 계산될 때 자동으로 큰 크기의 타입으로 형변환 발생
int intNum = 10; double doubleNum = 5.5; double result = intNum + doubleNum; // 정수로 나누기 (소수점 버림) intNum = 10; int iResult = intNum / 4; // iResult: 2 // 실수로 나누기 (소수점 저장) intNum = 10; double dResult = intNum / 4.0; // dResult: 2.5
✍️ 자동 형변환 vs 강제 형변환
- 작은 타입 → 큰 타입
- 더 큰 표현범위를 가진 타입으로 변환: 값 손실 X
- 값 손실 없이 변환 가능하므로 컴파일러가 자동으로 형변환 해줌
- 큰 타입 → 작은 타입
- 더 작은 표현범위를 가진 타입으로 변환: 값 손실 O
- 값 손실이 생기므로 자동 형변환 없이 개발자가 선택해 형변환