자바 도전기-12

김치전사·2022년 1월 7일
0

자바도전기

목록 보기
12/17

드디어 객체지향언어(객체지향프로그래밍)을 학습한다!!

객체지향언어

객체지향언어의 특징

1.코드의 재사용성이 높다
-새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있다
2.코드의 관리가 용이하다
-코드간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있다
3.신뢰성이 높은 프로그래밍을 가능하게 한다
-제어자와 메서드를 이용해서 데이터를 보호하고 올바른 값을 유지하도록 하며, 코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지할 수 있다

객체지향언어의 가장 큰 장점은 '코드의 재사용성이 높고 유지보수가 용이하다'는 것이다
상속, 다형성과 같은 객체지향개념을 학습할 때 재사용성과 유지보수 그리고 중복된 코드의 제거, 이 세 가지 관점에서 보면 쉽게 이해할 수 있을 것이다

클래스와 객체

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

클래스의 정의 : 클래스란 객체를 정의해 놓은 것이다
클래스의 용도 : 클래스는 객체를 생성하는데 사용된다

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

객체의 정의 : 실제로 존재하는 것. 사물 또는 개념
객체의 용도 : 객체가 가지고 있는 기능과 속성에 따라 다름

유형의 객체 : 책상, 의자, 자동차, TV와 같은 사물
무형의 객체 : 수학공식, 프로그램 에러와 같은 논리나 개념
클래스객체
제품 설계도제품
TV 설계도TV
붕어빵 기계붕어빵

객체와 인스턴스

클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화(instantiate)라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스(instance)라고 한다

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

객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있으며, 일반적으로 객체는 다수의 속성과 다수의 기능을 갖는다.

속성(property) : 멤버변수(member variable), 특성(attribute), 필드(field), 상태(state)
기능(function) : 메서드(method), 함수(function), 행위(behavior)

인스턴스의 생성과 사용

클래스명 변수명; // 클래스의 객체를 참조하기 위한 참조변수를 선언
변수명 = new 클래스명();//클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장

TV t;//Tv클래스 타입의 참조변수 t를 선언
t= new TV();//T인스턴스 생성한 후,  생성된 Tv인스턴스의 주소를 t에 저장
class Tv{
    String color;
    boolean power;
    int channel;

    void power(){power=!power;}
    void channelUp(){++channel;}
    void channelDown(){--channel;}
}

public class TvTest {
    public static void main(String args[]){
        Tv t;
        t= new Tv();
        t.channel = 7;
        t.channelDown();
        System.out.println("현재 채널은 "+t.channel+" 입니다.");
    }
}
  1. Tv t;
    -Tv클래스 타입의 참조변수 t를 선언한다. 메모리에 참조변수 t를 위한 공간이 마련된다. 아직 인스턴스가 생성되지 않았으므로 참조변수로 아무것도 할 수 없다.
  2. t= new Tv();
    -연산자 new에 의해 Tv클래스의 인스턴스가 메모리의 빈 공간에 생성된다. 멤버변수는 각 자료형에 해당하는 기본값으로 초기화 된다. color는 참조형이므로 null로, power는 boolean이므로 false로, 그리고 channel은 int이므로 0으로 초기화 된다.
  3. t.channel = 7;
    -참조변수 t에 저장된 주소에 있는 인스턴스의 멤버변수 channel에 7을 저장한다. 여기서 알 수 있는 것처럼 인스턴스의 멤버변수(속성)를 사용하려면 '참조변수.멤버변수'와 같이 하면 된다
  4. t.channelDown();
    -참조변수 t가 참조하고 있는 Tv인스턴스의 channelDown메서드를 호출한다.

인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야한다

객체 배열

객체 역시 배열로 다르는 것이 가능하며, 이를 '객체 배열'아록 한다.
객체 배열 안에 객체가 저장되는 것은 아니고, 객체의 주소가 저장된다.

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()};
class Tv{
    String color;
    boolean power;
    int channel;

    void power(){power = !power;}
    void channelUp(){++channel;}
    void channelDown(){--channel;}
}

public 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.printf("tvArr[%d].channel=%d%n",i,tvArr[i].channel);
        }
    }
}

클래스의 또 다른 정의

클래스는 '객체를 생성하기 위한 틀'이며 '클래스는 속성과 기능으로 정의되어있다'고 했다.
1.클래스-데이터와 함수의 결합

1. 변수 : 하나의 데이터를 저장할 수 있는 공간
2. 배열 : 같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간
3. 구조체 : 서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합으로 저장할 수 있는 공간
4. 클래스 : 데이터와 함수의 결합(구조체 + 함수)

