- 학습 목표 달성 확인 목록
- [] 생성자 문법의 용도를 설명할 수 있는가?
생성된 인스턴스가 제대로 쓰일 수 있도록 유효한 값으로 초기화시키는 일을 한다.
- [] 생성자를 이용하여 인스턴스 필드를 초기화시킬 수 있는가?
public class Constructor {
Constructor(String title) {
System.out.println(title);
}
public static void main(String[] args) {
Constructor c = new Constructor("hi! 자바");
}
}
//결과
hi! 자바
public class Constructor1 {
static class Con{
String title;
int a;
int b;
int c;
Con(String title, int a, int b, int c) {
System.out.println("생성자 호출!");
this.title = title;
this.a = a;
this.b = b;
this.c = c;
}
}
public static void main(String[] args) {
Con c = new Con("자바", 1, 2, 3);
System.out.printf("%s %d %d %d", c.title, c.a, c.b, c.c);
}
}
//결과
생성자 호출!
자바 1 2 3
- [] this() 의 용법을 아는가?
this는 주로 생성자와 메소드의 매개변수 이름이 필드와 동일한 경우 인스턴스 멤버인 필드임을 명시한다.
public class People{
//필드
int age;
//메소드
void setAge(int age){
this.age = age;
}
}
위와 같이 파라미터 이름과 필드의 이름이 같아도 this를 활용하면 같이 사용이 가능하다
코드를 해석하자면 this.age는 필드인 age를 의미한다.즉 this의 뒤의 변수명은 인수가 아닌 멤버변수(필드)를 의미하게 된다.
- [] 스태틱 변수 초기화 문장을 사용할 수 있는가?
public class StaticCon {
static class Sample {
static String name;
static int a;
static double b;
}
public static void main(String[] args) {
Sample.name = "자바";
Sample.a = 100;
Sample.b = 12.5;
System.out.printf("%s %d %.1f", Sample.name, Sample.a, Sample.b);
}
}
//결과
자바 100 12.5
스태틱 멤버는 인스턴스화를 하지 않고 호출할 수 있다.
- [] 스태틱 블록을 이용하여 스태틱 변수를 초기화시킬 수 있는가?
public class StaticCon1 {
static int a;
static int b;
static class Sample {
//아무런 코드가 없다
}
static {
System.out.println("Static{} 111");
}
static {
System.out.println("Static{} 222");
}
public static void main(String[] args) {
StaticCon1.a = 100;
System.out.println("종료!");
}
}
//결과
Static{} 111
Static{} 222
종료!
클래스가 로딩 될때 스태틱 초기화 블록은 실행된다.
클래스가 로딩되는 경우는 클래스 멤버(필드와 메서드)그러니까 스태틱 멤버들을 최초로 사용할 때!
그리고 해당 클래스의 인스턴스를 최소로 생성할 때
인스턴스를 만들려면 설계도가 있어야 하고,
설계도는 메모리에 로딩되어 있어야 한다.
따라서 설계도가 없으면 즉시 설계도를 로딩할 것이다.
그리고 JVM은 이미 로딩된 클래스가 있다면 중복해서 메모리에 로딩하지 않는다.
- [] 스태틱 블록이 여러 개일 경우 컴파일러가 어떻게 다루는지 아는가?
여러개의 스태틱 블록이 있을 때 컴파일러는 한 개의 블록으로 합친다.(위의 코드를 바이트코드를 인간이 볼수 있는 언어로 번역하여 봄)
static {};
0 getstatic java.lang.System.out : java.io.PrintStream [11]
3 ldc <String "Static{} 111"> [17]//--------여기랑!
5 invokevirtual java.io.PrintStream.println(java.lang.String) : void [19]
8 getstatic java.lang.System.out : java.io.PrintStream [11]
11 ldc <String "Static{} 222"> [25]//--------여기!
13 invokevirtual java.io.PrintStream.println(java.lang.String) : void [19]
16 return
- [] 스태틱 변수 초기화 문장이 컴파일되면 어떻게 바뀌는지 아는가?
public static class A {
static int a = 100;
}
public static void main(String[] args) throws Exception {
System.out.println(A.a);
}
}
//결과
100
스태틱 초기화 블록이 없으면 컴파일러가 자동으로 삽입한다.
스태틱 초기화 블록에 a에 100에 할당하는 문장을 삽입한다.
static int a = 100;
//위의 문장은 다음 문장으로 바뀐다
static int a;
static{
a = 100;
}
//위의 코드를 바이트코드로 볼때(사람이 볼수 있는)
static {};
0 bipush 100
2 putstatic com.eomcs.oop.ex03.Exam0670$A.a : int [10]
5 return
- [] 클래스 로딩할 때 어떻게 초기화 과정이 어떻게 진행되는지 이해하는가?
1.클래스를 Method Area에 로딩한다.
2.스태틱 변수를 만든다.
3.스태틱 블록을 실행한다.
- [] 인스턴스 블록을 이용하여 인스턴스 변수를 초기화시킬 수 있는가?
public class InstantCon {
static class A {
int a;
int b;
int c;
{
a = 100;//이 두 코드는 별도 메서드 없이 어느 메서드에든 삽입한다.
System.out.println("자바!");
}
A() {
// a = 100;
// System.out.println("자바!");
System.out.println("aaa");
}
A(int p1) {
// a = 100;
// System.out.println("자바!");
System.out.println("bbb");
}
}
public static void main(String[] args) {
A a = new A();
System.out.printf("a=%d, b=%d, c=%d", a.a, a.b, a.c);
}
}
스태틱 생성자든 인스턴스 생성자든 생성자를 따로 선언하지 않으면
컴파일러가 자동으로 디폴트로 생성자를 생성한다(보이지않음)
- [] 인스턴스 블록이 컴파일되면 어떻게 바뀌는지 아는가?
컴파일러는 필드초기화나 인스턴스 초기화 블록이 있으면
선언된 순서대로 모든 생성자의 첫 부분에 복사한다.
즉 위에 선언된 초기화 블록 안에 있는 코드가 그대로 다음과 같이 복사된다.
Java Tutorial 문서: Learning the Java Language > Classes and Objects
‘The Java compiler copies initializer blocks
into every constructor.
Therefore, this approach can be used
to share a block of code
between multiple constructors.’
- [] 인스턴스 변수 초기화 문장이 컴파일되면 어떻게 바뀌는지 아는가?
public class Exam {
static class A {
int a;
int b;
int c;
{
this.a = 101;
System.out.println("첫 번째 인스턴스 초기화 블록");
}
{
this.a = 102;
System.out.println("두 번째 인스턴스 초기화 블록");
}
{
this.a = 103;
System.out.println("세 번째 인스턴스 초기화 블록");
}
A() {
// 인스턴스 초기화 블록은 선언된 순서대로 삽입한다.
// 즉 다음과 같다.
// this.a = 101;
// System.out.println("첫 번째 인스턴스 초기화 블록");
// this.a = 102;
// System.out.println("두 번째 인스턴스 초기화 블록");
// this.a = 103;
// System.out.println("세 번째 인스턴스 초기화 블록");
System.out.println("A()");
b = 200;
c = 300;
}
}
public static void main(String[] args) {
A obj1 = new A();
System.out.printf("a=%d, b=%d, c=%d\n", obj1.a, obj1.b, obj1.c);
}
}
위의 코드를 바이트 코드로 번역된 것이다.
0 aload_0 [this]
1 invokespecial java.lang.Object() [12]
4 aload_0 [this]
5 bipush 101//----------->여기
7 putfield com.eomcs.oop.ex03.Exam0740$A.a : int [14]
10 getstatic java.lang.System.out : java.io.PrintStream [16]
13 ldc <String "첫 번째 인스턴스 초기화 블록"> [22]//----------->여기
15 invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]
18 aload_0 [this]
19 bipush 102//----------->여기
21 putfield com.eomcs.oop.ex03.Exam0740$A.a : int [14]
24 getstatic java.lang.System.out : java.io.PrintStream [16]
27 ldc <String "두 번째 인스턴스 초기화 블록"> [30]//----------->여기
29 invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]
32 aload_0 [this]
33 bipush 103//----------->여기
35 putfield com.eomcs.oop.ex03.Exam0740$A.a : int [14]
38 getstatic java.lang.System.out : java.io.PrintStream [16]
41 ldc <String "세 번째 인스턴스 초기화 블록"> [32]//----------->여기
43 invokevirtual java.io.PrintStream.println(java.lang.String) : void [24]
46 getstatic java.lang.System.out : java.io.PrintStream [16]
49 ldc <String "A()"> [34]
+참고
여러개의 인스턴스 초기화 블록이 있을 때,
선언된 순서대로 생성자의 앞 부분에 삽입된다
인스턴스 초기화 블록이 선언된 위치는 상관없다.
- [] 인스턴스 블록의 용도를 아는가?
1.여러 생성자에 공통으로 들어가는 초기화 문장을 작성할 때
2.생성자를 만들지 못하는 상황에서 복잡한 로직에 따라
인스턴스 필드를 초기화시켜야할때
생성자를 만들지 못하는 상황?
-
“익명 클래스”를 만들 때이다.
-
클래스 이름이 없기 때문에 생성자를 만들 수 없다.
다음은 Object 클래스를 상속 받은 익명 클래스를 정의하고 객체를 만드는 명령이다.
Object obj1 = new Object() {
{
System.out.println("인스턴스 블록...");
}
};
이 클래스는 이름이 없기 때문에 생성자를 만들 수 없다.
그래서 초기화 명령을 작성하려면 인스턴스 블록을 이용해야 한다.