최종 정적 메서드의 동작


123

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

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

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

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

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

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

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


2
이상하게 보이지만 질문에 +1하지만 지금까지 만족스러운 답변은 없습니다.
Rakesh Juyal

1
재정의되지 않습니다. 여전히 A.ts ()에 있습니다.
Alex Feinman

답변:


166

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

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

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


30
대답을 마치려면, 여기에있는 문제는 기본적으로 잘못된 컴파일러 오류 메시지입니다. B가 A에서 ts ()를 숨길 수 없다는 메시지가 표시되어야 합니다. static 메서드 final을 선언하는 것은 숨길 수 없음을 선언하는 것입니다.
Sean Owen

2
@Sean Owen : 저도 그렇게 생각합니다. '숨기기'라는 용어는 Java 사양에서도 사용되므로 컴파일러 메시지에서 사용하지 마십시오.
NawaMan

2
이것이 왜 기능일까요? 어떤 맥락에서 유용할까요?
user253751

public class Test {최종 정적 public void main (String ... srik) {System.out.println ( "In main method"); ts (); } public static void ts () {Child c = new Child (); c.ts (); System.out.println ( "테스트 ts"); }} public class Child extends Test {public static void ts () {System.out.println ( "Child ts"); }}
안녕하세요이

@SeanOwen 나는 이것이 옳다고 생각하지 않는다. 컴파일러는 A#ts상속되고 있고 그러한 메소드가 이미 존재하기 B때문에 단순히 동일한 서명을 가진 두 개의 메소드와 다른 수정 자 ( final)가 오버로드로 작동하지 않을 것이라고 말해야한다 . . 그래도, 내가 이것에 대한 간단한 메시지 생각할 수 있으면 좋겠다
유진

13

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

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


4
정확하지 않은 사실입니다. 정적 메서드는 재정의 할 수 없지만 클래스 이름이 아닌 인스턴스 참조에서 호출하는 경우 숨길 수 있습니다.
John Mercier

1
안타깝게도 링크가 더 이상 작동하지 않습니다. 이 문제를 해결할 수 있습니까?
Mathias Bader 2017 년

javaranch 링크가 작동하지 않지만 검색 키워드가 코드 목장 에서이 링크 를 찾았습니다
Sundeep

죽은 링크를 Sundeep에서 게시 한 링크로 대체하여 게시물을 편집했습니다.
MC Emperor

10

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

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

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

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


6

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

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

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는 인스턴스에서 정적 메서드를 호출하고 정적 메서드를 최종적으로 만들면 경고를 표시합니다.


0

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

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


나는 이것이 '최종'이 갑자기 이러한 방법이 공존 할 수 없다는 것을 의미하는 이유를 설명하지 않는다고 생각합니다. 말했듯이 '최종'없이는 문제가 없습니다. 재정의가 아니라고 말하지만 문제는 B가 A의 방법을 재정의 할 수 없다는 것입니다.
Sean Owen

물론 B는 A에서 ts () 메서드를 보지 못하지만 ( '숨겨 짐') 최종 수정자는 다른 클래스를 확장하는 클래스에서 메서드를 '숨기지'않습니다. 하지만 어, 알았어.
amischiefr

0

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


1
그래서 당신은 A의 것을 재정의하는 B의 정적 방법을 고려합니까?
Koray Tugay

@KorayTugay 컴파일러가 잠재적으로 재정의 가능한 메서드 (잠시 정적 무시)를 먼저보고 실패시 최종 결과를 보는지 궁금 합니다. 그냥 추측하지만
유진

Balus 저는 이것이 StackOverflow에서 유일하게 낮은 품질의 답변이라고 생각합니다. 모든 예외적 인 답변을 고려할 때 이것은 그들에게 속하지 않습니다. @BalusC
Koray Tugay

@KorayTugay : 그 당시에는 댓글을 달 수있는 평판이 충분하지 않았습니다. :) 다시 핑하면 답을 삭제하겠습니다. 문제 없습니다.
BalusC

0

정적 메서드는 비 정적 메서드와 달리 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 키워드는 자식 클래스에서 동일한 이름의 메서드 생성을 제한합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.