UFO ET IT

Java에서 멤버 변수 재정의 (변수 숨기기)

ufoet 2020. 12. 10. 20:45
반응형

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 개념은 객체 유형에 따라 재정의되며 변수는 참조 유형에서 액세스됩니다.

  1. 함수 재정의 :이 경우 부모 및 자식 클래스가 모두 고유 한 정의를 가진 동일한 이름의 함수를 가지고 있다고 가정합니다. 그러나 어떤 함수를 실행할지는 런타임에 참조 유형이 아닌 객체 유형에 따라 다릅니다.

예 :

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 클래스 함수가 ​​호출됩니다.

  1. 변수 무시 : 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액세스 할 수 없습니다 . 식별자 (즉, 클래스, 변수 등 이름)는 컴파일 타임에 확인되므로 컴파일러는이를 수행하기 위해 참조 유형에 의존합니다.aRefaRef = b

이제 예제에서 실행할 때 정의 된 System.out.println(aRef.intVal);값을 인쇄 합니다. 이것은 액세스하는 데 사용하는 참조 유형이기 때문입니다. 컴파일러는 그것이 유형 이고 그것이 액세스 할 것이라고 본다 . 의 인스턴스에 필드 가 있음을 잊지 마십시오 . JLS에는 "15.11.1-1. 필드 액세스를위한 정적 바인딩"과 유사한 예제도 있습니다.intValAaRefAintValB

그러나 방법이 다르게 작동하는 이유는 무엇입니까? 대답은 메소드의 경우 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 : 자식 클래스에 액세스하는 한 가지 방법 intValSystem.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

enter image description here


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

반응형