자바 : 재정의 된 메서드를 호출하는 슈퍼 메서드 호출
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
기술적으로는 내가 public 메서드를 재정의 한 것을 알고 있지만 super를 호출했기 때문에 super 내의 모든 호출이 super에 남아있을 것이라고 생각했습니다. 어떻게 할 수 있는지에 대한 아이디어가 있습니까?
키워드 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.Identifier
은Identifier
현재 객체의 이름 이 지정된 필드를 참조 하지만 현재 객체는 현재 클래스의 수퍼 클래스 인스턴스로 표시됩니다.양식
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
class SuperClass
{
public void method1()
{
System.out.println("superclass method1");
SuperClass se=new SuperClass();
se.method2();
}
public void method2()
{
System.out.println("superclass 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();
}
}
산출:
서브 클래스 method1
수퍼 클래스 method1
수퍼 클래스 method2
this
항상 현재 실행중인 개체를 참조합니다.
여기에 요점을 더 설명하기 위해 간단한 스케치가 있습니다.
+----------------+
| Subclass |
|----------------|
| @method1() |
| @method2() |
| |
| +------------+ |
| | Superclass | |
| |------------| |
| | method1() | |
| | method2() | |
| +------------+ |
+----------------+
상자 Subclass
내부, 심지어 Superclass
'영역' 까지 모험을 할 때마다 외부 상자, 개체 의 인스턴스가있는 경우 여전히 외부 상자의 인스턴스입니다.
What's more, in this program there is only one object that gets created out of the three classes, so this
can only ever refer to one thing and it is:
as shown in the Netbeans 'Heap Walker'.
I don't believe you can do it directly. One workaround would be to have a private internal implementation of method2 in the superclass, and call that. For example:
public class SuperClass
{
public void method1()
{
System.out.println("superclass method1");
this.internalMethod2();
}
public void method2()
{
this.internalMethod2();
}
private void internalMethod2()
{
System.out.println("superclass method2");
}
}
"this" keyword refers to current class reference. That means, when it is used inside the method, the 'current' class is still SubClass and so, the answer is explained.
To summarize, this points to current object and the method invocation in java is polymorphic by nature. So, method selection for execution, totally depends upon object pointed by this. Therefore, invoking method method2() from parent class invokes method2() of child class, as the this points to object of child class. The definition of this doesn't changes, irrespective of whichever class it's used.
PS. unlike methods, member variables of class are not polymorphic.
During my research for a similar case, I have been ending up by checking the stack trace in the subclass method to find out from where the call is coming from. There are probably smarter ways to do so, but it works out for me and it's a dynamic approach.
public void method2(){
Exception ex=new Exception();
StackTraceElement[] ste=ex.getStackTrace();
if(ste[1].getClassName().equals(this.getClass().getSuperclass().getName())){
super.method2();
}
else{
//subclass method2 code
}
}
사건에 대한 해결책을 찾는 것이 합리적이라고 생각합니다. 물론 스레드에서 이미 언급했듯이 다른 메서드 이름이나 다른 매개 변수 유형으로 문제를 해결하는 방법이 있지만 제 경우에는 다른 메서드 이름으로 혼동하고 싶지 않습니다.
'developer tip' 카테고리의 다른 글
자바 스크립트 사전에서 키 컬렉션을 얻는 방법은 무엇입니까? (0) | 2020.09.23 |
---|---|
EC2 인스턴스를 재부팅하면 어떻게됩니까? (0) | 2020.09.22 |
시간이 아닌 DURATION 시간으로 작업 (0) | 2020.09.22 |
Play Protect에 의해 차단 된 설치 앱 (0) | 2020.09.22 |
SQL Server 2005의 MySQL REPLACE INTO 구현? (0) | 2020.09.22 |