What is the class type of the ref superclass that points to the subclass object?

I have the following codes:

1. public class Tester
2. {
3.      public static void main(String[] args)
4.      {
5.          A a = new B();
6.          System.out.println(a.getClass());    //Prints class B       
7.          System.out.println(a instanceof A);  //Prints true
8.          System.out.println(a instanceof B);  //Prints true
9.          System.out.println(a.valA);          //Prints 1
10.         System.out.println(a.valB);          //Compilation error
11.
12.     }
13. }
14.
15. class A
16. {
17.     int valA=1;
18. }
19.
20. class B extends A
21. {
22.     int valB=2;
23. }

      

Line 6 shows what the a

type is class B

. However, when it reaches the line 10, the compiler generates an error : location: variable a of type A

.

So my question is: What is the class type now a

? Why getClass()

does it show it has a type class B

but the compiler complains about it as a type a

at compile time?

Also, since it is a instanceof B

true, why can't I access valB

?


To make it clearer:

EDIT . I ran this statement: System.out.println(a);

and the result was B@36d98810

, which somehow proves that the toString()

method was executed class B

. Since the variable a

can access the toString () method in class B

, why can't it access valB

which is also in class B

?

+3


source to share


5 answers


Professor Jonathan Shevchuk of UC Berkley explains that there is shadow circulation here . Start at 18 minutes. (If the link only changes google search for CS 61B Lecture 15: More Java)

To answer the short question, there are two types of variables, static type and dynamic type.

Static type is its Type at compile time
Dynamic type is its Type at run time.

      

In your example

A a = new B();

      

The static type a is A and the dynamic type a is B.

In Java a variable gets its non static methods from dynamic type
(if the method exists in both the parent and child class)
and 
its fields and static methods from the static type.

      



This is true in C # only if the method is overridden in the subclass

Update: String

a instanceof A

      

indicates whether the type is dynamic type of a OR subclass A

Update 2: An example to illustrate this

public class PlayGround {

    public static void main(String[] args) {
        Animal a = new Dog();
        System.out.print(a.name);// displays animal
        System.out.print("\r\n");
        a.MakeStaticSound();// displays static animal sound
        System.out.print("\r\n");
        a.MakeSound();// displays bow wow

    }

}

class Animal {
    public String name = "animal";

    public void MakeSound() {
        System.out.print("animal sound");
    }

    public static void MakeStaticSound() {
        System.out.print("static animal sound");
    }

}

class Dog extends Animal {
    public String name = "dog";

    public void MakeSound() {
        System.out.print("bow wow");
    }

    public static void MakeStaticSound() {
        System.out.print("static bow wow");
    }

}

      

Note that the more readable and preferred way to call a.MakeStaticSound () is Animal.MakeStaticSound ()

+3


source


a

is not an object. This is a variable.

Variable type a

. The type of object for which the value of the variable refers to at run time is B

.



The compiler decides everything against the compile-time type of the expressions involved - the variable in this case. When trying to resolve the name valB

during compile time, a

it can't find anything - hence the error.

+2


source


You need to keep in mind that compilation and execution are two different processes that take place at different times and have different information available to them. The compiler has to predict the future - it has to decide whether it can guarantee that your code will make sense in the future at runtime. It does this by examining the types of objects in your code. On the other hand, the runtime must check the current state .


When you read a line A a = new B()

, you output more information about the local variable a

than the compiler does. The compiler basically just sees it as A a = <some expression>

. It does not take note of the content of the expression that was used to create the value for a

.

The fact that you said A a = ...

, you are telling the compiler, "hey, this a

thing that I will be dealing with in the rest of my program is just a

, don 't think about it anymore." If you said B a = ...

, then you are telling the compiler what it is B

(and the compiler also sees B extends A

elsewhere in your code, so it knows that as well a

).

Subsequent expressions a instanceof A

, a instanceof B

, a.getClass()

and a.toString()

are legitimate from the point of view of the compiler, regardless of the type a

: the operator instanceof

and getClass()

> and toString()

are defined for all Object

s. (The compiler does not have to predict what value these expressions will produce at runtime, they just generate either true

, or false

some Class<?>

and some String

, respectively.)

But then when you come to a.valA

and a.valB

, the compiler really has to do some real work. He has to prove or guarantee that the facility a

will have a field valA

and valB

at runtime. But since you explicitly said this before, just assume that a

is a

, it cannot prove that at runtime it will have a field valB

.


Now, later, at runtime , the JVM has more information. When it evaluates a.getClass()

, it actually looks at the specific class that is "under the hood" a

and returns it. Likewise for instanceof B

- it looks at a specific class, and therefore the result of that expression is true

.

a.toString()

works the same way. At runtime, the JVM knows that the thing being referenced a

is in fact B

, so it executes the method B

toString

.

+1


source


This is a fundamental property of inheriting classes, interfaces, etc. Class "A" does not have a variable "valB". If you want to use the "valB" variable in the "B" class, you must first overlay the "A" class on the "B"

Try:

System.out.println(((B)a).valB);  

      

0


source


You should know the difference between an object type and an instance type. The compilation type is determined first and at runtime it does its best to keep that type safe. An instance type is the class whose object is being instantiated.

A a; //this is an object type
new B(); //this is an instance type
A a = new B(); //all together, but a is of type A, having instance of type B.

      

0


source







All Articles