[java] 자바 : 재정의 된 메서드를 호출하는 슈퍼 메서드 호출

public class SuperClass
{
    public void method1()
    {
        System.out.println("superclass method1");
        this.method2();
    }

    public void method2()
    {
        System.out.println("superclass method2");
    }

}

public class SubClass extends SuperClass
{
    @Override
    public void method1()
    {
        System.out.println("subclass method1");
        super.method1();
    }

    @Override
    public void method2()
    {
        System.out.println("subclass method2");
    }
}



public class Demo 
{
    public static void main(String[] args) 
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1();
    }
}

내 예상 출력 :

서브 클래스 method1
수퍼 클래스 method1
수퍼 클래스 method2

실제 출력 :

서브 클래스 method1
수퍼 클래스 method1
서브 클래스 method2

기술적으로는 내가 공개 메서드를 재정의 한 것을 알고 있지만, 수퍼를 호출했기 때문에 수퍼 내의 모든 호출이 수퍼에 남아있을 것이라고 생각했습니다. 어떻게 할 수 있는지에 대한 아이디어가 있습니까?



답변

키워드 super는 “고정”되지 않습니다. 모든 메서드 호출은 개별적으로 처리되므로 SuperClass.method1()를 호출 super하여 수행하더라도 향후 수행 할 수있는 다른 메서드 호출에는 영향을 미치지 않습니다.

그 말은 호출하는 직접적인 방법이 없습니다 SuperClass.method2()에서 SuperClass.method1()비록 거치지 않고 SubClass.method2()당신의 실제 인스턴스와 작업을하지 않는 한 SuperClass.

Reflection을 사용하여 원하는 효과를 얻을 수도 없습니다 ( 문서java.lang.reflect.Method.invoke(Object, Object...) 참조 ).

[편집] 아직도 약간의 혼란이있는 것 같습니다. 다른 설명을 해보겠습니다.

호출 할 때 foo()실제로 호출 this.foo()합니다. Java는 단순히 this. 질문의 예에서 유형은 this입니다 SubClass.

따라서 Java가에서 코드를 실행하면 SuperClass.method1()결국this.method2();

를 사용 super해도에서 가리키는 인스턴스는 변경되지 않습니다 this. 그래서 호출로 이동 SubClass.method2()하기 때문에 this유형입니다 SubClass.

Java가 this숨겨진 첫 번째 매개 변수로 전달된다고 생각하면 이해하기 더 쉬울 것입니다 .

public class SuperClass
{
    public void method1(SuperClass this)
    {
        System.out.println("superclass method1");
        this.method2(this); // <--- this == mSubClass
    }

    public void method2(SuperClass this)
    {
        System.out.println("superclass method2");
    }

}

public class SubClass extends SuperClass
{
    @Override
    public void method1(SubClass this)
    {
        System.out.println("subclass method1");
        super.method1(this);
    }

    @Override
    public void method2(SubClass this)
    {
        System.out.println("subclass method2");
    }
}



public class Demo 
{
    public static void main(String[] args) 
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1(mSubClass);
    }
}

호출 스택을 따라 가면 this절대 변경되지 않으며 항상 .NET에서 생성 된 인스턴스 임을 알 수 있습니다 main().


답변

재정의 메서드 (또는 재정의 클래스의 다른 메서드)에서만 재정의 된 메서드에 액세스 할 수 있습니다.

따라서 재정의 method2()하거나 super.method2()재정의 된 버전 내에서 호출 하지 마십시오 .


답변

this실제로 “사용중인 객체의 현재 실행중인 인스턴스”를 참조 하는 키워드를 사용하고 있습니다. 즉, this.method2();수퍼 클래스 를 호출 하고 있습니다. 즉, 객체에서 method2 ()를 호출합니다. re using, 이는 SubClass입니다.


답변

이렇게 생각해

+----------------+
|     super      |
+----------------+ <-----------------+
| +------------+ |                   |
| |    this    | | <-+               |
| +------------+ |   |               |
| | @method1() | |   |               |
| | @method2() | |   |               |
| +------------+ |   |               |
|    method4()   |   |               |
|    method5()   |   |               |
+----------------+   |               |
    We instantiate that class, not that one!

하위 클래스를 약간 왼쪽으로 이동하여 그 아래에 무엇이 있는지 보여 드리겠습니다 … (저는 ASCII 그래픽을 좋아합니다)

We are here
        |
       /  +----------------+
      |   |     super      |
      v   +----------------+
+------------+             |
|    this    |             |
+------------+             |
| @method1() | method1()   |
| @method2() | method2()   |
+------------+ method3()   |
          |    method4()   |
          |    method5()   |
          +----------------+

Then we call the method
over here...
      |               +----------------+
 _____/               |     super      |
