신규 블로그를 만들었습니다!

2020년 이후부터는 아래 블로그에서 활동합니다.

댓글로 질문 주셔도 확인하기 어려울 수 있습니다.

>> https://bluemiv.tistory.com/

1. 객체지향언어

1.1. 객체지향언어의 역사

초창기에는 컴퓨터는 미사일 발사실험, 모의 실험을 목적으로 사용되었다.

 

그리고, 실제 세계와 유사한 가상 세계를 컴퓨터 속에 구현하려 했고, 그 결과 객체지향이론이 탄생했다.

최초의 객체지향언어인 시뮬라(Simula)가 있다.

1.2. 객체 지향 언어

객체지향언어는 절차지향언어에 몇가지 규칙이 추가된 것이기 때문에 완전히 새로운 것이 아니다.

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

2. 클래스와 객체

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

클래스란?

  • 클래스의 정의: 객체를 정의해 놓은 것(틀)
  • 클래스의 용도: 객체를 생성하는데 사용된다.

사전적 정의

  • 객체의 정의: 실제로 존재하는 것. 사물 또는 개념
  • 객체의 용도: 객체가 가지고 있는 기능과 속성에 따라 다름
    • 유형 객체: 책상, 의자, 자동차, TV 등등
    • 무형 객체: 수학 공식, 프로그램 에러와 같은 논리나 개념

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

 

설계도(클래스)를 작성해두면 복잡한 제품 및 부품(객체)도 쉽게 만들 수 있다.

 

JDK에는 많은 수의 유용한 클래스가 기본적으로 제공되어 원하는 기능을 쉽게 작성할 수 있다.

2.2. 객체와 인스턴스

  • 책상은 객체다.
  • 책상은 책상 클래스의 인스턴스다.

객체와 인스턴스는 같은 의미를 가지기 때문에 엄격히 구분할 필요는 없지만, 문맥에 따라 구분해서 사용하는 것이 좋다.

 

클래스 --(인스턴스 화)--> 인스턴스(객체)

2.3. 객체의 구성요소

객체는 다수의 속성 및 기능을 가진다. 이러한 속성, 기능을 멤버(구성원, member)라고 한다.

  • 속성(property): 멤버변수
  • 기능(function): 메소드

2.4. 인스턴스의 생성과 사용

객체 생성

public class Tv {
    String color; // 색상
    boolean power; // 전원
    int channel; // 채널

    public void power() {
        this.power = !power; // 전원 토글
    }

    public void channelUp() {
        channel++; // 채널 증가
    }

    public void channelDown() {
        channel--; // 채널 감소
    }
}
Tv tv; // 참조변수 생성
tv = new Tv(); // 인스턴스 생성 (메모리의 빈 공간에 생성)

tv.channel = 7;
System.out.println(tv.channel);

tv.channelDown();
System.out.println(tv.channel);

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

2.5. 객체 배열

객체 역시 배열로 만드는 것이 가능하다.

Tv[] tvArr = new Tv[3]; // 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();
}

2.6. 클래스의 또 다른 정의

2.6.1. 데이터의 변화

  1. 변수
  2. 배열: 같은 타입의 데이터 집합
  3. 구조체: 타입에 상관없이 여러 데이터의 집합
  4. 클래스: 구조체 + 메소드

2.6.2. 접근 제어자

접근 제어자를 통해서 변수 값의 제한을 걸어, 보다 정확한 데이터를 유지할 수 있다.

 

Time을 예를들어보면 시간은 0 ~ 23 의 범위를 가지고, 분과 초는 0 ~ 59 범위를 가진다.

public class Time {
    private int hour;
    private int minute;
    private float second;

    // Constructor
    public Time () {}

    // Access methods
    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        if (hour < 0 || 23 < hour) return;
        this.hour = hour;
    }

    public int getMinute() {
        return minute;
    }

    public void setMinute(int minute) {
        if (minute < 0 ||  minute > 59) return;
        this.minute = minute;
    }

    public float getSecond() {
        return second;
    }

    public void setSecond(float second) {
        if (second < .0f || second > 59.99f) return;
        this.second = second;
    }

    // 데이터 확인을 위한 메소드
    @Override
    public String toString() {
        return "Time{" +
                "hour=" + hour +
                ", minute=" + minute +
                ", second=" + second +
                '}';
    }
}

3. 변수와 메소드

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

