기본형과 참조형에 대해 간략히 정리해 본 글. 겹치는 내용이 많을것이다
= 단 하나
의 값만을 저장할 수 있는 메모리 상의 공간
int a = 5;
int b = 5;
System.out.println(a == b);
(X) System.out.println(a.equals(b));
위의 출력이 true로 나올 수 있는 이유는 a와 b가 가리키고 있는 주솟값이 같기 때문에! (같은 값 5를 저장하는 메모리 상의 공간을 가리키고 있기 때문에)
** equals는 객체끼리 두 값이 리터럴 하게 같은지 확인해주는 함수이기 때문에 기본형에선 쓸 수 없음!
보통은
int a = 10;
int b;
b = 5;
이렇게 두가지의 경우로 변수의 선언과 함께 초기화 한다.
** 지역변수는 무조건 초기화를 해야 하지만, 클래스변수
와 인스턴스변수
는 초기화를 생략할 수 있다.
(왜냐면 각 타입의 기본값으로 초기화 할 수 있기 때문
ex. int[] arr = new int[10] => 값이 0으로 초기화됨)
기본적인 설명은 위의 포스팅을 참조하면 된다.
변수의 타입을 알아야 하는 이유: 타입에 따른 값의 종류와 범위
가 달라지는데, 이를 변수 선언시 저장할 값을 고려해서 넣어줘야 효율적이기 때문!
참조변수
Student s1 = null;
Student s2 = new Student();
//아래의 경우처럼 참조변수는 null or 주소값을 갖는다.
//여기서 객체를 생성하는 연산자 new가 사용됨으로써 새로운 객체의 주소를 생성한다.
//대입연산자 '='에 의해서 s2에 주소값이 저장됨
=> 참조형 변수는 기본형 변수들과 다르게 어떤 객체의 주소값을 저장할 것인가에 따라 구분되기 때문에, 자료형 대신 타입
이라는 용어를 사용한다!
(자료형 ( 타입 -> 따라서 굳이 구분할 필요는 없긴 함,,)
위에서 정리한 것 처럼 총 8개의 자료형이 있다.
위의 그림은 기본형의 크기인데 이 크기에 따라 저장 가능한 값의 범위가 달라진다. 이때 정수형 4가지는 음의 값도 갖는다.
(ex. char -> 2byte -> 16bit -> 0~2^16-1까지)
char은 문자를 내부적으로 정수 코드로 저장한다.
char first = 'A';
char first2 = '\u0041';
//이렇게 두개가 같은 말, 아래는 A를 16진수로 바꿨을 때 41
int code = 65;
char c = (char) code;
System.out.println(c) // casting(형변환)되어 A가 출력됨!
(유니코드(국제적인 코드 규약)를 사용하므로 2byte)
**여기서 유니코드는 한글, 한자, 일어등의 문자가 1byte로 표현이 불가하기 때문에 탄생하여 2byte로 문자를 표현함
이때 char형 변수는 한 문자밖에 저장이 안되기 때문에 String클래스
를 사용해서 여러 문자를 저장한다.
기본형, 참조형 구분 없이 문자열과 덧셈연산을 수행하면 그 결과는 문자열!
//example
String a = 7+7+""; //출력 14
String b = 7+""; //출력 7
*** 피연산자: 연산의 대상이 되는 값
**** JVM의 스택 영역(push, pop만 이뤄짐)에서 스택은 하나의 메서드가 실행될 때마다 스택 프레임
이 생성되는데, 스택 프레임은 지역 변수 배열, 피연산자 스택, 실행 중인 메서드가 속한 클래스의 런타임 상수 풀
에 대한 참조를 갖는다.
풀(pool)
= 필요할 때마다 객체를 생성하고 파괴하는 대신, 사용 준비된 상태로 초기화된 개체 집합
런타임 상수 풀 = constant pool 테이블에 있는 class나 interface별 런타임 표현 (JVM의 static 영역에서 생성)
아래는 런타임 상수 풀이 갖는 상수
*** 여기서 피연산자 스택
은 메서드의 실제 작업 공간
으로 컴파일 시에 그 크기가 결정된다 (어떤 변수가 들어올지 모르니까).
l
을 붙여줘야 한다** 리터럴 = 그 자체로 데이터 (ex. "A", 'a', 1)
(상수와 비슷한 의미로 받아들여질 수 있지만, 상수는 한번 저장되면 변경할 수 없는 저장공간
이기 때문에 다르다!!)
//차례대로 부호+지수+가수
float = 1+8+23 = 32bit = 4byte
double = 1+11+52 = 64bit = 8byte
float num = 0.1f
호구마가 정리해본 캐스팅
(다만 이 포스팅은 중점적으로 클래스 사이(상속 관계)에서의 캐스팅을 많이 다루고 있음)
보통은 같은 타입의 피연산자끼리 연산이 이뤄지나, 부득이 하게 다른 타입의 피연산자가 연산을 해야할 때 형변환이 일어나야 하기 때문에 사용한다.
** 그러나 기본형은 기본형끼리, 참조형은 참조형끼리만 형변환이 가능하다. (현재는 오토박싱 기능이 생겨 Object나 Wrapper 클래스를 활용해 기본형이 참조형으로 형변환이 가능해짐)
ex. Wrapper 클래스
Integer b = 1; int a = b.intValue()
ex. 형변환 예시
int score = (int) 95.4 // 95점
작은 범위 타입 -> 큰 범위 타입으로의 형변환
은 생략할 수 있다.int a = 1;
long b = a;
int c = 1;
byte d = (byte) c; //요런식으로 캐스트 연산자를 꼭 써주어야 함
int i = 100;
long l = 100L;
final float PI = 3.14f;
System.out.println('A'+'B') // 65+66
System.out.println('1'+2) // 49+2
System.out.println('1'+'2') //49+50
System.out.println(true+null) //오류(boolean형은 연산 불가)
위에서 설명한 것처럼 키워드는 의미가 약속되어 있어야 하므로
if
제외한 True
, Null
, Class
, System
모두 아님
** True가 아니라 true
였다면 키워드
a. $ystem
기호 $, _는 특이하게 허용됨
b. $MAX_NUM
a. byte b = 256
byte의 범위는 -127~128임..
b. char c = ''
char은 무조건 글자가 있는 상태로 초기화 돼야 함
c. public static void main(String[] arv)
e. static public void main(String[] args)
=> 인자 메서드의 이름은 아무거나 써도 되며,
static과 public은 순서를 바꿔두 됨!
** 메서드 이름이 main인 이유도 JVM(안에 명시된 메서드 이름이 main임), void인 이유도 JVM(아무것도 리턴하지 않기 위함)
f. String - ""
String도 참조형이기 때문에 기본값은 null
임
자바의 정석, 2nd Edition
https://velog.io/@kwak0568/JVM%EC%9D%98-%EC%9D%B4%ED%95%B4
https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.5