자바의 프리미티브 타입, 변수 그리고 배열을 사용하는 방법을 익힙니다.
출저 : 내가 만든거
여기서 위의 부분은 보통의 외우고 있지는 않지만 다들 알고 있는 테이블일 것이다.
기본형의 경우는 우리가 앞에서 배웠던 JVM 의 해당 값을 default 값으로 저장할때 위의 표를 참조하면 되겠다.
(Linking 의 prepare 부분 참조!)
Primitive Type 에 대한 약간의 설명을 하자면 해당 수행은 long 과 double 을 빼고는 원자적 수행
을 보장한다. ⇒ 이 부분은 내가 volatile 을 정리했을때 설명했던 부분이다.
뭐 이부분은 long
과 double
혹은 dynamic-computed constant
의 경우 constant pool 에서 해당 index 를 참조하여 가져오는 과정이 포함되어 있어서 해당 과정에서 다른 Thread 가 끼어들 수 있기에 원자적 수행을 보장하지 못한다고 생각하는게 좋지 않을까 싶다.
OS 에 따라 자료형의 길이가 변하지 않는다.
비객체 타입으로 null
값을 가질 수 없다.
Primitive Type 은 Thread 의 Stack 내 Frame 에 바로 저장된다. 아래 링크 참조해도 좋음
java.lang.Object
를 상속 받고 있어야 한다.javap
를 통해서 분석해보면 저런 코드가 나온다.extends java.lang.Object
class GenericExample<T extends java.lang.Object> extends java.lang.Object
class Node {
int data;
public void setData(int value) {
this.data = value;
}
public int getData() {
return this.data;
}
}
Other class..
public static void main(String[] args) {
Node node = new Node();
node.setData(3);
node.getData() == 3 // true
}
저번 주차에서 했던 내용과 연관지어서 정리해보자면, Reference Type 의 값을 Stack Frame 내에 저장할 때는 refernce (즉, Head 영역의 일정 주소를 가르키도록 저장되는데) 이런 개념들을 떠올려 보았을때 new Node() 라는 부분이 node (reference) 에게 return Instance Address
를 하고 있다고 생각할 수 있다. 즉, 주소값을 주입시켜준다고 생각할 수 있다. 그래서 이제 해당 node
는 heap 상의 한 영역을 계속해서 바라보고 있는 상태가 되는 것이다. 아마 생성자가 저러한 역할을 하는것이 아닐까라는 추측을 해본다.
class GenericExample<T> {
T data;
public GenericExample(T data) {
this.data = data;
}
public static void main(String[] args) {
GenericExample<String> ge = new GenericExample<>("Cool");
}
}
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #7 // Field data:Ljava/lang/Object;
9: return
생성자가 위와 같이 되어있는데 간단하게 보면 일단 data
를 reference 로 stack Index #1 에 저장하고,
5 번줄에서 aload_1
을 통해 stack 내의 lva 에서 1번을 꺼내오고, putfield
를 해주는데
이때 putField
에서 매개변수로 넘어온 data object 의 ref 를 대입해준다. (틀린 부분이 있을수도..?)
this
라는 키워드를 이용할 수 있는데 이는 객체 자기 자신을 나타낸다.리터럴은 변하지 않는 값을 의미하는데 만약 우리가 int a = 10
을 한다면 여기서 10
이 리터럴이다.
그니까 변하지 않는 데이터들 예를 들면 Primitive Type
혹은 불변의 객체
들이 리터럴이 될 수 있겠다.
그럼 여기서 불변의 객체 ( Immutable Object ) 란 무엇인가?
우리 주위에서 가장 찾기 쉬운 예로는 String 이 있겠다.
String 의 경우 " " 를 이용하여 생성할 경우 해당 문자가 Heap 영역의 String Constant Pool
에 생성된다. 그래서 만약 아래와 같은 코드를 적는다고 했을때
String s = "Hello";
String b = "Hello";
처음에 String s = "Hello"
를 했을때 Hello 에 대한 String 객체를 생성하여 Heap 영역의 String Constant Pool
에 저장하고, b 에서 "Hello"
를 쓸때에는 String Constant Pool
에 있는 주소값을 가져와서 참조하는 것이다. (이 부분은 intern()
을 키워드로 검색해보면 좋다!)
자 그렇다면 우리가 한번 이런걸 생각해보자!
s == b
는 true 일까? 물론 true 가 나온다.타입 변수명 ;
으로 보통 선언한다.public void method() {
int a = 10;
}
method
가 종료되면, 해당 스택도 pop
됬으므로 a 의 라이프 타임또한 종료된다.Method Start ~ Method End
public class Do {
public static int dodo = 10;
}
Runtime Constant Pool
에 저장된다고 한다Linking 의 prepare ~ Class Unloading
까지 선언된다고 할 수 있겠다.할당된 순간 ~ 수집된 순간
public class Test {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(()->{
int i = 0;
while(!stopRequested){
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
위의 클래스는 종료되지 않고 영원히 도는데 그 이유는 backGroung Thread
와 Main Thread
모두 각 Stack Frame 내에서 stopRequested 라는 값을 가지고 있는데 그걸 Main Memory 에 있는 값을 가져오는 것 보다는 로직 중에는 캐싱 된 값을 이용한다. 그래서 위의 코드가 종료되지 않는 현상이 일어나는데.. 이때 volatile
을 이용하면 종료 할 수 있다. 위의 코드도 어떻게 보면 캐싱해서 사용하는 방법으로 인해 문제가 일어날 수 있기에 한번쯤 봐두면 좋을듯 하다..?
byte a = 10;
int b = a;
작은 크기 타입 = (작은 크기 타입) 큰 크기 타입
int a = 10000000;
byte b = (byte) a;
int[] a = new int[10];
int[][] b = new int[10][10];
new int[SIZE]
에 명시한 크기만큼 생성된다.right-hand side
의 값을 보고 왼쪽 값의 타입을 추론하는 것이라고 한다. 뭐 JavaScript 처럼 완전한 var 는 아닌것 같다. 왜냐하면 컴파일 단계에서 right-hand side
의 값을 기반으로 이루어지므로 initializer
가 반드시 있어야 한다.var idToNameMap = new HashMap<Integer, String>();