변수에는 클래스 변수, 인스턴스 변수, 지역 변수 총 3개가 있다. 선언 위치에 따라 달라지게 되기 때문에 어느 위치에서 선언이 되었는지 학인하는 것이 중요하다.

class Variables {
    int iv; // instance variable 인스턴스 변수
    static int cv; // class variable 클래스 변수

    void method() {
        int lv = 0; // local variable 지역 변수
    }
}
  • 클래스변수
    • 선언 위치: 클래스 영역
    • 클래스가 메모리에 올라갔을때 생성 (static 키워드를 붙여서 생성)
    • 모든 인스턴스가 공통된 저장공간을 공유
  • 인스턴스 변수
    • 선언 위치: 클래스 영역
    • 인스턴스가 생성됐을때 생성
    • 독립적인 공간을 가지기 때문에 인스턴스끼리 공유하지 않는다.
  • 지역변수
    • 선언 위치: 메소드 내에 선언된 변수로 해당 블럭 안에서만 사용이 가능
    • 블럭을 벗어나면 소멸된다.

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

인스턴스들이 공통된 특징을 가지는 경우 클래스 변수로 선언한다. 각기 다른 특징을 가지는 경우 인스턴스 변수로 선언한다.

 

예를들어, 트럼프 카드가 있을때

class Card {
    String kind; // 문양 (instance variable)
    int number; // 숫자 (instance variable)

    static int width = 100; // 넓이 (class variable)
    static int height = 250; // 높이 (class variable)
}

모든 카드의 넓이와 높이는 공통된 값을 가지니 클래스 변수로 선언, 문양이랑 숫자는 카드마다 다른 값을 가지므로 인스턴스 변수로 선언하는 것이 좋다.

3.3. 메소드

메소드를 사용하는 이유

  1. 높은 재사용성 (reusability)
  2. 중복된 코드의 제거
  3. 프로그램의 구조화 (단순화)
    • 프로그램을 설계할 때, 메소드를 작업단위로 만들어놓고 하나씩 구현하는 것도 좋은 방법이다.

3.3.1. 메소드의 return 문

원래 메소드에는 반환값 유무에 상관없이 return문이 있어야한다. 하지만, void의 경우는 생략을 해도 컴파일러가 자동으로 return;을 추가해준다.

 

반면, void가 아닌 반환값이 있는 경우는 무조건 return 문을 작성해야 한다.

3.3.2. 메소드의 유효성 검사

메소드 구현부를 작성하기 전에 제일 먼저 할 것은 매개변수에 대한 유효성 검사를 하는 것이다. (프로그램이 비정상적으로 종료되는 것을 막기 위해)

호출하는 쪽에서 알아서 적절한 값을 넘겨주겠지 라는 생각은 절대로 가져선 안된다.

3.4. JVM의 메모리 구조

응용프로그램이 실행되면 JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당 받는다. 그리고, 메모리를 용도에 따라 여러 영역으로 나눠서 관리한다.

 

주요 3가지 영역

  1. method area

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

    • 메소드가 호출되면 해당 메소드에 필요한 메모리가 할당된다. 이 메모리는 메소드가 실행되는 동안 지역변수(매개변수 포함)들과 연산의 중간 결과 등을 저장하는데 사용된다.
    • 메소드가 작업을 마치면 메모리공간은 반환되어 비워진다.
  3. heap

    • 인스턴스가 생성되는 공간. 프로그램 실행 중 생성되는 모든 인스턴스는 이곳에 저장된다.
    • 인스턴스 변수(instance variable)도 이 영역에 생성된다.

3.4.1. call stack의 특징

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

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

  • 기본형 매개변수: 변수의 값을 읽을 수만 있다. (Read Only)
  • 참조형 매개변수: 변수의 값을 읽고 변경할 수 있다. (Read & Write)

메소드의 매개변수를 기본형으로 선언하면 단순히 값을 복사하여 넘긴다. 하지만, 참조형인 경우에는 주소값을 복사하여 넘기기 때문에 값을 변경하는 것이 가능하다.

public class Parameter {
    private int x;
    private int y;

    // Constructor
    public Parameter() {}
    public Parameter(int x, int y) {
        this.x = x;
        this.y = y;
    }

    // Access methods
    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    // 기본형 매개변수 변경하는 메소드
    public static void changePrimitiveParam(int num) {
        num += 10;
    }

