클래스

dev_314·2022년 10월 3일
0
post-thumbnail

| 백기선님의 라이브 스터디를 참고하여 작성한 게시물입니다.

클래스 정의하는 방법

참고: 클래스의 선언

기본적으로 클래스는 다음과 같은 형태를 띤다.

접근제어자 class 클래스이름 {

    접근제어자 필드타입 필드이름;

    ...

    접근제어자 메소드반환형 메소드이름(파라미터 타입 파라미터 이름)
    ...

};

Access Modifier

자바는 접근제어자를 사용하여 변수나 메소드에 대한 접근 범위를 제한할 수 있다.

public

모든 클래스에서 접근 가능

protected

동일한 패키지에 위치한 모든 클래스, 클래스를 상속한 다른 패키지에 위치한 하위 클래스에서 접근 가능

default

어떠한 Access Modifier도 명시하지 않았을 때 기본적으로 적용되는 정책
동일한 패키지에 위치한 모든 클래스에서 접근 가능

private

변수, 메소드를 포함하는 클래스에서만 접근 가능

Variable, Method

지난 주에 공부했던 것 처럼, 변수는 세 가지로 구분할 수 있다.
Instance, class Variable은 class에서 선언한다.

public class Person {
	private String name; // instance variable
    protected Integer age; // instance variable
    
    static String staticVariable // class variable
}

메소드는 아래와 같은 형태를 띤다.
Local varaible은 class의 method 내부에서 선언한다.
Local varaible은 사용전 반드시 초기화가 이뤄져야 한다.

public class Person {
	
    ...
    
    // Access_Modifier, return_Type, method_name(param_type param_name) { ... }
    public void printMessage() {
    	String message = "hello my name is " + this.name; // local variable
    	System.out.println(message);
    }
}

Constructor

default Constructor

모든 Class는 최소한 1개의 생성자를 가져야 한다.
생성자를 정의하지 않은 경우, 자바 컴파일러는 기본 생성자를 자동으로 생성한다.

class MyClass {
	int i;
    boolean b;
    char c;
    
    void myMethod() {
    	...
    }
}

위와 같이 생성자가 없는 코드를 자바 컴파일러는 다음과 같이 만들어준다.

class MyClass {
	int i;
    boolean b;
    char c;
    
    // 기본 생성자
    MyClass() {
    }
    
    void myMethod() {
    	...
    }
}

기본 생성자는 instance variable를 초기화 하지 않는다.

class MyClass {
	int i;
    boolean b;
    char c;
    
    // 명시적으로 생성자를 정의했다.
    MyClass(int i) {
    	this.i = i;
    }
    
    void myMethod() {
    	...
    }
}


MyClass obj1 = new MyClass(1);
MyClass obj2 = new MyClass(); // Error, 기본 생성자 없음

위와 같이 개발자가 생성자를 명시적으로 정의한 경우, 기본 생성자는 생성되지 않는다.

Bytecode Level에서 살펴보기

참고: Where is definition of Method java/lang/Object."init":()V?

package defaultconstructor;

public class DefaultConstructor {

}

위와 같은 클래스를 컴파일한 바이트 코드를 살펴보자

javap -v -p -s DefaultConstructor.class

코드 영역을 보니, 자바 컴파일러에 의해 default constructor가 추가(?)되었음을 확인할 수 있다.

그런데 코드를 살펴보니, 생성자 내부에서 상위 클래스의 어떤 메소드를 호출한다 (invokespecial). 그리고 그 메소드는 java/lang/Object의 <init>이다.

<init>은 생성자, ()V는 파라미터가 없고 Void를 반환함을 의미한다.

그런데 왜 상위 클래스의 메소드를 호출하는 것일까

생성자는 다음의 규칙에 따라 작동하기 때문이다.

1. 클래스에 생성자를 작성하지 않으면, 자바는 기본생성자를 생성한다.

앞에서 살펴봤다.

2. 모든 생성자는 같은 클래스의 다른 생성자를 호출하거나, 상위 클래스의 생성자를 호출해야 한다.

