Java의 정석 - Chapter6 객체지향 프로그래밍

hoegon kim·2023년 8월 29일
0

JAVA

목록 보기
24/26
post-thumbnail

1.객체지향 언어


1.1 객체지향언어의 역사

  • 실제 세계는 사물(객체)로 이루어져 있으며, 발생하는 모든 사건들은 사물간의 상호작용이다.

  • 객체지향 이론 (캡상추다)

    • 캡슐화
    • 상속
    • 추상화
    • 다향성

1.2 객체지향언어

  • 관점 3가지

    • 재사용성
    • 유지보수
    • 중복된 코드의 제거
  • 코드 작성시 유의사항

    • 프로그래밍 : 설계 + 코드작성

    • 객체지향 개념에 얽매여서 프로그램을 작성하기보다 프로그램을 기능적으로 완성한 다음 어떻게 하면 보다 객체지향적으로 코드를 개선할 수 있을지를 고민하여 점차 개선해 나가는 것이 좋다.


2. 클래스와 객체


2.1 클래스와 객체의 정의와 용도

  • 클래스 정의 : 클래스란 객체를 정의해 놓은것
  • 클래스 용도 : 클래스는 객체를 생성하는데 사용된다.
  • 객체의 정의 : 실제로 존재하는 것, 사물 또는 개념
  • 객체의 용도 : 객체가 가지고 있는 기능과 속성에 따라 다름
  • 객체의 범주 : 유형(책상,의자,TV) 무형(수학공식, 프로그램에러)

프로그래밍에서의 객체는 클래스에 정의된 내용대로 메모리에 생성된 것을 뜻함


2.2 객체와 인스턴스

  • 클래스로부터 객체를 만드는 과정 : 클래스의 인스턴스 화

    • CODE :
  • 어떤 클래스로 부터 만들어진 객체 : 그 클래스의 인스턴스

    • CODE :

2.3 객체의 구성요소 - 속성과 기능

  • 객체 : 속성(변수) + 기능(메소드)
    • 속성 : 크기 , 길이, 높이, 색상, 볼륨, 채널 등
    • 기능 : 켜기, 끄기, 볼륨높이기, 볼륨낮추기, 채널 변경하기 등

< Class 의 구성 >

Class Tv {
	String color;          // 속성
	Boolean power;     	   // 인스턴스 멤버 변수
	Int channel;
 
	void power();         // 기능
	void channelUp();   // 인스턴스 멤버 함수
	void channelDown();

int method(int a, int b) { // a, b 는 메소드의 매개변수(parameter)
	Result = a + b        
	return  Result;
	}
 
Public static void main(String[] args) {
	method(3,7);          // 3, 7 args(아규먼트) 라고한다. 
	}
 
} 

※ 참고

  • 클래스내부 선언 규칙
    • 멤버변수와 멤버함수를 선언하는데 있어서 순서는 관계없지만,
    • 멤버변수를 먼저 선언 → 멤버함수를 선언
    • 멤버변수끼리 모아두기 → 멤버함수끼리 모아두기

2.4 인스턴스의 생성과 사용

  • 인스턴스(인스턴스 멤버변수, 인스턴스 멤버함수)는 참조변수를 통해서만 다룰 수 있다.

    • 참조변수의 타입은 인스턴스 타입과 일치해야한다.

      • CODE (참조변수타입 VS 인스턴스타입 구별)
  • 참조변수에는 하나의 값(주소)만이 저장 될 수 있고, 둘 이상의 참조변수가 하나의 인스턴스를 가리키는(참조하는) 것은 가능하지만 하나의 참조변수로 여러 개의 인스턴스를 가리키는 것은 가능하지 않다.

    • (1) 하나의 인스턴스르 여러 개의 참조변수가 가리키는 경우(가능)

    • (2) 여러 인스턴스를 하나의 참조변수가 가리키는 경우(불가능)

      • 그림적으로 표현