    // 참조형 매개변수 변경하는 메소드
    public static void changeReferenceParam(Parameter param) {
        param.setX(100);
        param.setY(200);
    }

    @Override
    public String toString() {
        return "Parameter{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }
}
// 기본형 매개변수는 바뀌지 않는다. (Read only)
System.out.println("기본형(primitive) 매개변수 값 변경");
int z = 10;
System.out.println("변경 전 z: " + z);
Parameter.changePrimitiveParam(z);
System.out.println("변경 후 z: " + z);

// 참조형 매개변수는 바뀔 수 있다. (Read & Write)
System.out.println("참조형(Reference) 매개변수 값 변경");
final Parameter param = new Parameter();
System.out.println("변경 전 Parameter: " + param.toString());
Parameter.changeReferenceParam(param);
System.out.println("변경 후 Parameter: " + param.toString());

결과

기본형(primitive) 매개변수 값 변경
변경 전 z: 10
변경 후 z: 10
참조형(Reference) 매개변수 값 변경
변경 전 Parameter: Parameter{x=0, y=0}
변경 후 Parameter: Parameter{x=100, y=200}

3.6. 재귀호출(recursive call)

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

재귀호출과 반복문은 서로 유사한점이 많아서 변환이 가능하다.

 

반복문은 그저 같은 문장을 반복해서 호출하지만, 재귀 호출은 매개변수 복사와 종료, 복귀할 메모리 주소 저장 등 추가적으로 필요한 요소가 많다. 그래서 반복문보다 재귀호출의 수행시간이 더 오래걸린다.

 

재귀호출을 사용하는 이유는 논리적 간결함 때문이다. 논리적으로 간결하게 표현이 가능한 경우, 비효율적이더라도 오류를 줄이고 단순한 구조로 바꿀 수 있다.

3.7. 클래스 메소드(static 메소드)와 인스턴스 메소드

  • 인스턴스 메소드는 인스턴스 변수와 관련된 작업을 하는, 즉 인스턴스 변수를 필요로 하는 메소드일때 정의한다.
  • 클래스 메소드는 인스턴스와 관계없이 공통으로 사용되는 메소드일때 정의한다.

무조건 인스턴스를 사용하지 않는다고 클래스 메소드를 만드는 것은 아니지만, 특별한 이유가 없는 한 클래스 메소드로 만드는것이 일반적이다.

 

정리

  1. 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에는 static을 붙인다.
  2. 클래스 변수(static 변수)는 인스턴스를 생성하지 않아도 사용할 수 있다.
  3. 클래스 메소드(static method)는 인스턴스 매개변수를 사용할 수 없다.
  4. 메소드 내에서 인스턴스 변수를 사용하지 않는다면 static을 붙이는 것을 고려한다.
public class MyMath {
    static int add(int x, int y) {
        return  x + y;
    }

    static int subtract(int x, int y) {
        return x - y;
    }

    static double multiply(double x, double y) {
        return x * y;
    }

    static double divide(double x, double y) {
        return x / y;
    }
}
MyMath.add(1, 3)
MyMath.subtract(10, 5)
MyMath.multiply(1, 2)
MyMath.divide(10, 5)

3.8. 클래스 멤버와 인스턴스 멤버간이 참조와 호출

같은 클래스내에서는 별도의 인스턴스를 생성하지 않고도 참조 또는 호출이 가능하다.

 

클래스 멤버가 인스턴스 멤버를 호출하는 경우, 인스턴스를 생성해야한다. (클래스 멤버가 생성되는 시점에 인스턴스 멤버가 존재하지 않을 수 있기 때문에)


public class MemberCall {
    private int iv = 10;
    private static int cv = 20;

    private int iv2 = cv; // 인스턴스 변수에서 클래스 변수를 사용할 수 있음
//    private static int cv2 = iv2; // 반대로, 클래스 변수에 인스턴스 변수를 사용할 수 없음.

    // Methods
    public static void staticMethod() {
        System.out.println("cv: " + cv);
//        System.out.println("iv: " + iv); // 클래스 메소드에서 인스턴스 변수를 사용할 수 없음

        // 인스턴스를 생성해서 사용
        MemberCall memberCall = new MemberCall();
        System.out.println("memberCall.iv: " + memberCall.iv);
    }

    public void instanceMethod() {
        System.out.println("cv: " + cv); // 클래스 변수 사용 가능
        System.out.println("iv: " + iv); // 인스턴스 변수 사용 가능
    }

