생성자 : 인스턴스(객체)를 생성한 후에 사용하기 전에 유효한(적당한) 값으로 초기화시키는 작업을 수행한다.

클래스에 생성자가 하나도 없을 때만 컴파일러가 기본 생성자 자동 추가

com.eomcs.oop.ex03.Exam0440.java
생성자 - this()

생성자에서 다른 생성자 호출하기

다른 생성자를 호출할 때는 this()를 사용한다.
단, 생성자의 첫 문장으로 와야 한다.

일반 메서드에서 생성자를 호출할 수 없다!

com.eomcs.oop.ex03.Exam0450.java
생성자 - 생성자 호출 막기 (인스턴스 생성 막기)

생성자 앞에 private 붙인다

생성자를 호출할 수 없다.

결국 인스턴스를 생성하지 못하게 만든다.

이 클래스의 인스턴스를 생성하지 못하게 한다.

com.eomcs.oop.ex03.Exam0510 ~ 530
변수 자동 초기화

초기화 : 값을 한 번이라도 저장하는 것

클래스 변수(스태틱 변수)는 생성되는 순간 0으로 자동 초기화 된다.
인스턴스 변수도 클래스 변수와 마찬가지이다.

A 클래스가 로딩될 때 Method Area에 만들어진다.
🔹 클래스가 로딩되는 경우
1) 스태틱 필드나 스태틱 메서드를 사용할 때
2) 인스턴스를 생성할 때(new 명령을 실행할 때)

클래스 멤버(필드와 메서드)를 사용할 때, 클래스가 로딩된 상태가 아니라면 클래스를 로딩한다.

로컬 변수는 자동으로 초기화되지 않는다.
초기화시키지 않은 로컬 변수를 사용하려고 하면 컴파일 오류가 발생한다!
The local variable x may not have been initialized

410 ~ 530 복습

com.eomcs.oop.ex03.Exam0610.java
스태틱 초기화 블록(static initializer)

🔹 static 블록
스태틱 블록은 클래스 멤버(클래스 변수, 클래스 메서드)를 사용하기 전에 유효한 값으로 초기화시키는 것.

클래스가 로딩될 때 스태틱 초기화 블록은 실행된다.

각각의 클래스는 딱 한 번만 로딩된다.

여러 개의 스태틱 블록이 있을 때, 컴파일러는 한 개의 static 블록으로 합친다.

레퍼런스를 선언할 때는 클래스가 로딩되지 않는다.

com.eomcs.oop.ex03.Exam0650.java
스태틱 초기화 블록(static initializer) - Class.forName()

자바에서 제공하는 도구를 사용하여 클래스를 로딩

ArrayList : 객체 주소 등록, 수정, 삭제
ContactController : 연락처에 관련된 클라이언트 요청을 받아서 처리
String : 문자열을 다루는 변수나 메서드가 있다

클래스에는 역할이 있음

클래스 정보를 다루는 일을 합니다.

레퍼런스를 선언할 때는 클래스가 로딩되지 않는다.

만약 이전에 클래스가 로딩되었다면, 다시 로딩하지 않는다.

610 ~ 660 복습

모든 로컬 변수는 다 JVM Stack에 올라간다.

스태틱 변수에 변수 초기화 문장이 같이 있으면 스태틱 블록 안에 집어 넣는다.

com.eomcs.oop.ex03.Exam0670.java
변수 초기화 문장(variable initializer)

🔹 변수 초기화 문장(variable initializer)
변수를 만들자마자 어떤 값으로 초기화시켜야 하는지 명령하는 문장.
변수 선언문에 할당 연산자(=)를 붙여서 초기화할 값을 지정한다.

컴파일될 때 두 개의 문장으로 분리된다.
변수 선언과 값을 초기화 시키는 블록으로 분리된다.

com.eomcs.oop.ex03.Exam0690.java

간단한 초기화는 변수 초기화 문장(variable initializer)으로 한다.

변수 초기화 문장을 컴파일 할 때,
스태틱 초기화 블록이 없으면 컴파일러가 자동으로 삽입한다.