2.클래스 - 사용자정의 타입(user-defined type)
프로그래밍어너에서 제공하는 자료형(primitive type)외에 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것을 사용자정의 타입(user-defined type)이라고 한다.

변수와 메서드

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

변수는 클래스변수, 인스턴스변수, 지역변수 모두 세 종료가 있다..
변수의 종류를 결정짓는 중요한 요소는 '변수의 선언된 위치'이므로 변수의 종류를 파악하기 위해서는 변수가 어느 영역에 선언되었는지를 확인하는 것이 중요하다.
멤버변수를 제외한 나머지 변수들은 모두 지역변수이며, 멤버변수 중 static이 붙은 것은 클래스변수, 붙지 않은 것은 인스턴스변수이다.

class Variables{
	int iv; //인스턴스 변수
    	static int cv;//클래스변수(static변수, 공유변수)
        void method()
        {
        	int lv = 0; //지역변수
        }
}
변수의 종류선언위치생성시기
클래스변수클래스 영역클래스가 메모리에 올라갈 때
인스턴스변수클래스 영역인스턴스가 생성되었을 때
지역변수클래스 영역 이외의 영역변수 선언문이 수행되었을 때
  1. 인스턴스 변수(instatnce variable)
    -클래스 영역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어진다.
    -인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있다.
  2. 클래스 변수(class variable)
    -클래스 변수를 선언하는 방법은 인스턴스변수 앞에 static을 붙이기만 하면 된다.
    -인스턴스마다 독립적인 저장공간을 갖는 인스턴스변수와는 달리, 클래스변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 된다.
    -한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우, 클래스변수로 선언해야 한다.
    -클래스 변수는 인스턴스변수와 달리 인스턴스를 생성하지 않아도 언제라도 바로 사용할 수 있다는 특징이 있으며, '클래스 이름.클래스변수'와 같은 형식으로 사용한다.
  3. 지역변수(local variable)
    -메서드 내에 선언되어 메서드 내에서만 사용 가능하며, 메서드가 종료되면 소멸되어 사용할 수 없게 된다.

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

인스턴스변수는 인스턴스가 생성될 때 마다 생성되므로 인ㄴ스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.

메서드

메서드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다.
메서드를 사용하는 이유
1. 높은 재사용성(reusability)
2. 중복된 코드의 제거
-반복되는 문장들을 묶어서 하나의 메서드로 작성해 놓으면, 반보고디는 문장들 대신 메서드를 호출하는 한 문장으로 대체할 수 있다.
3. 프로그램의 구조화

메서드의 선언과 구현

메서드는 크게 두 부분, '선언부(header.머리)'와 '구현부(body, 몸통)'로 이루어져 있다.

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

메서드 선언부는 '메서드의 이름'과 '매개변수 선언', 그리고 '반환타입'으로 구성되어 있으며, 메서드가 작업을 수행하기 위해 어떤 값들을 필요로 하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한 정보를 제공한다.

메서드의 호출

메서드를 호출해야만 구현부{ }의 문장들이 수행된다.

return문

return문은 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아간다. 지금까지 반환값이 있을 때만 return문을 썼지만, 원래는 반환값의 유무에 관계없이 모든 메서드에는 적어도 하나의 return문이 있어야 한다.

void printShow(){
        System.out.println("Show");
        //return; 생략가능
    }

JVM의 메모리 구조

  1. 메서드 영역(method area)
    -프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스파일을 읽어서 분석하여 클래스에 대한 정보를 이곳에 저장한다. 이 때, 그 클래스의 클래스변수(class variable)도 이 영역에 함께 생성된다
  2. 힙(heap)
    -인스턴스가 생성되는 공간. 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다.
  3. 호출스택(call stack 또는 execution stack)
    -호출스택은 메서드의 작업에 필요한 메모리 공간을 제공한다.

호출스택 특징

-메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받는다
-메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거된다
-호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드이다
-아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드이다

public class CallStackTest {
    public static void main(String[] args){
        firstMethod();
    }

    static void firstMethod(){
        secondMethod();
    }

    static void secondMethod(){
        System.out.println("secondMethod()");
    }
}

객체를 생성하지 않고도 메서드를 호출할 수 있으려면, 메서드 앞에 'static'을 붙여야 한다

public class CallStackTest2 {
    public static void main(String[] args){
        System.out.println("main이 시작됨");
        firstMethod();
        System.out.println("main이 끝남");
    }