    public static void staticMethod2() {
        staticMethod(); // 클래스 메소드 사용 가능
//        instanceMethod(); // 클래스 메소드에서 인스턴스 메소드 사용 불가
    }

    public void instanceMethod2() {
        // 둘다 사용가능
        staticMethod();
        instanceMethod();
    }
}

정리

  • 클래스 멤버는 언제나 참조 또는 호출이 가능하다.
  • 인스턴스 멤버는 객체가 생성되지 않았을 수 있기 때문에, 언제나 호출이 가능한 것은 아니다.
  • 인스턴스 멤버끼리는 참조 또는 호출이 가능하다.

4. 오버로딩 (overloading)

4.1. 오버로딩?

자바에서는 매개 변수의 타입 또는 개수가 다르면 같은 이름의 메소드를 정의 할 수 있다. 이를 오버로딩이라 한다.

4.2. 오버로딩의 조건

  1. 메소드의 이름이 같아야 한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.
주의. 반환 타입은 오버로딩을 구현하는데 아무런 영향을 주지 못한다. 즉, 오버로딩은 매개변수에 의해서만 구분 될 수 있다.

4.3. 오버로딩의 예

대표적인 예로 println() 메소드를 들 수 있다.

System.out.println() ...
System.out.println(boolean x) ...
System.out.println(char x) ...
System.out.println(char[] x) ...
System.out.println(double x) ...
System.out.println(float x) ...
System.out.println(int x) ...
System.out.println(long x) ...
System.out.println(Object x) ...
System.out.println(String x) ...
public static int add (int x, int y) {
    return x + y;
}

public static long add(long x, int y) {
    return x + y;
}

public static long add(int x, long y) {
    return x + y;
}

public static long add(long x, long y) {
    return x + y;
}
final int intX = 10, intY = 20;
final long longX = 100_000L, longY = 200_000L;

Stream.of(
    add(intX, intY),
    add(longX, intY),
    add(intX, longY),
    add(longX, longY)
).forEach(System.out::println);

4.4. 오버로딩의 장점

오버로딩이 없다면, 근본적으로 같은 역할을 하는 메소드지만 각각 다른 이름을 사용해서 메소드를 생성해야하는 불편함이 있다.

예를들어서,

System.out.println() ...
System.out.printlnBoolean(boolean x) ...
System.out.printlnChar(char x) ...
System.out.printlnCharArr(char[] x) ...
...

System.out.println() 메소드는 근본적으로 콘솔에 매개변수를 출력하는 역할을 하지만, 오버로딩이 없다면 위처럼 모두 다른 이름으로 메소드를 정의해야한다.

메소드 이름이 같음으로서 우리는 "같은 기능을 하는 메소드구나" 라고 예상할 수 있다.

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

매개 변수 개수가 고정된 것이 아닌, 동적으로 지정하고 싶을 때 "타입... 변수명" 과 같이 표현한다.

 

예를들어, concatenate(문자를 합치는 기능) 메소드를 구현할 때, 가변인자를 이용하면 편리하다.

 

가변인자를 사용하지 않는 경우

concat(String delim, String str1, String str2)
concat(String delim, String str1, String str2, String str3)
concat(String delim, String str1, String str2, String str3, String str4)
...

가변인자를 사용하는 경우
```java
public static String concat(String delim, String... strs) {
    final StringBuffer sb = new StringBuffer();

    Stream.of(strs)
            .filter(str -> !str.isEmpty())
            .forEach(str -> sb.append(str + delim));

    return sb.toString();
}
Stream.of(
        MyString.concat("/", "Hello,", "Java", ""),
        MyString.concat("/", "Hello,", "Java", "", "!"),
        MyString.concat("/", "Hello,", "Java", "", "!", "!")
).forEach(System.out::println);
주의. 가변인자를 이용한 오버로딩 메소드는 구별되지 못하는 경우가 발생하기 쉽기 때문에 가변인자를 이용한 오버로딩을 하지 않는 것이 좋다.

5. 생성자 (Constructor)

5.1. 생성자란?

생성자는 인스턴스가 생성될 때 호출되는 인스턴스 초기화 메소드이다. 따라서, 주로 초기화하는 작업을 할때 사용된다.

  1. 생성자의 이름은 클래스의 이름과 같아야 한다.
  2. 생성자는 리턴 값이 없다.

생성자도 오버로딩이 가능하다. 예를들어,

public class Card {
    private String kind; // 무늬
    private int number; // 숫자

    private static int width = 100; // 가로 길이
    private static int height = 250; // 세로 길이

    // Constructor
    public Card() {} // 매개변수가 없는 생성자

    public Card(String kind, int number) {      // 매개변수가 있는 생성자
        this.kind = kind;
        this.number = number;
    }

    ...
}

5.1.1. 인스턴스가 만들어지는 과정

주의할 점. 연산자 new가 인스턴스를 생성하는 것이지, 생성자(Constructor)가 인스턴스를 생성하는 것이 아니다.

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

5.2. 기본 생성자 (Default Constructor)

생성자를 성성하지 않더라도 컴파일러는 자동적으로 기본 생성자를 만들어준다.

컴파일을 할 때, .java 파일에 생성자가 없다면

클래스이름() {}

위와같이 기본 생성자를 생성해준다. (반대로 생성자가 있다면 생성해주지 않는다.)

class Card {
    ...

    Card(String kind, int number) {
        ...
    }

    ...
}

// 호출부분
Card card = new Card(); // 컴파일 에러 발생.

이미 매개변수가 있는 생성자가 있기 때문에, 컴파일러는 기본 생성자(Card())를 생성하지 않는다.

즉, 기본생성자가 컴파일러에 의해 추가되는 경우는 클래스에 생성자가 하나도 없는 경우이다.

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

같은 클래스의 멤버들 간에 서로 호출할 수 있는 것처럼 생성자 간에도 호출이 가능하다. 단, 2가지 규칙을 지켜야한다.

  • 생성자의 이름으로 클래스 이름 대신에 this 키워드를 사용한다.
  • 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫줄에서만 호출이 가능하다.
public class Car {
    private String color; // 색상
    private String gearType; // 변속기 종류 - 오토 or 수동
    private int door; // 문의 개수

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

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

    public Car(String color) {
        this(color, "auto", 4);
    }
}
// 실행부
Stream.of(
        new Car().toString(),
        new Car("pink").toString(),
        new Car("black", "manual", 6).toString()
).forEach(System.out::println);

위에서 this.color는 인스턴스 변수를 뜻하고, color는 매개변수를 뜻한다.

정리

  • this는 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.
  • this(), this(매개변수)는 생성자를 뜻한다. 같은 클래스의 다른 생성자를 호출할 때 사용한다.

6. 변수의 초기화

6.1. 변수의 초기화

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

int i;
int j = i; // 컴파일러 에러.

인스턴스 변수는 초기화를 하지 않아도 (정수형인경우) 0으로 초기화 해준다.

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

6.2. 멤버변수의 초기화

6.2.1. 명시적 초기화 (Explicit initialization)

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

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

6.2.2. 초기화 블럭(initialization block)

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

배열과 같이 초기화 과정이 복잡한 경우 초기화 블럭을 사용하면 좋다.

public class InitBlock {

    static { /* 클래스 초기화 블럭 */ }

    { /* 인스턴스 초기화 블럭 */ }

}

인스턴스 변수의 초기화는 보통 생성자 초기화를 이용하고, 공통으로 수행되는 코드의 경우 인스턴스 초기화 블럭을 이용한다.

// 인스턴스 초기화 블럭을 이용하여 공통 부분을 제거
{
    count++;
    serialNo = count;
}

Car() {
    // count++;         // 중복되는 코드
    // serialNo = count;
    color = "White";
    gearType = "Auto";
}

Car(String color, String gearType) {
    // count++;
    // serialNo = count;
    this.color = color;
    this.gearType = gearType;
}

코드의 중복을 제거하는 것은 코드의 신뢰성을 높여준다. 그리고 오류의 발생 가능성을 줄여준다는 장점이 있다. 프로그래머는 코드의 중복을 최대한 제거하기 위해 노력해야 한다.

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

시점

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

순서

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

클래스가 실행되는 시점에 메모리에 로딩된다. 이미 메모리에 로딩되어 있다면 다시 로딩하지 않는다. (클래스 멤버가 한번만 호출되는 이유)

 

중요. 클래스 변수는 인스턴스 변수보다 항상 먼저 생성되고 초기화 된다.

Reference

Java의 정석, 남궁 성 지음

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기