정적 메소드는 Java로 상속됩니까?


142

Khalid Mughal의 Java ™ SCJP 인증대한 프로그래머 안내서를 읽고있었습니다 .

상속 장에서는 다음과 같이 설명합니다.

회원의 상속은 선언 된 접근성과 밀접한 관련이 있습니다. 서브 클래스에서 단순한 이름으로 슈퍼 클래스 멤버에 액세스 할 수있는 경우 (슈퍼와 같은 추가 구문을 사용하지 않고) 해당 멤버는 상속 된 것으로 간주됩니다.

또한 정적 메소드가 상속되지 않는다고 언급합니다. 그러나 아래 코드는 완벽하게 좋습니다.

class A
{
    public static void display()
    {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A
{
    public void show()
    {
        // This works - accessing display() by its simple name -
        // meaning it is inherited according to the book.
        display();
    }
}

display()수업 시간에 B어떻게 직접 사용할 수 있습니까? 더, B.display()또한 작동합니다.

이 책의 설명은 인스턴스 메소드에만 적용됩니까?


stackoverflow.com/questions/4716040/… 흥미로운 정보가 있습니다.
Mat

제 1 판 제 1 판에서는 그렇지 않습니다. 실제 견적을 제공하십시오.
Lorne의 후작

답변:


179

액세스 가능한 모든 메소드는 서브 클래스에 의해 상속됩니다.

Sun Java 자습서에서 :

서브 클래스는 서브 클래스에있는 패키지에 상관없이 부모의 모든 공용 및 보호 멤버를 상속받습니다. 서브 클래스가 부모와 동일한 패키지에있는 경우 서브 클래스는 또한 부모의 패키지 개인 멤버도 상속합니다. 상속 된 멤버를 그대로 사용하거나 바꾸거나 숨기거나 새 멤버로 보충 할 수 있습니다

상속 된 정적 (클래스) 메소드와 상속 된 비 정적 (인스턴스) 메소드와의 유일한 차이점은 동일한 서명으로 새 정적 메소드를 작성할 때 기존 정적 메소드가 대체되지 않고 숨겨져 있다는 것입니다.

재정의와 숨기기의 차이점에 대한 페이지 에서.

숨기기와 재정의의 차이점은 중요한 의미를 갖습니다. 호출 된 대체 메소드의 버전은 서브 클래스의 버전입니다. 호출되는 숨겨진 메소드의 버전은 수퍼 클래스 또는 서브 클래스에서 호출되는지 여부에 따라 다릅니다.


상속받은 하위 클래스에서 해당 멤버를 재정의 할 수 있는지 여부와 관련이 있습니까?
알고리즘

그것은 상속의 일부이지만 전부는 아닙니다. 상속의 다른 주요 부분은 코드 재사용과 다형성이라고 말합니다.
yincrash 5

재정의에는 재정의와 같은 규칙이 있습니까?
Surender Thakran

2
@Algorithmist는 정확하지 않습니다. 하위 클래스가 계층 구조에서 더 많이 볼 수있는 것은 클래스가 상속 한 것입니다. 그러나 상속 된 정적 메소드는 재정의 할 수 없으며 숨겨 질뿐입니다 (같은 서명으로 "선언"됨). 따라서 정적 메소드를 final로 선언해도 상관 없습니다. 호출 될 정적 메소드는 컴파일시 알려져 있습니다. 최종 인스턴스가 아닌 인스턴스 메서드를 사용하면 재정의 될 수 있으므로 확인을 런타임으로 연기해야합니다.
Martin Andersson

1
마지막 단락이 완전히 손상되었습니다 !!! "호출되는 대체 메소드의 버전이 서브 클래스에있는 버전입니다"이것은 사실이 아닙니다. call :)
mounaim

14

그것이 그 책이 실제로 말하는 것이라면, 그것은 잘못된 것입니다. [1]

Java 언어 사양 # 8.4.8 상태 :

8.4.8 상속, 재정의 및 숨기기

클래스 C는 직접 수퍼 클래스로부터 다음의 모든 것이 참인 수퍼 클래스의 모든 구체적인 메소드 m (정적 및 인스턴스)을 상속합니다.