    static void firstMethod(){
        System.out.println("firstMethod가 시작됨");
        secondMethod();
        System.out.println("firstMethod가 끝남");
    }

    static void secondMethod(){
        System.out.println("secondMethod가 시작됨");
        System.out.println("secondMethod가 끝남");
    }
}

각 메서드의 시작과 종료의 순서를 확인하는 예제이다.

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

기본형 매개변수 : 변수의 값을 읽기만 할 수 있다(read only)
참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다(read & write)

참조형 반환타입

매개변수뿐만 아니라 반환타입도 참조형이 될 수 있다.

class Data {int x;}

public class ReferenceReturnEx {
    public static void main(String[] args){
        Data d= new Data();
        d.x=10;

        Data d2 = copy(d);
        System.out.println("d.x = "+d.x);
        System.out.println("d2.x= "+d2.x);
    }

    static Data copy(Data d){
        Data tmp = new Data();
        tmp.x=d.x;

        return tmp;
    }
}

반환하는 값이 Data객체의 주소이므로 반환 타입이 'Data'인 것이다.

반환타입이 '참조형'이라는 것은 메서드가 '객체의 주소'를 반환한다는 것을 의미한다.

재귀호출(recursive call)

메서드의 내부에서 메서드 자신을 다시 호출하는 것을 '재귀호출(recursive call)'이라 하고, 재귀호출을 하는 메서드를 '재귀 메서드'라 한다.

void method(){
	method();// 재귀호출. 메서드 자신을 호출한다
}

호출된 메서드는 '값에 의한 호출(call by value)'을 통해, 원래의 값이 아닌 복사된 값으로 작업하기 때문에 호출한 메서드와 관계없이 독립적인 작업수행이 가능하다

public class FactorialTest {
    public static void main(String[] args){
        int result = factorial(5);

        System.out.println(result);
    }

    static int factorial(int x){
        int result=0;
        if(x==1){
            return result=1;
        }else{
            result = x*factorial(x-1);
        }
        return result;
    }
}

재귀호출의 대표적인 예시인 팩토리얼이다.
재귀호출은 무한루프가 될 수 있기 때문에 조건문이 필수적으로 따라다닌다.

public class FactorialTest2 {
    static long factorial(int n){
        if(n<=0 || n>=20){
            return -1;
        }
        if(n<=1){
            return 1;
        }
        return n*factorial(n-1);
    }
    public static void main(String[] args){
        int n=21;
        long result = 0;
        for(int i=1;i<=n;i++){
            result = factorial(i);

            if(result==-1){
                System.out.printf("유효하지 않은 값입니다. (0<n<=20) : %d%n",n);
                break;
            }
            System.out.printf("%2d!=%20d%n",i,result);
        }
    }
}

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

메서드 앞에 static이 부터 있으면 클래스메서드이고 붙어 있지 않으면 인스턴스 메서드이다.
인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드이다.

  1. 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.
  • 생성된 각 인스턴스는 서로 독립적이기 때문에 각 인스턴스 변수(iv)는 서로 다른 값을 유지한다. 그러나 모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스변수로 정의해야 한다.
  1. 클래스 변수(static변수)는 인스턴스를 생성하지 않아도 사용할 수 있다.
  • static이 붙은 변수(클래스변수)는 클래스가 메모리에 올라갈 때 이미 자동적으로 생성되기 때문이다
  1. 클래스 메서드(static메서드)는 인스턴스 변수를 사용할 수 없다
    -인스턴스변수는 인스턴스가 반드시 존재해야만 사용할 수 있는데, 클래스메서드(static이 붙은 메서드)는 인스턴스 생성 없이 호출가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수도 있다.
  2. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다
    -메서드의 작업내용 중에서 인스턴스변수를 필요로 한다면, static을 붙일 수 없다.

-클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면, static을 붙여준다.
-작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려한다

class MyMath2 {
    long a,b;
    //인스턴스변수 a,b만을 이용해서 작업하므로 매개변수가 필요없다.
    long add(){return a+b;}//a,b는 인스턴스변수
    long subtract(){return a-b;}
    long multiply(){return a*b;}
    long divide(){return a/b;}
    //인스턴스변수와 관계없이 매개변수만으로 작업이 가능하다
    static long add(long a,long b){return a+b;}
    static long subtract(long a, long b){return a-b;}
    static long multiply(long a, long b){return a*b;}
    static long divide(long a, long b){return a/b;}
}

