그저 내가 되었고

☕️Java:: 자바 코드 기본적 분석 & final 키워드 본문

개발/Java

☕️Java:: 자바 코드 기본적 분석 & final 키워드

hyuunii 2023. 6. 1. 21:16

  • 접근 제어자 (Access Modifier)
    = 클래스, 변수, 메서드의 접근 권한 정의 키워드.
    public: 모든 접근 허용
    protected: 같은 패키지(폴더) 내 객체와 상속 관계의 객체들만 허용
    default: 같은 패키지(폴더) 내 객체들만 허용
    private: 같은 클래스 내에서만 허용
    일반적으로 많이 쓰이는 건 public, private이다.
  • 클래스 (Class)
    = 객체를 찍어낼 수 있는 틀.
  • 메서드 (Method)
    = 클래스 내부에 정의된 함수.
    = 특정 작업을 하기 위한 명령문의 집합.
    자바가 실행되면 main() 메서드를 제일 먼저 찾아 그 안의 것들을 순차적으로 실행하기 때문에 다른 메서드를 만들고 싶다면 main() 메서드 안에서 호출해야 한다.
  • Static
    변수나 메서드가 객체의 것이 아니라, 클래스 내용물이라는 것을 지정하는 키워드.
  • return, void
    자바 메서드는 리턴할 값을 타입을 명시해줘야 한다.
    return = 메서드가 작업 마치고 데이터를 반환하는 것.
    void = 데이터를 리턴하지 않을 경우, 특정 타입을 리턴할 경우 따로 명시.

 

 

* final

변수(variable), 메서드(method), 또는 클래스(class)에 사용될 수 있다.

이 키워드는 어떤 곳에 사용되냐에 따라 다른 의미를 가지지만, final 키워드를 붙이면 무언가를 제한한다는 의미를 가지는 것이 공통 성격이다.

이 Final 키워드가 사용되는 4가지 경우를 정리해보자면 다음과 같다.

 

1. final 변수

다음과 같이 변수를 선언할 때 클래스 앞에 final 키워드

final String hello = "Hello world";

final 키워드가 붙은 변수는 초기화 후 변경할 수 없다. 다음과 같이 변경하려고 하면 컴파일 에러가 발생한다.

final String hello = "Hello world";

hello = "See you around" // compile error!

 

 

2. final arguments (인자) 

final로 선언된 인자는 메소드 내에서 변경이 불가능하다. 따라서 다음과 같이 final int로 선언한 number는 읽을 수 있지만, number = 2처럼 값을 변경하려고 하면 컴파일 에러가 발생한다.

public void func(final int number) {
    System.out.println(number);

    // number = 2;  compile error!
}

 

3. final 클래스

final class MJ {
    final String hello;
    MJ() {
        hello = "hello world";
    }
}

클래스에 final을 붙이면 다른 클래스가 상속할 수 없는 클래스가 된다. 다음과 같이 final 클래스를 상속하려고 하면 컴파일 에러 발생.

final class MJ {
    final String hello;
    MJ() {
        hello = "hello world";
    }
}

class MMJ extends MJ() { // compile error!
}

 

4. final 메소드

class MJ {
    final String hello = "hello world";

    final String getHello() {
        return hello;
    }
}

final 메소드는 Override가 안되도록 한다. 예를 들어 다음과 같이 MJ 클래스를 상속하는 MMJ 클래스에서는 getHello()를 재정의할 수 없다. Override하려고 하면 컴파일 에러가 발생한다.

class MJ extends MMJ {

    @Override
    String getHello() { // compile error !
        return "See you MJ";
    }
}

 

정리

- final variables, arguments : 값이 변경되지 않도록 만듬

- final class : 클래스를 상속하지 못하도록 만듬

- final method : 메소드가 오버라이드되지 못하도록 만듬

 

주의할 점

final 변수는 초기화 이후 값 변경이 발생하지 않도록 만든다.

final List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");

다음과 같이 List에 final을 선언하여 list 변수의 변경은 불가능하다.

하지만 list 내부에 있는 변수들은 변경이 가능하여 문자열을 계속 추가할 수 있다.

 

 

+ Effective final keyword

Effective final은 Java8에서 추가된 기능으로, final이 붙지 않은 변수의 값이 변경되지 않는다면 그 변수를 Effectively final이라고 한다. final을 붙이지 않았지만 컴파일러가 final로 취급하는 것이다.

int num = 1;

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("number: " + num);
    }
};
runnable.run();

위 코드에서 변수 num은 Effectively final이다.

num은 선언과 동시에 1으로 할당되었고, 객체가 소멸될 때까지 값이 변경되지 않았기 때문이다.

 

Effective final이 없었던 Java8 이전에는 컴파일 에러가 발생하는 코드였다.

run()안에서 변경이 가능한 num 변수에 접근하기 때문이다. 하지만 Java8은 num 변수가 내부에서 변경되지 않기 때문에 final로 취급하여 컴파일 에러가 발생하지 않는다.

 

 

 

참고::
1. https://sabarada.tistory.com/148
2. https://sudo-minz.tistory.com/135