  • m은 C의 직접 수퍼 클래스의 멤버입니다.

  • m은 C와 동일한 패키지에서 패키지 액세스로 공개, 보호 또는 선언됩니다.

  • C로 선언 된 메소드에는 m의 서명에 대한 하위 서명 (§8.4.2) 인 서명이 없습니다.

[1] 2000 년 제 1 판에는 해당되지 않습니다.


13

다음 코드의 차이를 경험할 수 있으며 이는 코드를 약간 수정 한 것입니다.

class A {
    public static void display() {
        System.out.println("Inside static method of superclass");
    }
}

class B extends A {
    public void show() {
        display();
    }

    public static void display() {
        System.out.println("Inside static method of this class");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        // prints: Inside static method of this class
        b.display();

        A a = new B();
        // prints: Inside static method of superclass
        a.display();
    }
}

이것은 정적 메소드가 클래스 메소드이기 때문입니다.

A.display () 및 B.display ()는 해당 클래스의 메서드를 호출합니다.


1
당신이하려고하는 것처럼 인스턴스에서 정적 메소드를 호출하면 Java에서 작동하지 않습니다.
루카스 C. Feijo

이 프로그램이 설명하는 것은 B의 객체를 인스턴스화하고 상속이 작동하기를 기대하는 정적 멤버에서는 불가능합니다. 이클립스 / 아이디어에서 동일한 코드를 사용하거나 javac를 사용하여 컴파일하여 실행하라
Gaurav

2
@ LucasC.Feijo 실제로 작동합니다. 적어도 내 IDE에서 (일식). 나는 단지 경고를 받는다. 스타일이 좋지 않을 수도 있지만 ... 다른 이야기입니다.
dingalapadum

2
@ LucasC.Feijo는 인스턴스에서 정적 메소드를 호출하지 않는 것이 좋습니다. 그러나 클래스 이름에서 정적 메서드를 호출하는 것과 동일하게 작동합니다.
Ziyang Zhang

5

정적 선언은 메소드 / 멤버가 특정 클래스 인스턴스 (일명 Object)가 아닌 클래스에 속하기 때문에 B.display ()가 작동합니다. 자세한 내용은 여기를 참조 하십시오 .

주목해야 할 또 다른 사항은 정적 메서드를 재정의 할 수 없으며 하위 클래스가 동일한 서명으로 정적 메서드를 선언하도록 할 수 있지만 그 동작은 예상과 다를 수 있습니다. 이것이 아마도 상속 된 것으로 간주되지 않는 이유 일 것입니다. 여기서 문제가되는 시나리오와 설명을 확인할 수 있습니다 .


3

Java의 정적 메소드는 상속되지만 재정의 할 수는 없습니다. 서브 클래스에서 동일한 메소드를 선언하면, 수퍼 클래스 메소드를 대체하지 않고 숨 깁니다. 정적 메소드는 다형성이 아닙니다. 컴파일시 정적 메소드는 정적으로 링크됩니다.

예:

public class Writer {
    public static void write() {
        System.out.println("Writing");
    }
}

public class Author extends Writer {
    public static void write() {
        System.out.println("Writing book");
    }
}

public class Programmer extends Writer {

    public static void write() {
        System.out.println("Writing code");
    }