2.5 객체 배열

  • 목적 : 많은 수의 객체를 다뤄야 할때, 배열로 다루면 편리

  • 객체 배열 안에 객체가 저장되는 것은 아니고, 객체의 주소가 저장된다.

    • 메모리적 구조 (그림 표현)
  • 객체 배열 생성 방법

    • 방법 ①

      Tv[] tvArr = new Tv[3];   // 참조변수 배열(객체 배열)을 생성
      
      // 객체를 생성해서 배열의 각 요소에 저장
      tvArr[0] = new Tv();
      tvArr[1] = new Tv();
      tvArr[2] = new Tv(); 
    • 방법 ②

      Tv[] tvArr = {
        	new Tv(),
        	new Tv(),
        	new Tv(),
      	};
      	```
        
    • 방법 ③ (객체 수가 많을 때)

      Tv[] tvArr = new Tv[100];
      for(int i=0; i<tvArr.length; i++){
      	tvArr[i] = new Tv();
      }
    • 방법 ④ (서로 다른 객체를 배열에 넣고 싶을 때)

      Class Tv {
        	String color;
        	boolean power;
        	int channel;
        	void power(){
            	power = !power;
        		};
        	
            void channelUp(){
            	++channel;
        		};
        
        	void channelDown(){
            	--channel;
        		};
      	}
      
      	Class TvTest4{
              public static void main(String args[]){
                  Tv [] tvArr = new Tv[3];
                  for(int i=0; i< tvArr.length; i++){
                      tvArr[i] = new Tv();
                      tvArr[i].channel = i + 10;
                  }
      
                  for(int i=0; i< tvArr.length; i++){
                      tvArr[i].channelUp();
                      System.out.println("tvArr[%d].channel=%d%n", i, tvArr[i].channel);
                  }
              }
      	}
  • 객체 배열 생성시 주의할점

    • 모든 배열이 그렇듯이 배열도 같은 타입의 객체만 저장 할 수 있다.
    • 여러 종류의 객체를 하나의 배열에 저장할 수 있는 방법은 ?
      • 다향성

2.6 클래스의 또 다른 정의

  • 관점 2가지

    • 객체 지향 이론 : 클래스는 객체를 생성하기 위한틀, 클래스는 속성과 기능으로 정의 되어 있다. 객체로 정의되어 있다. 설명되어 있다.

    • 프로그래밍 관점 : 관점 2가지 데이터와 함수의 결합, 사용자 정의 타입

  • 클래스 - ① 데이터와 함수의 결합

    • 변수 : 하나의 데이터를 저장할 수 있는 공간

    • 배열 : 같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간

    • 구조체 : 서로 관련된 여러 데이터를 종류에 관계 없이 하나의 집합으로 저장 할 수 있는 공간

    • 클래스 : 데이터와 함수의 결합 (구조체 + 함수)

    • 프로그래밍 언어에서 데이터를 처리를 하기윈한 데이터 저장형태의 발전과정

  • 클래스 - ② 사용자 정의 타입

    • 사용자 정의 타입 정의 : 프로그래밍 언어에서 제공하는 자료형 외의 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입(참조형타입)으로 새로 추가하는 것을 사용자 정의 타입이라고 한다.
Class Time {
	int hour;
    int minute;
    float second;
    
    int[] hour = new int[3];
    int[] minute = new int[3];
    float[] second = new float[3];
}


// 위 식을 아래 식으로 변경 

Class Time {
	int hour;
    int minute;
    float second;
}


Time t1 = new Time();
Time t2 = new Time();
Time t3 = new Time();

Time[] t = new Time[3];
t[0] = new Time();
t[1] = new Time();
t[2] = new Time();

3.변수와 메서드


3.1 선언위치에 따른 변수의 종류

변수의 종류, 선언 위치, 생성 시기


3.2 클래스변수와 인스턴스 변수

// 3.1, 3.2 변수에 대한 정리 한번에


3.3 메서드

① 문장들을 묶어 놓은 것
② 값(입력)을 받아서 처리하고, 결과를 반환(출력)

※ 참고 : 함수 vs 메소드

  • 함수 : 클래스 안에 반드시 존재할 필요가 없다. (독립적이다.)
  • 메서드 : 클래스 안에 반드시 존재해야 한다. (종속적이다.)
  • 메서드의 장점
    • 코드의 중복을 줄일 수 있다.
    • 코드의 관리가 쉽다.
    • 코드를 재사용할 수 있다.
    • 코드가 간결해서 이해하기 쉬워진다.
  • 메서드의 작성
    • 반복적으로 수행되는 여러문장을 메서드로 작성
    • 하나의 메서드를 한 가지 기능만 수행하도록 작성

3.4 메서드의 선언과 구현

  • 메서드 = 선언부 + 구현부
int add (int a, int b) {          // 선언부 
	int result = a + b;          //  구현부
	return result; 
}

3.5 메서드의 호출

  • 메서드이름(값1, 값2, …);

    • Function();
  • 메서드의 실행 흐름

① MyMath mm = new MyMath();     	// 먼저 인스턴스를 생성 

② long value = mm.add(1L, 2L);		// 메서드를 호출한다. 

③ long add(long a, long b) {
	long result = a + b;
    return result;
}

① main 메서드에서 add를 호출한다. 인수 1L과 2L이 메서드 add의 매개변수 a,b에 각각 복사(대입)된다.

② 메서드 add의 괄호{}안에 있는 문장들이 순서대로 수행된다.

③ 메서드 add의 모든 문장이 실행되거나 return문을 만나면, 호출한 메서드(main메서드)로 되돌아와서 이후의 문장들을 실행한다.


3.6 return문

① 실행중인 메서드를 종료하고 호출한 곳으로 되돌아간다.
② 반환값

※ return 문 주의할점
① 반환 타입이 void가 아닌 경우, 반드시 return문 필요
② 생성자는 return 문을 필요로 하지 않는다.


3.7 JVM의 메모리구조

  • 메서드영역

    • 프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스 파일(*.class)을 읽어서 분석하여 클래스에 대한 정보(클래스 데이터)를 이곳에 저장한다. 이 떄, 그 클래스의 클래스 변수도 이 영역에 함께 생성된다.
  • 힙영역

    • 인스턴스가 생성되는 공간. 프로르냄 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다. 즉, 인스턴스 변수들이 생성되는 공간이다.
  • 호출 스택

    • 호출 스택은 메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면, 호출스택에 호출된 메서드를 위한 메모리가 할당되며, 이메모리는 메서드가 작업을 수행하는 동안 지역변수(매개변수 포함)들과 연산의 중간결과 등을 저장하는데 사용된다. 그리고 메서드가 작업을 마치면 할당되었던 메모리공간은 반환되어 비워진다.

메모리 구조에 대한 이해 자세히


3.8 기본형 매개변수와 참조형 매개변수

기본형 매개변수 : 변수의 값을 읽기만 할 수 있다.
참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다.

코드에 따른 메모리구조 자세히

Call by value vs Call by reference


3.9 참조형 반환타입

매개변수 뿐만 아니라 반환타입도 참조형이 될 수 있다.
반환 타입이 참조형이라는 것은 반환하는 값의 타입이 참조형이라는 얘긴데, 모든 참조형 타입의 값은 '객체의 주소'이므로 그저 정수값이 반환되는 것일 뿐 특별할 것이 없다.


3.10 재귀호출(recursive call)

재귀호출 : 메서드의 내부에서 메서드 자신을 다시 호출하는 것

void method() {
	method();			// 재귀호출
}

다음과 같이 작성하면 무한히 자기 자신을 호출하기 때문에 무한 반복에 빠진다.

무한 반복문이 조건문과 함께 사용되어야 하는 것 처럼, 재귀호출도 조건문이 필수적으로 따라다닌다.

void method(int n){
	if(n==0)
    	return;  // n의 값이 0 일떄, 메서드를 종료한다.
	System.out.println(n);
    
    method(--n);
}

3.11 클래스 메서드(static 메서드)와 인스턴스 메서드

인스턴스 메서드 : 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드이다 .

인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는)메서드를 클래스 메서드(static 메서드)로 정의한다.

① 클래스를 설계할 때, 멤버 변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.

  • 생성된 각 인스턴스는 서로 독립적이기 때문에 각 인스턴스의 변수(iv)는 서로 다른 값을 유지한다. 그러나 모든 인스턴스에서 같은 값이 유지되어야 하는 변수 static을 붙여서 클래스변수로 정의한다.

② 클래스 변수(static변수)는 인스턴스를 생성하지 않아도 사용할 수 있다.

  • static이 붙은 변수 (클래스변수)는 클래스가 메모리에 올라 갈때 이미 자동적으로 생성되기 때문이다.

③ 클래스 메서드(static메서드)는 인스턴스 변수를 사용할 수 없다.

  • 인스턴스변수는 인스턴스가 반드시 존재해야만 사용할 수 있는데, 클래스 메서드(static 이 붙은 메서드)는 인스턴스 생성 없이 호출 가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수도 있다. 그래서 클래스 메서드에서 인스턴스변수의 사용을 금지한다. 반면에, 인스턴스변수나 인스턴스메서드에서는 static이 붙은 멤버들을 사용하는 것이 언제나 가능하다. 인스턴스 변수가 존재한다는 것은 static변수가 이미 메모리에 존재한다는 것을 의미하기 때문이다.

④ 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.

  • 메서드의 작업내용 중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다. 반대로 인스턴스변수를 필요로 하지 않는다면 static을 붙이자. 메서드 호출시간이 짧아지므로 성능이 향상된다. static을 안 붙인 메서드(인스턴스메서드)는 실행 시 호출되어야할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸린다.

클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야 하는 것이 있는 살펴보고 있으면, static을 붙여준다.

작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려한다.


3.12 클래스 멤버와 인스턴스 멤버간의 참조와 호출

클래스멤버가 인스턴스 멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야한다.

why? 클래스멤버는 객체생성없이 호출이 가능하다. 하지만 인스턴스 멤버는 객체를 생성해야 호출이 가능하기 때문에 호출하고자 하는 경우에는 인스턴스를 생성해야한다.

이와관련된 관계 코드 실습

Q&A 정리

Q1. static 메서드는 static 메서드 호출가능?

Q2. static 메서드는 인스턴스 변수 사용가능?
아니오

Q3. static 메서드는 인스턴스 메서드 호출 가능?
아니오

Q4. 왜? static 메서드는 인스턴스 멤버를 쓸 수 없나요?
static 메서드 호출 시 객체 iv 묶음 가 없을 수도 있어서


4. 오버로딩(overloading)


4.1 오버로딩이란?

한 클래스 안에 같은 이름의 메서드 여러개 정의 하는 것

void println()
void println(boolean x)
void println(char x)
void println(double x)
void println(char[] x)
void println(String x)
void println(Object x)

4.2 오버로딩의 조건

① 메서드 이름이 같아야 한다.
② 매개변수의 개수 또는 타입이 달라야 한다.
③ 반환 타입은 영향 없다.

<보기1>
조건1 : method 이름 동일
조건2 : 매개변수갯수 동일, 타입 동일
조건3 : 반환 타입은 영향을 미치지 않는다

그러므로 중복정의

<보기2>
조건1 : method 이름 동일
조건2 : 매개변수갯수 동일, 타입 동일
조건3 : 반환 타입은 영향을 미치지 않는다

그러므로 중복정의

<보기3>
조건1 : method 이름 동일
조건2 : 매개변수갯수 동일, 타입 다름
조건3 : 반환 타입은 영향을 미치지 않는다

여기서 add(3,3); 하면 컴퓨터가 보기3번을 인식하지 못한다. 컴파일러가 어느것을 사용할 것인지 에러가난다. (ambiguous error 모호하다.)


4.3 오버로딩의 예


4.4 오버로딩의 장점

같은 이름의 메서드들을 오버로딩하면 해당 기능은 같은 기능을 하겠구나 라고 생각을 하게된다.

또한 메서드의 이름을 절약 할 수 있다는 것이다.

오버라이딩 : 조상 클래스로 부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩 (덮어쓰다, 재정의한다.)

오버로딩 : 메서드의 기능이 동일한 것


4.5 가변인자(varargs)와 오버로딩

????????


5.생성자(constructor)


5.1 생성자란?

생성자는 인스턴스가 생성될 때 호출되는 인스턴스 초기화 메서드이다.

< 조건 >

  1. 생성자의 이름은 클래스의 이름과 같아야 한다.
  2. 생성자는 리턴 값이 없다.
  3. 모든 클래스는 반드시 생성자를 가져야 한다.

※ 생성자도 메서드이기 때문에 리턴 값이 없다는 의미의 void를 붙여야 하지만, 모든 생성자가 리턴값이 없으므로 void를 생략 할 수 있게 한 것이다.

class Card {
	Card() {
    			// 기본 생성자
    }
    
    Card(String k, int num) {
    			// 매개변수가 있는 생성자.
                // 생성자 오버로딩 
    }

}

강조

연산자 new가 인스턴스를 생성하는 것이지 생성자가 인스턴스를 생성하는 것이 아니다.

생성자는 단순히 인스턴스를 변수들의 초기화에 사용되는 조금 특별한 메서드 일뿐이다.

생성자는 인스턴스 객체를 생성할때마다 생성된다.


5.2 기본 생성자(default constructor)

모든 클래스에는 반드시 하나 이상의 생성자가 정의 되어 있어야 한다.


5.3 매개변수가 있는 생성자

class Car {
	String color;
    String gearType;
    int door;
    
    Car() { }
    Car(String c, Sting g, int d) {
   		color = c;
        gearType = g;
        door = d;   
    }

}

위의 코드처럼 class를 내부에 생성자를 생성해두면 다음과 같이 인스턴스의 초기화를 진행할 경우 편리하게 코드를 관리할 수 있다.

Car c = new Car("white", "auto", 4); 초기화 생성자


5.4 생성자에서 다른 생성자 호출하기 - this(), this

  • 생성자의 이름으로 클래스 이름 대신 this()를 사용한다.
  • 한 생성자에서 다른 생성자를 호출 할때는 반드시 첫 줄에서만 호출이 가능하다.

예를들어

Car(String color) {           // 새로운 생성자의 정의
	door = 5;
    Car(color, "auto", 4);    // 위에 예제의 생성자 호출
    						  // 두 번째 줄이므로 에러 발생
                              // 또한, this(color, "auto", 4);로 해야함 
}

해당 코드의 이해를 반드시 해야함.

또한 this() 와 this.인스턴스멤버변수의 차이를 식별해야함

< 정리 >

this 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다. 모든 인스턴스메서드에 지역변수로 숨겨진 채로 존재한다.

this(), this(매개변수) 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.

※ 참고

this와 this()는 비슷하게 생겼을 뿐 완전히 다른 것이다. this는 '참조변수' 이고, this()는 '생성자'이다.


5.5 생성자를 이용한 인스턴스의 복사

현재 사용하고 있는 인스턴스와 같은 상태를 갖는 인스턴스를 하나 더 만들고자 할 때 생성자를 이용할 수 있다.

포인트

하나의 클래스로부터 생성된 모든 인스턴스의 메서드와 클래스변수는 서로 동일하기 떄문에 인스턴스간의 차이는, 인스터스마다 각기 다른 값을 가질 수 있는 인스턴스 변수일 뿐이다.

여기서의 포인트는 실행결과의 4번째줄과 5번째줄이다.

c1.door의 인스턴스 멤버변수의 리터럴 값을 변경했음에도 c2.door의 값이 변하지 않았다는 의미

의미는 c1.door c2.door의 각각 따로 주소값이 저장되어있는 메모리에 값이 인풋 되어진 것이기 때문에 에초에 객체를 새로 생성했다는 의미로 받아들여야 된다. 자바의 에서의 포인트는 객체를 생성할 뿐이지 객체를 복사했다고해서 그 값을 서로 공유한다는 것은 아니다.

인스턴스를 생성할 때는 다음의 2가지 사항을 결정해야한다.
1. 클래스 - 어떤 클래스의 인스턴스를 생성할 것인가?
2. 생성자 - 선택한 클래스의 어떤 생성자로 인스턴스를 생성할 것인가?


6.변수의 초기화


6.1 변수의 초기화

변수의 초기화 : 변수를 선언하고 처음으로 값을 저장하는 것

변수의 초기화는 경우에 따라서 필수적이기도 하고 선택적이기도 하지만, 가능하면 선언과 동시에 적절한 값으로 초기화 하는 것이 바람직하다.

① 멤버변수는 초기화를 하지 않아도 자동적으로 변수의 자료형에 맞는 기본값으로 초기화가 이루어짐

② 지역변수는 사용하기 전에 반드시 초기화 해야한다.

선택적 : 클래스변수, 인스턴스 변수, 배열
필수적 : 지역변수(수동초기화)

멤버변수(클래스변수와 인스턴스변수)와 배열의 초기화는 선택적이지만,
지역변수의 초기화는 필수적이다.

지역변수를 선언하는 방법 여러가지 경우의 수

멤버변수의 초기화는 지역변수와 달리 여러 가지 방법이 있다.

멤버변수의 초기화 방법

  1. 명시적 초기화
  2. 생성자
  3. 초기화 블럭
  • 인스턴스 초기화 블럭 : 인스턴스변수를 초기화 하는데 사용
  • 클래스 초기화 블럭 : 클래스변수를 초기화 하는데 사용

< 정리 >

cv, iv 초기화
① 자동초기화 (자동컴파일 0으로 해주는것)
② 간단초기화 (대입연산자 사용하여 초기화 = 명시적 초기화)
③ 복잡초기화

  • {} (거의 사용하지 않는다)
  • static{} (cv 초기화)
  • 생성자 (iv 초기화)

6.2 명시적 초기화(explicit intialzation)

명시적 초기화(=) 대입연산자를 사용하여 초기화하는것이 명시적 초기화 이다.

class Car {
int door = 4; // 기본형 변수의 초기화
Engine e = new Engin(); // 참조형 변수의 초기화
}


6.3 초기화 블록(initialization block)

when ? : 복잡한 초기화 {} 안에 여러 문장을 넣을 수 있다.

초기화 블럭 (초기화하기 복잡할 때 쓴다.)

  • 인스턴스 초기화 블럭 {}
  • 클래스 초기화 블럭 static{}
class StaticBlockTest {
	static int[] arr = new int[10]; // 명시적 초기화(간단초기화) 
        
    static {  // 클래스 초기화 블럭 - 배열 arr을 난수로 채운다. 
    	for(int i=0; i< arr.length; i++) {
        	arr[i] = (int)(Math.random)*10) + 1;  // 복잡초기화
        }
    }

}

6.4 멤버변수의 초기화 시기완료 순서


클래스 변수 초기화 시점 : 클래스가 처음 로딩될때 단 한번 (메모리에 올라갈때)

인스턴스 변수 초기화 시점 : 인스턴스가 생성될 때 마다 (각각 저장공간이 초기화된다)

class InitTEST {
	static int cv =1;	// 명시적 초기화
    int iv = 1;			// 명시적 초기화
    
    static { cv = 2; } 	//  클래스 초기화 블럭
    { iv = 2; }			//  인스턴스 초기화 블럭
    
    InitTest() {		// 생성자 
    	iv = 3;
    } 
    
}

명심해야 할것

InitTest it = new InitTest(); 를 다른 클래스에서 객체를 생성할때 클래스 초기화는 더이상 되지않고 인스턴스 초기화는 해당되는 인스턴스가 객체화 될때마다 초기화가 진행된다.

그림보면서 파악해야되는것
변수가 생성되는것,
변수가 변경되는것 구분할줄알아야함
어떤 초기화를 사용했는지 구분
어느 시점에서 초기화 되었는지

1,2,3 은 새로 생성된 변수
4,5,6,7 의 경우는 인스턴스변수가 계속 변경되는 것

① CV → iv
② 초기화 순서가 자동(0) → 간단(=) → 복잡(static{}, 생성자)

0개의 댓글