이는 자바의this(), super()를 의미한다.
this(), super()는 생성자 최상단에 위치해야 한다.

2-1. 만약 this() 또는 super()가 호출되지 않으면 자동으로 super()를 호출한다.

위의 생성자 법칙에 따라 정리하자면,

  1. 어떠한 생성자도 명시하지 않은 클래스를 컴파일하면, 자바 컴파일러가 기본 생성자를 생성한다.
  2. 기본 생성자는 비어있다. -> this 또는 super를 호출하지 않는다.
  3. this 또는 super를 호출하지 않았기 때문에 자동으로 super()를 수행한다.
  4. 따라서, 모든 Class의 최상위 Class인 Object의 생성자가 호출된다.

Constructor vs Method

같은 결과를 내놓는 생성자와 메소드가 있다. 둘의 차이점이 있을까


descriptor를 살펴보면 factory메소드는 (I)클래스인 반면, 생성자는 (I)V이다.
즉, 생성자는 객체를 생성하여 반환하는 주체가 아니다.

자세한 내용은 뒤에서 다루도록 하겠다.

자바의 소멸자

참고: 자바 소멸자 finalize

C, C++은 객체를 위해 할당한 메모리를 명시적으로 반납해야 하고, 소멸 직전에 소멸자가 호출된다.

자바도 Garbage collector를 통해 자동으로 자원을 반납하기 전 수행할 작업을finalize를 통해 정의할 수 있다.

// 최상위 클래스 Object
public class Object {
	
    // 기본 생성자
	public Object() {}

	...중략...
    
    @Deprecated(since="9")
    protected void finalize() throws Throwable { }
}

finalize는 최상위 클래스 Object에 정의되어 있고, 하위 클래스에서 각각 Override하여 사용한다.

그런데 프로그램을 예측할 수 없게 만든다는 치명적 단점 때문에 Java 9부터는 deprecated되었다.
대신 java.lang.ref 패키지의 Cleaner 클래스가 등장했다.

객체 만드는 방법 (new 키워드 이해하기)

참고: new operator in Java

정의한 클래스로 부터 변수를 생성하는 과정은 세 단계로 구분할 수 있다.

1. Declaration

MyClass myObj;

단순히 특정 메모리 주소를 가리키는 변수를 생성한 단계

2. Instantiation and Initialization

new MyClass();

instantiation

  • new 연산자를 통해, 실제 인스턴스를 생성하는 작업
  • 실제 인스턴스를 위한 동적 할당 발생
    (JVM은 C언어로 작성된 프로그램 -> malloc을 통해 동적 할당 실시)
  • 작업 결과로 실제 인스턴스가 저장된 주소를 반환

Initialization

  • 생성한 인스턴스를 생성자를 통해 초기화하는 작업

3. assignment

MyClass myObj = new MyClass();

할당 연산자를 통해 변수에 인스턴스를 할당하는 단계

자바에서 배열은 객체로 취급되므로, new 키워드를 통해 생성한다.

변수와 객체(인스턴스)는 서로 다른 메모리에 할당되므로, 다음의 상황에 주의해야 한다.
사진 출처: https://www.geeksforgeeks.org/new-operator-java/

this 키워드 이해하기

일반적으로 알고 있는 this에 대한 설명은 생략하겠다.
this is a reference variable that refers to the current object.

Class.this

참고: Difference Between Class.this and this in Java

다음과 같이 중첩된 클래스가 있다고 하자

class Outer {
      class Inner {
        public void showOuter() {
            System.out.println ("Outer.this = " + Outer.this);
        }
        
        public void showInner() {
              System.out.println ("this = " + this);
        }
    }
    
    public static void main (String[] args)  {
        Outer outer = new Outer();
        Inner inner = outer.new Inner();
          
        inner.showOuter();
        inner.showInner();     
    }
}

클래스가 중첩된 상황에서, 변수 이름이 같을 경우에도 this를 사용할 수 있다.

profile
블로그 이전했습니다 https://dev314.tistory.com/

0개의 댓글