    public static void main(String[] args) {
        Writer w = new Programmer();
        w.write();

        Writer secondWriter = new Author();
        secondWriter.write();

        Writer thirdWriter = null;
        thirdWriter.write();

        Author firstAuthor = new Author();
        firstAuthor.write();
    }
}

당신은 다음을 얻을 것이다 :

Writing
Writing
Writing
Writing book

2

정적 메소드는 Java로 상속되지만 다형성에는 참여하지 않습니다. 정적 메서드를 재정의하려고 시도하면 슈퍼 클래스 정적 메서드를 재정의하는 대신 숨길 수 있습니다.


이 답변을 내리는 이유는 없습니다. 적어도 첫 부분은 선명하고 깨끗합니다. 두 번째 부분은 너무 기술적으로 받아 들여서는 안되며 그렇지 않으면 괜찮습니다. 명확히하기 위해 메서드를 재정의하면 반환 형식이 하위 형식으로 변경 될 수 있지만 정적 메서드의 경우에는 그렇지 않습니다. 기술적으로 '재시도'는 정적 메소드에는 적용되지 않으므로 말할 수없는 것은 말할 수 없습니다.
sharhp

2

이 개념은보기에는 쉽지 않습니다. 상속없이 정적 멤버에 액세스 할 수 있습니다. 이는 HasA 관계입니다. 부모 클래스도 확장하여 정적 멤버에 액세스 할 수 있습니다. 그렇다고 ISA 관계 (상속)라는 의미는 아닙니다. 실제로 정적 멤버는 클래스에 속하며 static은 액세스 수정자가 아닙니다. 액세스 수정자가 정적 멤버에 대한 액세스를 허용하는 한 다른 클래스에서 사용할 수 있습니다. 공개 된 것처럼 동일한 패키지 내부 및 패키지 외부에서 액세스 할 수 있습니다. 개인을 위해 우리는 그것을 어디서나 사용할 수 없습니다. 기본적으로 패키지 내에서만 사용할 수 있습니다. 그러나 보호를 위해 수퍼 클래스를 확장해야합니다. 따라서 정적 메소드를 다른 클래스로 가져 오는 것은 정적 인 것에 의존하지 않습니다. 액세스 수정 자에 따라 다릅니다. 제 생각에는 액세스 수정자가 허용하면 정적 멤버에 액세스 할 수 있습니다. 그렇지 않으면 Hasa-relation에서 사용하는 것처럼 사용할 수 있습니다. 그리고 관계는 상속이 아닙니다. 다시 정적 메서드를 재정의 할 수 없습니다. 우리가 다른 방법을 사용할 수는 있지만 무시할 수 없다면 HasA- 관계입니다. 우리가 그것들을 무시할 수 없다면 그것은 상속이 아니기 때문에 작가는 100 % 정확했습니다.


부모 클래스를 확장하는 것입니다 에 '입니다-A'의 관계. 액세스가 개인용 인 경우 클래스 내에서 액세스 할 수 있습니다. 'protected'에는 현재 패키지의 파생 클래스와 클래스가 포함됩니다. 여기에 오류가 너무 많습니다.
Lorne의 후작

0

정적 메소드는 서브 클래스에서 상속되지만 다형성이 아닙니다. 정적 메서드의 구현을 작성할 때 부모의 클래스 메서드는 재정의되지 않고 숨겨져 있습니다. 상속되지 않으면 어떻게 액세스하지 않고 액세스 할 수 classname.staticMethodname();있습니까?


0

모든 공용 및 보호 된 멤버는 모든 클래스에서 상속 될 수 있지만 기본 또는 패키지 멤버는 수퍼 클래스와 동일한 패키지 내의 클래스에서 상속 될 수도 있습니다. 정적 멤버인지 또는 비 정적 멤버인지에 의존하지 않습니다.

그러나 정적 멤버 함수가 동적 바인딩에 참여하지 않는 것도 사실입니다. 해당 정적 메서드의 서명이 부모 클래스와 자식 클래스 모두에서 동일하면 다형성이 아닌 그림자 개념이 적용됩니다.


0

정적 메서드를 재정의 할 수 있지만 다형성을 사용하려고하면 클래스 범위에 따라 작동합니다 (일반적으로 예상되는 것과 달리).

public class A {

    public static void display(){
        System.out.println("in static method of A");
    }
}

public class B extends A {

    void show(){
        display();
    }

     public static void display(){
        System.out.println("in static method of B");
    }

}
public class Test {

