[java] 최종 정적 메서드의 동작

나는 정적 방법으로 수정자를 가지고 놀았고 이상한 행동을 발견했습니다.

아시다시피, 정적 메서드는 인스턴스가 아닌 클래스와 연결되어 있으므로 재정의 할 수 없습니다.

그래서 아래 스 니펫이 있으면 잘 컴파일됩니다.

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

그러나 클래스 A의 정적 메서드에 대한 최종 수정자를 포함하면 컴파일이 실패합니다
. B의 ts ()는 A의 ts ()를 재정의 할 수 없습니다. 재정의 된 메서드는 static final 입니다.

정적 메서드를 전혀 재정의 할 수 없는데 왜 이런 일이 발생합니까?



답변

정적 메서드는 재정의 할 수 없지만 숨길 수 있습니다. ts()B 의 방법은 A의 a를 재정의하지 않지만 (다형성의 영향을받지 않음) ts()숨길 것입니다. ts()B (NOT A.ts()또는 B.ts()… just ts()) 를 호출하면 A가 아닌 B 중 하나가 호출됩니다. 이것은 다형성의 영향을받지 않으므로 A의 호출 ts()은 B 의 호출 로 리디렉션되지 않습니다.

키워드 final는 메서드가 숨겨지지 않도록합니다. 따라서 숨길 수 없으며 그렇게하면 컴파일러 오류가 발생합니다.

도움이 되었기를 바랍니다.


답변

정적 메서드는 재정의 할 수 없습니다.

이것은 정확히 사실이 아닙니다. 예제 코드는 실제로 B의 ts 메서드가 A의 ts 메서드를 숨긴다는 것을 의미합니다. 따라서 정확히 재정의하지는 않습니다. 에 걸쳐 Javaranch 멋진 설명이있다.


답변

정적 메서드는 인스턴스가 아닌 클래스에 속합니다.

A.ts()그리고 B.ts()항상 별도의 방법이 될 것입니다.

진짜 문제는 Java가 인스턴스 객체에 대한 정적 메서드를 호출 할 수 있다는 것입니다. 상위 클래스의 동일한 서명을 가진 정적 메서드는 하위 클래스 의 인스턴스에서 호출 될 때 숨겨집니다 . 그러나 최종 메서드를 재정의 / 숨길 수는 없습니다 .

오류 메시지가 재정의 대신 숨겨진 단어를 사용한다고 생각할 것입니다.


답변

다음을 고려하여 정적 메서드를 최종적으로 만드는 것에 대해 생각할 수있는 위치에있을 수 있습니다.

다음과 같은 수업이 있습니다.

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

이제 이러한 메서드를 호출하는 ‘올바른’방법은 다음과 같습니다.

A.ts();
B.ts();

결과적으로 발생 AB하지만 인스턴스에서 메서드를 호출 할 수도 있습니다.

A a = new A();
a.ts();
B b = new B();
b.ts();

그 결과 AB도 마찬가지입니다.

이제 다음을 고려하십시오.

A a = new B();
a.ts();

인쇄 A됩니다. 실제로 클래스의 객체를 가지고 있기 때문에 놀랄 수도 있습니다 B. 이 유형의 참조에서 호출하고 있기 때문에 그러나 A, 그것은 호출합니다 A.ts(). B다음 코드로 인쇄 할 수 있습니다 .

A a = new B();
((B)a).ts();

두 경우 모두 당신이 가진 객체는 실제로 class에서 가져온 것 B입니다. 그러나 객체를 가리키는 포인터에 따라에서 A또는에서 메서드를 호출 B합니다.

이제 당신이 클래스의 개발자이고 A서브 클래스를 허용하고 싶다고 가정 해 봅시다 . 그러나 당신은 정말로 method를 원한다 ts(). 심지어 서브 클래스에서 호출 될 때조차, 그것이 당신이 원하는 일을하고 서브 클래스 버전에 의해 숨겨지지 않도록하는 것이다. 그런 다음 그것을 만들고 final하위 클래스에서 숨겨지지 않도록 할 수 있습니다 . 그리고 다음 코드가 클래스에서 메서드를 호출 할 것임을 확신 할 수 있습니다 A.

B b = new B();
b.ts();

좋아, 그것은 어떻게 든 구성되었지만 어떤 경우에는 의미가있을 수 있습니다.

인스턴스에서 정적 메서드를 호출하지 말고 클래스에서 직접 호출하면 문제가 발생하지 않습니다. 또한 예를 들어 IntelliJ IDEA는 인스턴스에서 정적 메서드를 호출하고 정적 메서드를 최종적으로 만들면 경고를 표시합니다.


답변

B의 ts () 메서드는 A의 ts () 메서드를 재정의하는 것이 아니라 단순히 다른 메서드입니다. B 클래스는 A에서 ts () 메서드가 정적이기 때문에 보이지 않으므로 ts ()라는 자체 메서드를 선언 할 수 있습니다.

그러나 메서드가 final이면 컴파일러는 B에서 재정의해서는 안되는 ts () 메서드가 A에 있음을 인식합니다.


답변

여기에서 컴파일 오류가 오해의 소지가 있다고 생각합니다. “overridden method is static final.”이라고 말해서는 안되지만 대신 “overridden method is final”이라고 말해야합니다. 여기서 정적 수정자는 관련이 없습니다.


답변

정적 메서드는 비 정적 메서드와 달리 Java에서 재정의 할 수 없습니다. 그러나 이들은 정적 및 비 정적 데이터 멤버처럼 상속됩니다. 그렇기 때문에 동일한 이름의 비 정적 메서드를 부모 클래스에서 만들 수 없습니다.

class Writer {
    public static void doo(){
        System.out.println("sth");
    }
}
class Author extends Writer{
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

final특정 방법 몸이 매번에게 메서드 호출을 실행하는 것이 키워드 보장합니다. 이제 동일한 이름의 자식 클래스에 정적 메서드가 생성되고 메서드에 대한 호출이 이루어지면 하위 클래스의 메서드가 실행됩니다. 이는 부모 클래스의 정적 메서드 이름 앞에 final이 접두사로 붙는 경우에는 해당되지 않아야합니다. . 따라서 final 키워드는 자식 클래스에서 동일한 이름의 메서드 생성을 제한합니다.