/                     +----------------+
|   +------------+    |    bar()       |
|   |    this    |    |    foo()       |
|   +------------+    |    method0()   |
+-> | @method1() |--->|    method1()   | <------------------------------+
    | @method2() | ^  |    method2()   |                                |
    +------------+ |  |    method3()   |                                |
                   |  |    method4()   |                                |
                   |  |    method5()   |                                |
                   |  +----------------+                                |
                   \______________________________________              |
                                                          \             |
                                                          |             |
...which calls super, thus calling the super's method1() here, so that that
method (the overidden one) is executed instead[of the overriding one].

Keep in mind that, in the inheritance hierarchy, since the instantiated
class is the sub one, for methods called via super.something() everything
is the same except for one thing (two, actually): "this" means "the only
this we have" (a pointer to the class we have instantiated, the
subclass), even when java syntax allows us to omit "this" (most of the
time); "super", though, is polymorphism-aware and always refers to the
superclass of the class (instantiated or not) that we're actually
executing code from ("this" is about objects [and can't be used in a
static context], super is about classes).

즉, Java 언어 사양 에서 인용 :

양식 super.IdentifierIdentifier현재 객체의 이름 이 지정된 필드를 참조 하지만 현재 객체는 현재 클래스의 수퍼 클래스 인스턴스로 표시됩니다.

양식 T.super.Identifier은에 해당 Identifier하는 어휘 적으로 둘러싸는 인스턴스의 이름 이 지정된 필드를 참조 T하지만 해당 인스턴스는의 수퍼 클래스 인스턴스로 표시 T됩니다.

평신도의 용어로, this기본적으로 객체 (* the ** 객체, 변수에서 이동할 수있는 것과 동일한 객체), 인스턴스화 된 클래스의 인스턴스, 데이터 도메인의 일반 변수입니다. super실행하고자하는 차용 된 코드 블록에 대한 포인터와 같으며, 단순한 함수 호출과 비슷하며 호출되는 클래스와 관련이 있습니다.

따라서 super수퍼 클래스에서 사용 하는 경우 수 퍼듀 퍼 클래스 [조부모]에서 코드가 실행되는 반면, 수퍼 클래스에서 사용 this(또는 암시 적으로 사용되는 경우)하면 하위 클래스를 계속 가리 킵니다 (아무도 변경하지 않았기 때문에-그리고 아무도 할 수 있었다).


답변

superClass.method1이 subClass.method2를 호출하지 않도록하려면 method2를 재정의 할 수 없도록 private로 설정하십시오.

다음은 제안입니다.

public class SuperClass {

  public void method1() {
    System.out.println("superclass method1");
    this.internalMethod2();
  }

  public void method2()  {
    // this method can be overridden.  
    // It can still be invoked by a childclass using super
    internalMethod2();
  }

  private void internalMethod2()  {
    // this one cannot.  Call this one if you want to be sure to use
    // this implementation.
    System.out.println("superclass method2");
  }

}

public class SubClass extends SuperClass {

  @Override
  public void method1() {
    System.out.println("subclass method1");
    super.method1();
  }

  @Override
  public void method2() {
    System.out.println("subclass method2");
  }
}

이런 식으로 작동하지 않는다면 다형성은 불가능할 것입니다 (적어도 절반도 유용하지 않습니다).


답변

재정의되는 메서드를 피하는 유일한 방법은 super 키워드를 사용하는 것이므로 SuperClass 에서 다른 새 Base 클래스 로 method2 ()를 이동 한 다음 SuperClass 에서 호출 할 수 있다고 생각했습니다 .

class Base
{
    public void method2()
    {
        System.out.println("superclass method2");
    }
}

class SuperClass extends Base
{
    public void method1()
    {
        System.out.println("superclass method1");
        super.method2();
    }
}

class SubClass extends SuperClass
{
    @Override
    public void method1()
    {
        System.out.println("subclass method1");
        super.method1();
    }

    @Override
    public void method2()
    {
        System.out.println("subclass method2");
    }
}

public class Demo
{
    public static void main(String[] args)
    {
        SubClass mSubClass = new SubClass();
        mSubClass.method1();
    }
}

산출:

subclass method1
superclass method1
superclass method2


답변

this 항상 현재 실행중인 개체를 참조합니다.

여기에 요점을 더 설명하기 위해 간단한 스케치가 있습니다.

+----------------+
|  Subclass      |
|----------------|
|  @method1()    |
|  @method2()    |
|                |
| +------------+ |
| | Superclass | |
| |------------| |
| | method1()  | |
| | method2()  | |
| +------------+ |
+----------------+

상자 Subclass내부, 심지어 Superclass‘영역’ 으로 모험을 할 때마다 외부 상자, 개체 의 인스턴스가있는 경우 여전히 외부 상자의 인스턴스입니다.

더욱이이 프로그램에는 세 개의 클래스에서 생성되는 객체가 하나 this뿐 이므로 한 가지만 참조 할 수 있습니다.

여기에 이미지 설명 입력

상기 실시 형태에서 나타낸 넷빈즈 ‘힙 보행자.