public class MyMathTest2{
    public static void main(String[] args){
        //클래스메서드 호출. 인스턴스 생성없이 호출가능
        System.out.println(MyMath2.add(200L,300L));
        System.out.println(MyMath2.subtract(200L,300L));
        System.out.println(MyMath2.multiply(200L,300L));
        System.out.println(MyMath2.divide(200L,300L));
        
        MyMath2 mm = new MyMath2();//인스턴스를 생성
        mm.a=200L;
        mm.b=300L;
        //인스턴스메서드는 객체생성 후에만 호출이 가능함
        System.out.println(mm.add());
        System.out.println(mm.subtract());
        System.out.println(mm.multiply());
        System.out.println(mm.divide());
    }
}

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

같은 클래스에 속한 멤버들 간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능하다.
단, 클래스멤버가 인스턴스 멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 한다.

class TestClass{
    void instanceMethod(){}//인스턴스메서드
    static void staticMethod(){}//static 메서드
    
    void instanceMethod2(){//인스턴스메서드
        instanceMethod();//다른 인스턴스메서드를 호출한다
        staticMethod();//static메서드를 호출한다
    }
    
    static void staticMethod2(){//static메서드
        instanceMethod();//에러!!! 인스턴스메서드를 호출할 수 없다
        staticMethod();//static메서드는 호출 할 수 있다
    }
}

클래스멤버(클래스변수와 클래스메서드)는 언제나 참조 또는 호출이 가능하기 때문에 인스턴스멤버가 클래스멤버를 사용하는 것은 아무런 문제가 안된다. 클래스멤버간의 참조 또는 호출 역시 아무런 문제가 없다.
그러나, 인스턴스멤버는 반드시 객체를 생성한 후에만 참조 또는 호출이 가능하기 대문에 클래스멤버가 인스턴스멤버를 참조, 호출하기 위해서는 객체를 생성해야 한다.

오버로딩(overloading)

오버로딩이란?

한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것을 '메서드 오버로딩(method overloading)' 또는 간단히 '오버로딩(overloading)'이라 한다.

오버로딩의 조건

  1. 메서드 이름이 같아야 한다
  2. 매개변수의 개수 또는 타입이 달라야 한다

반환 타입은 오버로딩을 구현하는데 아무런 영향을 주지 못한다

long add(int a, long b){return a+b;}
long add(long a, int b){return a+b;}

오버로딩으로 간주함

오버로딩의 장점

메서드의 이름만 보고도 '이 메서드들은 이름이 같으니, 같은 기능을 하겠구나.'라고 쉽게 예측할 수 있다.
메서드의 이름을 절약할 수 있다는 것이다.

public class OverloadingTest {
    public static void main(String args[]){
        MyMath3 mm = new MyMath3();
        System.out.println(mm.add(3,3));
        System.out.println(mm.add(3L,3));
        System.out.println(mm.add(3,3L));
        System.out.println(mm.add(3L,3L));

        int[] a={100,200,300};
        System.out.println(mm.add(a));
    }
}

class MyMath3{
    int add(int a,int b){
        return a+b;
    }
    long add(int a, long b){
        return a+b;
    }
    long add(long a, int b){
        return a+b;
    }
    long add(long a, long b){
        return a+b;
    }
    int add(int[] a){
        int result = 0;
        for(int i=0;i<a.length;i++){
            result+=a[i];
        }
        return result;
    }
}

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

기존에는 메서드의 매개변수 개수가 고정적이었으나 JDK1.5부터 도적으로 지정해 줄 수 있게 되었으며, 이 기능을 '가변인자(variable arguments)'라고 한다.
가변인자는 '타입... 변수명'과 같은 형식으로 선언한다.

생성자

생성자란?

생성자는 인스턴스가 생성될 떄 호출되는 '인스턴스 초기화 메서드'이다. 따라서 인스턴스 변수의 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야 할 작업을 위해서도 사용된다.

  1. 생성자의 이름은 클래스의 이름과 같아야 한다
  2. 생성자는 리턴 값이 없다
class Card{
	Card(){ //매개변수가 ㅇ벗는 생성자
    		...
        }
        Card(String k, int num){// 매개변수가 있는 생성자
        	...
        }
        ...
}

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

Card c = new Card();
1. 연산자 new에 의해서 메모리(heap)에 Card클래스의 인스턴스가 생성된다.
2. 생성자 Card()가 호출되어 수행된다.
3. 연산자 new의 결과로, 생성된 Card인스턴스의 주소가 반환되어 참조변수 c에 저장된다.