    public static void main(String[] args){
        B obj =new B();
        obj.show();

        A a_obj=new B();
        a_obj.display();


    }


}

첫 번째 경우, o / p는 "B의 정적 방법에서"# 성공적인 대체입니다. 두 번째 경우, o / p는 "A의 정적 방법에서"입니다. # 정적 방법-다형성을 고려하지 않습니다


-1

서브 클래스에서 동일한 서명으로 정적 메소드를 선언 할 수 있지만 런타임 다형성이 없으므로 재정의되는 것으로 간주되지 않습니다. 클래스의 모든 정적 멤버는 클래스로드시로드되므로 컴파일시 결정합니다. time (런타임에서 재정의) 따라서 정답은 '아니오'입니다.


2
사람들이 왜 항상 투표를하지 않고 투표를하지 않는지 모르겠습니다.
surajs1n

이 답변은 재정의에 관한 것입니다. 문제는 상속에 관한 것입니다.
Lorne의 후작

-1

많은 사람들이 그들의 대답을 한마디로 말하였습니다. 이것은 코드에서 확장 된 설명입니다 :

public class A {
    public static void test() {
        System.out.println("A");
    }
    public static void test2() {
        System.out.println("Test");
    }
}

public class B extends A {
    public static void test() {
        System.out.println("B");
    }
}

// Called statically
A.test();
B.test();
System.out.println();

// Called statically, testing static inheritance
A.test2();
B.test2();
System.out.println();

// Called via instance object
A a = new A();
B b = new B();
a.test();
b.test();
System.out.println();

// Testing inheritance via instance call
a.test2();
b.test2();
System.out.println();

// Testing whether calling static method via instance object is dependent on compile or runtime type
((A) b).hi();
System.out.println();

// Testing whether null instance works
A nullObj = null;
nullObj.hi();

결과 :

A
B

Test
Test

A
B

Test
Test

A

A

따라서 이것이 결론입니다.

  1. .를 통해 정적 방식으로 정적을 호출하면 해당 클래스에 정의 된 정적 또는 상속 체인에서 가장 가까운 클래스를 찾습니다. 이것은 정적 메소드가 상속됨을 증명합니다.
  2. 인스턴스에서 정적 메소드를 호출하면 컴파일 타임 유형에 정의 된 정적 메소드를 호출합니다.
  3. 정적 메소드는 null인스턴스 에서 호출 할 수 있습니다 . 컴파일러는 변수 유형을 사용하여 컴파일하는 동안 클래스를 찾고 적절한 정적 메소드 호출로 변환합니다.

1
단순한 코드는 설명이 아니라 데모입니다. 이 질문에 대한 대답은 규명되지 않은 구현의 행동을 나타내는 것이 아니라 규범 적 참조를 인용해야합니다.
Lorne의 후작

-2

정적 멤버는 범용 멤버입니다. 어디서나 액세스 할 수 있습니다.


4
문자 그대로 가져온 에서 액세스 할 수 있습니다 . 정적! = 범위입니다. :-)
kleopatra

실제로,이 답변은 문자 그대로 볼 때 좋습니다. 코드에서 정적 클래스 멤버에 액세스 할 수없는 코드의 단일 위치를 생각할 수 없습니다. 정적 이니셜 라이저, 정적 생성자, 인스턴스 생성자, 메서드, 속성, 다른 클래스의 범위에서 액세스 할 수 있습니다. 클래스와 정적 메소드가 공용 인 한 정적 초기화 프로그램에 순환 종속성이 없다고 가정하면 어디서나 액세스 할 수 있습니다. 본질적으로 정적 멤버는 상속되지 않으며 어디에서나 액세스 할 수있는 클래스 수준 (즉, 범용) 메서드입니다.
Triynko

@Triynko 비공개 또는 패키지 외부에서 패키지로 보호 된 메소드의 경우에는 정답이 아닙니다.
Lorne의 후작

@kleopatra-주제를 벗어났습니다. 자바 스윙? 사람들은 실제로 요즘 그것을 사용합니까?
MasterJoe2

@Pavan은 클래스 외부에서 개인 정적 호출을 시도하십시오. 작동하지 않습니다.
Rakesh Yadav

-2

상속은 비 정적 멤버 전용이므로 정적 멤버는 하위 클래스로 상속되지 않습니다. 정적 멤버는 클래스 로더에 의해 정적 풀 내부에로드됩니다. 상속은 객체 내부에로드 된 멤버에 대해서만


완전히 틀렸다. JLS # 8.4.8 참조 .
Lorne의 후작
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.