com.eomcs.oop.ex03.Exam0691.java
1. Method Area에 Exam0691 클래스 로딩
2. main() 호출
3. main() 로컬 변수 생성
4. System.out.println(A.a);
A 클래스가 로딩이 안 되어 있으므로 로딩한다.
5. 스태틱 변수 생성
a 변수 생성, int 타입이니까 0으로 초기화된다.
6. 스태틱 블록 실행
위에서 아래서 순서대로 실행
a = 7
System.out.println("A.static{}"); 실행
a += B.b;
B 클래스가 로딩이 안 되어 있다.
7. B 클래스를 로딩한다.
8. 스태틱 변수 생성
b 생성, int 타입이니까 0으로 초기화된다.
9. 스태틱 블록 실행
b = 22
System.out.println("B.static{}"); 실행
b += A.a;
A 클래스는 이미 로딩되어 있다. b = 22 + 7
b = 29
10. A 클래스로 돌아가서 마저 실행한다.
a += B.b;
a = 7 + 29
a = 36

클래스 로딩 시점, static 블록 실행 순서

com.eomcs.oop.ex03.Exam0710.java
인스턴스 초기화 블록(instance initializer)

여러 생성자에 공통으로 존재해야 하는 코드가 있다면 인스턴스 초기화 블록에 작성한다.

생성자가 없으면, 컴파일러는 기본 생성자를 만든 후 생성자 시작 부분에 인스턴스 초기화 블록에 들어 있는 코드를 삽입한다.

생성자가 있으면, 존재하는 생성자의 앞부분에 삽입된다.

여러 개의 생성자가 있으면, 존재하는 모든 생성자의 앞부분에 삽입된다.

여러 개의 인스턴스 초기화 블록이 있으면, 선언된 순서대로 생성자의 앞부분에 삽입된다.

생성자에 들어갈 코드를 작성하면 된다.
생성자 시작 부분에 들어간다.

인스턴스 초기화 블록이 생성자보다 뒤쪽에 위치해도 무조건 생성자 앞부분에 삽입된다.

생성자에 두나 인스턴스 블록 안에 두나 똑같다

클래스의 모든 생성자에 삽입된다

똑같은 코드를 모든 생성자에 집어넣으면 코드가 중복된다.

모든 생성자에 자동으로 삽입하는 문법
인스턴스 초기화 블록

여러 생성자에 공통으로 존재해야 하는 코드가 있다면
공통으로 들어가는 코드가 있다면 인스턴트 초기화 블록에 넣어라

710 ~ 750 복습

com.eomcs.oop.ex03.Exam0810.java
인스턴스 변수 초기화 문장(variable initializer)

인스턴스 변수 초기화 문장은 생성자의 앞부분에 삽입된다.

선언된 순서대로 모든 생성자의 앞부분에 삽입된다.

com.eomcs.oop.ex03.Exam0850.java
인스턴스 초기화 블록과 변수 초기화 문장, 생성자의 실행 순서

자바 컴파일러는
인스턴스 초기화 블록이나 인스턴스 변수 초기화 문장이 있다면,
종류에 구분 없이 선언된 순서 그대로 모든 생성자의 처음 부분에 복사한다.

둘 중 하나만 사용하기...

문법을 헷갈리지 않도록 하기 위해서 가능한 다음 순서로 코드를 작성하라.
1) 필드 선언 및 초기화 문장
2) 스태틱 블록 (가능한 한 1개의 블록으로 묶어라.)
3) 인스턴스 블록 (가능한 한 1개의 블록으로 묶어라.)
4) 생성자 (기본 생성자를 먼저 두고 파라미터 개수에 따라 나열하라.)

810 ~ 860 정리

com.eomcs.oop.ex03.Exam0910.java

실무에서는 인스턴스 블록을 잘 사용하지 않는다. 대신에 생성자를 주로 사용한다.

값을 설정하는 것이 복잡할 경우 초기화 문장이 아닌 인스턴스 초기화 블록에서 수행한다.

생성자에서 다른 생성자 호출하기 : this()

생성자 첫 문장에 this()가 있는 경우, 변수 초기화 문장이 삽입되지 않는다.

oop.ex04

com.eomcs.oop.ex04.Exam0111.java

Ctrl 누른 상태에서 String 클릭

전에는 char 배열이었음