기본 생성자(default constructor)

기본 생성자가 컴파일러에 의해서 추가되는 경우는 클래스에 정의된 생성자가 하나도 없을 때 뿐이다

매개변수가 있는 생성자

class Car{
    String color;
    String gearType;
    int door;
    
    Car(){}//생성자
    Car(String c, String g, int d){//생성자
        color=c;
        gearType=g;
        door=d;
    }
}

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

같은 클래스의 멤버들 간에 서로 호출할 수 있는 것처럼 생성자 간에도 서로 호출이 가능하려면 다음의 두 조건을 만족시켜야 한다.

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

class Car{
    String color;
    String gearType;
    int door;

    Car(){
        this("white","auto",4);
    }

    Car(String color){
        this(color,"auto",4);
    }

    Car(String color, String gearType, int door){
        this.color= color;
        this.gearType=gearType;
        this.door=door;
    }
}

public class CarTest2 {
    public static void main(String[] args){
        Car c1 = new Car();
        Car c2 = new Car("blue");

        System.out.println(c1.color+c1.gearType+c1.door);
        System.out.println(c2.color+c2.gearType+c2.door);
    }
}

this를 사용하여 호출이 가능하다

this : 인스턴스 자시을 가리키ㅣ는 참조변수, 인스턴스의 주소가 저장되어 있다. 모든 인스턴스메서드에 지역변수로 숨겨진 채로 존재한다.
this(), this(매개변수) : 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.

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

class Car{
    String color;
    String gearType;
    int door;
    
    Car(){
        this("white","auto",4);
    }
    
    Car(Car c){
        color = c.color;
        gearType = c.gearType;
        door = c.door;
    }
    
    Car(String color, String gearType, int door){
        this.color = color;
        this.gearType = gearType;
        this.door = door;
    }
}

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

변수의 초기화

변수의 초기화

변수를 선언하고 처음으로 값을 저장하는 것을 '변수의 초기화'라고 한다.
멤버변수는 초기화를 하지 않아도 자동적으로 변수의 자료형에 맞는 기본값으로 초기화가 이루어지므로 초기화하지 않고 사용해도 되지만, 지역변수는 사용하기 전에 반드시 초기화해야 한다.

class InitTest{
	int x; //인스턴스변수
    	int y=x;//인스턴스변수
        void method1(){
        	int i;//지역변수
            	int j = i;//에러. 지역변수를 초기화하지 않고 사용
        }
}

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

멤버변수의 초기화 방법
1. 명시적 초기화(explicit initialization)
2. 생성자(constructor)
3. 초기화 블럭(initialization block)
-인스턴스 초기화 블럭 : 인스턴스변수를 초기화 하는데 사용
-클래스 초기화 블럭 : 클래스변수를 초기화 하는데 사용

명시적 초기화(explicit initialization)

변수를 선언과 동시에 초기화하는 것을 명시적 초기화라고 한다.

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

초기화 블럭(initialization block)

초기화 블럭에는 '클래스 초기화 블럭'과 '인스턴스 초기화 블럭' 두 가지 종류가 있다.

클래스 초기화 블럭 : 클래스변수의 복잡한 초기화에 사용된다
인스턴스 초기화 블럭 : 인스턴스변수의 복잡한 초기화에 사용된다

class InitBlock{
    static { /* 클래스 초기화블럭 입니다. */}
    {/* 인스턴스 초기화블럭 입니다. */}
    //...
}
public class BlockTest {
    static{//클래스 초기화 블럭
        System.out.println("static { }");
    }

    {//인스턴스 초기화 블럭
        System.out.println("{ }");
    }
    public BlockTest(){
        System.out.println("생성자");
    }

    public static void main(String[] args){
        System.out.println("BlockTest bt = new BlockTest(); ");
        BlockTest bt = new BlockTest();

        System.out.println("BlockTest bt2 = new BlockTest(); ");
        BlockTest bt2 = new BlockTest();
    }
}

멤버변수의 초기화 시기와 순서

클래스변수의 초기화시점 : 클래스가 처음 로딩될 때 단 한번 초기화 된다
인스턴스변수의 초기화시점 : 인스턴스가 생성될 때마다 각 인스턴스별로 초기화가 이루어진다

클래스변수의 초기화순서 : 기본값->명시적초기화->클래스 초기화 블럭
인스턴스변수의 초기화순서 : 기본값->명시적초기화->인스턴스 초기화 블럭->생성자

profile
개인공부 블로그입니다. 상업적 용도 X

0개의 댓글