Java에서 멤버 변수 재정의 (변수 숨기기)
JAVA에서 멤버 함수 재정의를 연구 중이며 멤버 변수 재정의 실험에 대해 생각했습니다.
그래서 저는 클래스를 정의했습니다.
public class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
public class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class mainClass
{
public static void main(String [] args)
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
System.out.println(aRef.intVal);
aRef.identifyClass();
}
}
출력은 다음과 같습니다.
1
I am class A
1
I am class B
aRef가 b로 설정된 경우 intVal이 여전히 클래스 A 인 이유를 이해할 수 없습니다.
하위 클래스에서 같은 이름의 변수를 만들 때이를 hide 라고 합니다. 결과 하위 클래스는 이제 실제로 두 속성 을 모두 갖습니다. 당신과 함께 슈퍼 클래스에서 하나에 액세스 할 수 있습니다 super.var
또는 ((SuperClass)this).var
. 변수는 같은 유형일 필요도 없습니다. 두 개의 오버로드 된 메소드처럼 이름을 공유하는 두 개의 변수 일뿐입니다.
변수는 Java에서 다형성이 아닙니다. 그들은 서로를 무시하지 않습니다.
변수는 컴파일 타임, 메서드 런타임으로 확인됩니다. aRef는 A 유형이므로 aRef.Intvalue는 컴파일시 1로 확인됩니다.
Java에는 필드에 대한 다형성이 없습니다.
Variables
결정은 컴파일 시간에 발생하므로 항상 기본 클래스 변수 (자식의 상속 된 변수가 아님)에 액세스합니다.
따라서 업 캐스트가 발생할 때마다 항상
1) 기본 클래스 변수에 액세스합니다.
2) Sub Class 메서드 (오버라이드가 발생하면 오버라이드 된 메서드, 부모로부터 상속 된 메서드)가 호출됩니다.
Java 함수의 OverRiding 개념은 객체 유형에 따라 재정의되며 변수는 참조 유형에서 액세스됩니다.
- 함수 재정의 :이 경우 부모 및 자식 클래스가 모두 고유 한 정의를 가진 동일한 이름의 함수를 가지고 있다고 가정합니다. 그러나 어떤 함수를 실행할지는 런타임에 참조 유형이 아닌 객체 유형에 따라 다릅니다.
예 :
Parent parent=new Child();
parent.behaviour();
다음 parent
은 Parent 클래스에 대한 참조이지만 Child Class의 객체를 보유하고 있으므로이 경우 Child 클래스 함수가 호출됩니다.
Child child=new Child();
child.behaviour();
여기 child
에는 Child Class의 객체가 있으므로 Child 클래스 함수가 호출됩니다.
Parent parent=new Parent();
parent.behaviour();
여기 parent
에 Parent Class의 객체가 있으므로 Parent 클래스 함수가 호출됩니다.
- 변수 무시 : Java는 오버로드 된 변수를 지원합니다. 그러나 실제로 이것들은 같은 이름을 가진 두 개의 다른 변수입니다. 하나는 부모 클래스에 있고 다른 하나는 자식 클래스에 있습니다. 그리고 두 변수는 동일한 데이터 유형이거나 다를 수 있습니다.
변수에 액세스하려고 할 때 개체 유형이 아닌 참조 유형 개체에 따라 다릅니다.
예 :
Parent parent=new Child();
System.out.println(parent.state);
참조 유형은 Parent이므로 Child 클래스 변수가 아닌 Parent 클래스 변수에 액세스합니다.
Child child=new Child();
System.out.println(child.state);
여기서 참조 유형은 Child이므로 Parent 클래스 변수가 아닌 Child 클래스 변수에 액세스됩니다.
Parent parent=new Parent();
System.out.println(parent.state);
여기서 참조 유형은 Parent이므로 Parent 클래스 변수에 액세스합니다.
JLS Java SE 7 Edition §15.11.1에서 :
이러한 필드 액세스에 대한 동적 조회가 없기 때문에 프로그램을 직접 구현하여 효율적으로 실행할 수 있습니다. 후기 바인딩 및 재정의 기능을 사용할 수 있지만 인스턴스 메서드를 사용할 때만 가능합니다.
Oliver Charlesworth와 Marko Topolnik의 답변이 맞습니다 . 질문 의 이유 부분 에 대해 조금 더 자세히 설명하고 싶습니다 .
Java에서 클래스 멤버 는 실제 객체의 유형이 아닌 참조 유형에 따라 액세스 됩니다. 같은 이유로 someOtherMethodInB()
in class 가있는 경우 실행 후 B
액세스 할 수 없습니다 . 식별자 (즉, 클래스, 변수 등 이름)는 컴파일 타임에 확인되므로 컴파일러는이를 수행하기 위해 참조 유형에 의존합니다.aRef
aRef = b
이제 예제에서 실행할 때 정의 된 System.out.println(aRef.intVal);
값을 인쇄 합니다. 이것은 액세스하는 데 사용하는 참조 유형이기 때문입니다. 컴파일러는 그것이 유형 이고 그것이 액세스 할 것이라고 본다 . 의 인스턴스에 두 필드 가 있음을 잊지 마십시오 . JLS에는 "15.11.1-1. 필드 액세스를위한 정적 바인딩"과 유사한 예제도 있습니다.intVal
A
aRef
A
intVal
B
그러나 방법이 다르게 작동하는 이유는 무엇입니까? 대답은 메소드의 경우 Java가 후기 바인딩을 사용한다는 것입니다 . 즉, 컴파일 타임 에 런타임 중에 검색 하기에 가장 적합한 방법을 찾습니다 . 검색에는 일부 클래스에서 메서드가 재정의되는 경우가 포함됩니다.
도움이 되었기를 바랍니다.
public class B extends A {
// public int intVal = 2;
public B() {
super();
super.intVal = 2;
}
public void identifyClass() {
System.out.println("I am class B");
}
}
따라서 기본 클래스의 변수를 재정의 할 수는 없지만 상속 된 클래스의 생성자에서 기본 클래스 변수 값을 설정 (변경) 할 수 있습니다.
이를 변수 숨김이라고합니다 . 당신이 할당 할 때 aRef = b;
, aRef
두 INTVAL, 1 단지 이름이있다 intVal
또 다른이 아래에 숨겨져 A.intVal
당신의 변수 타입이기 때문에, (디버거 스크린 샷 참조) class A
방금 인쇄 할 경우에도, intVal
지능적으로 집어 자바 A.intVal
.
답변 1 : 자식 클래스에 액세스하는 한 가지 방법 intVal
은System.out.println((B)aRef.intVal);
답변 2 : 또 다른 방법은 Java Reflection입니다. 리플렉션 자바를 사용하면 A.intVal
클래스 유형에 따라 숨겨진 정보를 지능적으로 픽업 할 수 없기 때문에 문자열로 지정된 변수 이름을 선택해야합니다.
import java.lang.reflect.Field;
class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class Main
{
public static void main(String [] args) throws Exception
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
Field xField = aRef.getClass().getField("intVal");
System.out.println(xField.get(aRef));
aRef.identifyClass();
}
}
출력-
1
I am class A
2
I am class B
Well, I hope u got the answer. If not, you can try seeing in the debug mode. the subclass B has access to both the intVal. They are not polymorphic hence they are not overriden.
If you use B's reference you will get B's intVal. If you use A's reference , you will get A's intVal. It's that simple.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.
Hence the variable in the sub class only can be seen as one sharing the same name.
Also when the constructor of A is called during the instance creation of B the variable (intVal) is initialized and hence the output.
Java has a feather of encapsulation means it tightly binds the property and the behavior of an object. so only via a class reference we can call it's behavior to change it's property.
and in inheritance only method overrides so that it can affects only it's property.
참고URL : https://stackoverflow.com/questions/10722110/overriding-member-variables-in-java-variable-hiding
'UFO ET IT' 카테고리의 다른 글
사전을 데이터 소스로 사용하여 콤보 상자 바인딩 (0) | 2020.12.10 |
---|---|
3.2 sdk 플랫폼 설치 문제. (0) | 2020.12.10 |
SVN은 LC_CTYPE 로케일을 설정할 수 없습니다. (0) | 2020.12.10 |
연결 Java-MySql : 공개 키 검색이 허용되지 않습니다. (0) | 2020.12.10 |
장고 모델 인스턴스의 여러 필드를 업데이트하는 방법은 무엇입니까? (0) | 2020.12.10 |