IT이야기

정적 메서드는 Java에서 상속되는가?

cyworld 2022. 5. 11. 22:05
반응형

정적 메서드는 Java에서 상속되는가?

는 Khalid Mughal의 Java™ SCJP 인증 프로그래머 가이드를 읽고 있었다.

상속 장에서는 다음과 같이 설명하고 있다.

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

정적 방법이 유전되지 않는다는 점도 언급한다.하지만 아래 코드는 완벽히 괜찮다.

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()또한 효과가 있다.

이 책의 설명은 예시법에만 적용되는가?

접근 가능한 모든 방법은 하위 클래스에 의해 계승된다.

Sun Java 자습서:

하위 클래스는 하위 클래스가 어떤 패키지에 포함되어 있든 관계없이 모든 공용 구성원과 보호되는 부모 구성원을 상속한다.하위 클래스가 상위 클래스와 동일한 패키지에 있으면 상위 패키지의 개인 멤버도 상속한다.상속된 멤버를 그대로 사용하거나, 교체하거나, 숨기거나, 새 멤버로 보충할 수 있다.

유전된 정적(클래스) 방법과 유전된 비정적(인스턴스) 방법과의 유일한 차이점은 동일한 서명으로 새로운 정적 방법을 쓸 때 기존의 정적 방법은 덮어쓰지 않고 그냥 숨겨져 있다는 것이다.

재정의와 숨김의 차이에 대한 페이지부터.

숨는 것과 덮어쓰는 것의 구별은 중요한 의미를 갖는다.호출되는 재정의된 메서드의 버전은 하위 클래스에 있는 메서드 버전이다.호출되는 숨겨진 메서드의 버전은 수퍼클래스에서 호출되는지 서브클래스에서 호출되는지 여부에 따라 달라진다.

당신은 당신의 코드에 비해 약간 수정된 다음의 코드의 차이를 경험할 수 있다.

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]

자바 언어 규격 #8.4.8에는 다음과 같이 명시되어 있다.

8.4.8 상속, 재정의 및 숨기기

등급 C는 다음의 모든 것이 참인 슈퍼클래스의 직접 수퍼클래스로부터 모든 콘크리트 방법 m(정적 및 인스턴스 모두)을 이어받는다.

  • m은 C의 직접 슈퍼클래스의 일원이다.

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

  • C에서 선언된 어떤 방법에도 m의 서명의 하위 서명(제8.4.2조)인 서명이 없다.

[1] 제 1판 2000에는 그렇게 나와 있지 않다.

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

B.display()는 정적 선언이 메서드/구성원을 특정 클래스 인스턴스(일명 객체)가 아닌 클래스에 속하게 만들기 때문에 작동한다.여기에서는 그것에 대해 더 많이 읽을 수 있다.

또 다른 주목할 점은 정적 방법을 재정의할 수 없다는 것이다. 동일한 서명으로 정적 방법을 선언하도록 하위 클래스로 지정할 수 있지만 해당 동작이 예상과 다를 수 있다.이것이 아마도 그것이 유전된다고 여겨지지 않는 이유일 것이다.여기서 문제가 있는 시나리오와 설명을 확인할 수 있다.

정적 방법은 자바에서 계승되지만 다형성에는 참여하지 않는다.만약 우리가 정적 방법을 무시하려고 한다면 그들은 초급 정적 방법을 무시하는 대신에 숨길 것이다.