jdk9부터 문자열이 byte 배열로 바뀜

직관적으로 char 배열이라고 생각

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html

생성자 많음

String(String original)

new char[0]
0개의 항목을 가지고 있는 캐릭터 배열을 만든다

[72, 101, 108, 108, 111]

Unicode (JVM이 사용하는 charset, UTF-16)

H → 72 (0x48)
e → 101 (0x65)
l → 108 (0x6C)
l → 108 (0x6C)
o → 111 (0x6F)

넘겨준 문자 개수만큼
배열의 주소가 value에 들어간다.
s1에는 String 객체 주소가 들어간다.

Java8까지는 char[]에 문자코드(Unicode, UTF-16)를 저장했다.

String s1 = new String("HelloABCabc012가각간");

리틀 엔디언(Little-endian)

바이트 배열을 사용할지라도 원리는 똑같다

유니코드 16으로 저장한다.

Java9부터는 byte[] 배열에 문자코드(Unicode, UTF-16)를 저장한다.

String(char[] value)

s2 = new String(chars, 1, 3);

String(byte[] bytes)

인스턴스를 생성할 때 생성자 골라서 사용하면 됨

System.out.println(Charset.defaultCharset()); // UTF-8

JVM과 default characterset

Windows 운영체제
JVM
외부와 데이터를 주고 받을 때 기본적으로 MS949
JVM은 UTF-16
그래서 항상 변환을 한다

Unix/Linux
UTF-8이라고 가정한다

Eclipse에서 실행할 때는 무조건 UTF-8로 내보낸다.
UTF-8이라고 가정한다.

JVM은 UTF-16
default characterset(문자변환규칙) →
JVM이 외부에 문자코드를 내보낼 때 사용하는 characterset
JVM이 외부에서 문자를 가져올 때 가정하는 characterset

잘못된 변환.. 결국엔 한글이 깨지는 상황이 발생

String 클래스와 생성자

com.eomcs.oop.ex04.Exam0112.java

EUC-KR인데 UTF-8이라고 가정해서 잘못 변환

실행조건 : 이클립스에서 실행
JVM이 외부 문자코드를 읽을 때 UTF-8이라 가정한다.

    byte[] arr = s1.getBytes();
    for (byte b : arr) {
      System.out.println(Integer.toHexString(b & 0xff));
    }

String 클래스는 바이트 배열에 들어 있는 문자코드가 UTF-8이라고 착각한다. → 잘못된 Unicode로 변환 → 한글이 깨진다.

한글이 왜 깨졌는지 모름

byte[] 배열에 들어 있는 값이 어떤 문자 집합의 규칙을 따르는지 정확하게 지정한다면 UTF-16으로 정상적으로 변환할 것이다.

EUC-KR B0A1 B0A2 B6CA BCCB
UTF-16 AC00 AC01 B618 B625

Java 한글 처리 주의!

byte[] String 객체 UTF-16

byte[] 배열에 들어 있는 문자 코드가 어떤 charset 규칙을 따르는지 정확하게 알려줘야 한다. 그래야 변환이 올바르게 이루어진다.

내보낼 때
String 객체에 저장된 문자열을 JVM 외부로 내보낼 때 어떤 charset으로 변환할지 정확하게 지정해야 한다.
보통 웹브라우저는 UTF-8을 요구한다.

C:\Users\JYH\git\bitcamp-study\java-lang\app>
java -cp bin/main com.eomcs.oop.ex04.Exam0113
ABCabc012 !#%+媛?媛곷삓?삦

C:\Users\JYH\git\bitcamp-study\java-lang\app>
java -Dfile.encoding=UTF-8 -cp bin/main com.eomcs.oop.ex04.Exam0113
ABCabc012 !#%+가각똘똥

어떤 charset으로 인코딩 되었는지

브라우저가 잘못 이해한 건지
서버가 잘못 이해한 건지

내일 ex04 나머지
내일 프로젝트 생성자 적용할 거
종료하고 사라지는 거
파일 입출력 클래스 도구를 사용해서 연락처 정보를 저장할 때마다 파일에 쓰는 거 할 거
파일에 저장된 데이터를 읽어오기 때문에 예전처럼 초기화되지 않게

0개의 댓글