자바`최종`방법 : 그것은 무엇을 약속합니까?


141

Java 클래스 final에서이 메소드를 대체 할 수 없음을 표시 하기 위해 메소드를로 정의 할 수 있습니다 .

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

분명합니다. 우연한 재정의 또는 성능 저하로부터 보호하는 데 유용 할 수 있습니다. 그러나 그것은 제 질문이 아닙니다.

내 질문은 : OOP 관점 final에서 클래스 디자이너 가 메소드를 정의 함으로써이 메소드가 항상 설명 된대로 또는 암시 적으로 작동 할 것이라고 약속 했습니다. 그러나 종종 방법이 수행하는 것이 더 복잡하고 속성을 제공하는 것보다 복잡한 경우 클래스 작성자의 영향을받지 않을 수 있습니다 .

구문상의 제약은 나에게 분명하지만 OOP의 의미는 무엇입니까? 되어 final대부분의 클래스 저자에 의해 이러한 의미에서 올바르게 사용?

방법은 어떤 종류의 "계약"을 final약속합니까?

답변:


156

언급했듯이 finalJava 메소드와 함께 사용하여 메소드를 대체 (객체 범위)하거나 숨길 수 없음 (정적)을 표시합니다. 이를 통해 원래 개발자는 서브 클래스로 변경할 수없는 기능을 작성할 수 있으며 이것이 제공하는 모든 보증입니다.

즉,이 방법이 비공개 필드 / 방법과 같은 다른 사용자 정의 가능한 구성 요소에 의존하는 경우 최종 방법의 기능은 여전히 ​​사용자 정의 할 수 있습니다. 이것은 (다형성과 함께) 부분적인 커스터마이징이 가능하지만 좋습니다.

다음을 포함하여 무언가를 사용자 정의 할 수 없게하는 데는 여러 가지 이유가 있습니다.

  • 성능 -일부 컴파일러는 작업, 특히 부작용이없는 작업을 분석하고 최적화 할 수 있습니다.

  • 캡슐화 된 데이터 확보 -생성시 속성이 설정되어 절대로 변경해서는 안되는 불변 개체를 살펴보십시오. 또는 해당 속성에서 파생 된 계산 된 값입니다. 좋은 예는 Java String클래스입니다.

  • 신뢰성 및 계약은 - 객체는 프리미티브 (구성된다 int, char, double, 등) 및 / 또는 기타 객체. 이러한 구성 요소에 적용 가능한 모든 작업이 더 큰 개체에서 사용될 때 적용 가능하거나 논리적이어야하는 것은 아닙니다. final수정자를 사용한 메소드를 사용하여이를 확인할 수 있습니다. 카운터 클래스가 좋은 예입니다.


public class Counter {
    private int counter = 0;

    public final int count() {
        return counter++;
    }

    public final int reset() {
        return (counter = 0);
    }
}

public final int count()메소드가 아닌 경우 final다음과 같이 할 수 있습니다.

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2

또는 이와 같은 것 :

Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count

27

최종 방법은 어떤 종류의 "계약"을 약속합니까?

다른 방법으로 보아라. 최종이 아닌 메소드는 자신의 구현으로 재정의 할 수 있으며 클래스가 여전히 예상대로 작동 한다는 것을 암시 적으로 보장 합니다. 클래스가 메소드 덮어 쓰기를 지원한다고 보장 할 수없는 경우 최종 메소드로 만들어야합니다.


그러나이 견해는 "최종 방법이 항상 약속 된대로 행동 할 것"이라는 내 원래의 질문에 최종 방법 내에서 비 ​​최종 방법을 호출해서는 안된다는 것을 암시하지 않습니까? 호출 된 메소드를 재정의하면 최종 메소드의 동작을 보장 할 수 없기 때문에?
towi

8

우선, 비추 상 클래스 final와 필드 및 메소드를 표시 할 수 있습니다 . 이런 식으로 전체 클래스를 서브 클래 싱 할 수 없습니다. 따라서 수업의 행동이 고정됩니다.

final최종 메소드가 비 최종 메소드를 호출하는 경우 표시 메소드가 서브 클래스에서 동일한 동작을 보장하지는 않는다는 데 동의합니다 . 행동이 실제로 고쳐 져야한다면, 이것은 관습과 신중한 디자인에 의해 달성되어야합니다. 그리고 이것을 javadoc에서 이것을 잊지 마십시오! (Java documentation)

마지막으로 final키워드는 JMM (Java Memory Model)에서 매우 중요한 역할을합니다. JMM은 final필드의 가시성을 달성하기 위해 적절한 동기화가 필요하지 않음 을 보장 합니다. 예 :

class A implements Runnable {
  final String caption = "Some caption";                           

  void run() {
    // no need to synchronize here to see proper value of final field..
    System.out.println(caption);
  }
}  

예, 마지막 수업에 대해 알고 있습니다. 쉬운 경우입니다. JMM이있는 최종 필드에 대한 좋은 지적, 동기화가 필요하지 않습니다 ... 흠 : 이것은 "포인터"만 나타냅니다. 여전히 참조하는 객체를 동기화 할 수 없었습니다 (ok, in String이 아니라 사용자 정의 클래스). 하지만 "최종 행동이 보장되지는 않는다"고 말한 것이 바로 내 요점입니다. 문서와 디자인이 중요하다는 데 동의합니다.
towi

@towi 당신 final과 같은 복합 객체에 대한 변경 사항의 가시성을 보장하지 않습니다 Map.
Victor Sorokin

0

"최종"의 사용과 이것이 소프트웨어의 전체 설계 계약에 미치는 영향에 대해 어떤 주장을 할 수 있는지 잘 모르겠습니다. 개발자는이 방법을 무시하고 계약을 무효화 할 수 없습니다. 그러나 다른 한편으로, final 메소드는 서브 클래스에 의해 값이 설정되는 클래스 또는 인스턴스 변수에 의존 할 수 있으며 재정의 된 다른 클래스 메소드를 호출 할 수 있습니다 . 따라서 final은 기껏해야 매우 약한 보증입니다.


1
그렇습니다. 권리. 나는 "약한 보증"이라는 용어를 좋아한다 const. 에서 char const * const = "Hello"또는 char const * const addName(char const * const name) const...
towi

0

아니요, 수업 저자의 영향을받지 않습니다. 파생 클래스에서는 재정의 할 수 없으므로 기본 클래스 작성자가 의도 한대로 수행됩니다.

http://download.oracle.com/javase/tutorial/java/IandI/final.html

주목할만한 점은 생성자에서 호출 된 메소드가 있어야 함을 제안하는 부분 final입니다.


1
기술적으로 기본 클래스 작성자가 작성한 것을 수행 합니다.
Joey
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.