이 개념은 보기만큼 쉽지 않다.우리는 상속 없이 정적 멤버에 접근할 수 있는데, 그것이 HasA-relation이다.우리는 또한 부모 클래스를 확장함으로써 정적 멤버에 접근할 수 있다.그것은 그것이 ISA 관계라는 것을 의미하지 않는다.실제로 정적 멤버는 클래스에 속하며, 정적 멤버는 액세스 수식어가 아니다.접근 수식어가 정적 멤버에 접근하는 것을 허용하는 한 우리는 그것들을 다른 클래스에서 사용할 수 있다.만약 그것이 공개된다면, 그것은 같은 패키지 안에서 그리고 또한 패키지 밖에서 접근할 수 있을 것이다.개인용으로는 어디에서도 사용할 수 없다.디폴트인 경우 패키지 내에서만 사용할 수 있다.하지만 보호를 위해서는 슈퍼 클래스를 확장해야 한다.따라서 정적 방법을 다른 클래스로 가져오는 것은 정적 방법에 의존하지 않는다.접근 수식어에 따라 달라진다.그래서 내 생각에는 정적 멤버들은 접근 수식어가 허용하면 접근할 수 있다.그렇지 않으면 하사릴레이가 사용하는 것처럼 사용할 수 있다.그리고 관계가 있는 것은 유산이 아니다.다시 한번 우리는 정적 방법을 무시할 수 없다.만약 우리가 다른 방법을 사용할 수 있지만 그것을 무시할 수 없다면, 그것은 HasA-relation이다.우리가 그들을 무시할 수 없다면 그것은 유산이 아닐 것이다.그래서 작가는 100% 정확했다.

클래스의 정적 메서드는 상속되는 반면 인터페이스의 정적 메서드는 상속되지 않는다.

클래스의 정적 메서드는 인스턴스를 사용하여 호출할 수 있지만 인터페이스의 정적 메서드는 상속되지 않으므로 인터페이스 이름을 통해서만 호출할 수 있음

정적 방법은 하위계급에서 계승되지만 다형성은 아니다.정적 방법의 구현을 작성할 때 부모의 클래스 방법은 오버라이드가 아니라 오버라이드된다.만약 그것이 유전되지 않는다면, 어떻게 당신이 없이도 접근할 수 있는지 생각해라.classname.staticMethodname();?

모든 공용 및 보호 멤버는 어느 클래스에서나 상속할 수 있으며, 기본 멤버나 패키지 멤버도 슈퍼 클래스와 동일한 패키지 내에서 클래스에서 상속할 수 있다.정적 부재인지 비 정적 부재인지에 따라 달라지지 않는다.

그러나 정적 멤버 기능이 동적 바인딩에 참여하지 않는 것도 사실이다.만약 그 정적 방법의 서명이 부모 계층과 자식 계층 모두에서 동일하다면, 다형성이 아닌 섀도우잉의 개념이 적용된다.

정적 방법을 무시할 수는 있지만 다형성을 사용하려고 하면 클래스 범위(평소 우리가 기대하는 것과 대조적)에 따라 작동한다.

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의 정적 방법" # 정적 방법 - 다형성을 고려하지 않는다.

우리는 서브클래스에서 동일한 서명으로 정적 방법을 선언할 수 있지만 런타임 다형성은 없을 것이기 때문에 오버라이드하는 것으로 간주되지 않는다.클래스의 모든 정적 멤버는 클래스 로드 시 로드되므로 컴파일 시간에 결정(런타임에 오버라이드)그러므로 대답은 '아니오'이다.

많은 사람들이 그들의 대답을 말로 표현했다.이것은 코드에서 확장된 설명이다.

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. 정적 방법은 a에서 호출할 수 있다.null인스턴스내 추측으로는 컴파일러는 컴파일러가 가변 유형을 사용하여 컴파일을 하는 동안 클래스를 찾아 적절한 정적 메서드 호출로 변환할 것이다.

정적 멤버는 보편적인 멤버다.어디서든 접근할 수 있다.

정적 멤버는 비정적 멤버에 대해서만 상속되기 때문에 하위 클래스로 상속되지 않는다.그리고 정적 멤버는 클래스 로더에 의해 정적 풀 안에 적재될 것이다.상속은 개체 내부에 로드된 멤버에만 해당됨

참조URL: https://stackoverflow.com/questions/10291949/are-static-methods-inherited-in-java

반응형