可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Given the follow class hierarchy what are the dynamic and static types for the following statements?
Class hierarchy:
class Alpha {}
class Beta extends Alpha {}
class Gamma extends Alpha {}
class Epsilon extends Alpha{}
class Fruit extends Gamma{}
class Golf extends Beta {}
class Orange extends Fruit{}
For each of the following statements, Static Type? Dynamic Type?:
Fruit f = new Fruit();
Alpha a = f;
Beta b = f;
a = b;
Gamma g = f;
My answers/questions
I understand that Fruit f = new Fruit()
will be of both static and dynamic type Fruit.
Alpha a = f;
Will be of type Alpha at at compile time (static) and type Fruit at runtime (dynamic).
Gamma g = f;
Will be of type Gamma at compile time (static) and type Fruit at runtime (dynamic).
However I do not know the other two answers. Beta b = f is an instance in which two subclasses of the same super class are assigned to one another so I'm not sure if it would be of type Beta or type Alpha at compile time (static). And a = b is an assignment after declaration so I'm not sure what the answer for that would be. Someone please help me out thanks!
回答1:
I'm typing this in a hurry, so pls excuse any typos (I'll fix those later when I get a chance).
I understand that Fruit f = new Fruit() will be of both static and dynamic type Fruit.
I think you are confusing a bit the terms static and dynamic
types with compile-time and run-time types (or as in C++ when you assign the address of a object of type A to a pointer of type B with B being the parent class of A.)
Barring reflection tricks, there is no dynamic typing in Java. Everything is statically typed at compile time. The type of an object at run-time is the same as the one it got compiled to.
What is happening is that you are confusing object references (a, b, c, f) with actual objects instantiated in the heap (anything created with new
.)
In Java, f
is an object reference, not the object itself. Moreover, the reference type of f
is Fruit and sub-classes of it
. The object (new Fruit()
) that you assign to it happens to be of type Fruit
.
Now all the other references in your sample code, a is of type reference to A and sub-classes of it
; b is of type reference to B and sub-classes of it
; etc, etc.
Keep this in mind because it is very important.
Alpha a = f; Will be of type Alpha at at compile time (static) and type Fruit at runtime (dynamic).
a is of type 'reference to type A and sub-classes'.
f is of type 'reference to type Fruit and sub-classes'.
The object f points to is of type 'Fruit'. When you say 'a = f' you are not assigning 'f' to 'a'. You are saying 'a now will reference that thing f is currently referencing to'.
So after that assignment, what is a
referencing? The object of type Fruit
the object reference f
pointed to at the time of assignment.
Remember, a, b, g, f, they are not objects. They are references or handles to objects created one way or another with the new
operator.
A reference variable such as a, b or f are different beasts from the objects created with new
. But it just so happen that the former can point to the later.
The type of the object created with new at run-time is the same as the one determined at compile time.
Gamma g = f; Will be of type Gamma at compile time (static) and type Fruit at runtime (dynamic).
Same as above. The variable g
is an object reference of type reference to type Gamma and sub-classes
. In this assignment, g
is made to point to the same object pointed by f
. What is the type of that object? The same given at compile time: Fruit.
However I do not know the other two answers. Beta b = f is an instance
in which two subclasses of the same super class are assigned to one
another so I'm not sure if it would be of type Beta or type Alpha at
compile time (static).
b is of type reference to type Beta and sub-classes of it
. The object it points to after the assignment b = f
is of type Fruit
, the type it had at compile time.
The type of object references a, b, g, and f is determined at compile time. They are statically typed and do not change at run-time.
The type of an object created with new
is also determined at compile time. They are also statically typed and do not change at run-time.
The objects, the stuff object references a, b, g and f point to at run-time, that is determined by whether the statements are found valid by the compiler. The assignments can change, but that has nothing do with whether the object references or the object themselves are statically or dynamically typed.
If you want to see a clear distinction between dynamic and static typing consider the following:
// Java, statically typed.
int x = 3;
x = 5; // good
x = "hi"; // compiler error
## Ruby, dynamically typed
x = 3 # ok
x = 5 # ok
x = "hi" # still ok
Then there is the distinction between strongly typed and weakly/duck typed languages (both of which can be dynamically typed.) There is plenty of literature on this subject out there.
Hope it helps.
回答2:
the dynamic and static types for the following statements
Erm, a statement doesn't have a type, at least there is no such notion in the Java Language Specification. The spec does define two different kinds of types: the declared type of variable, field, or parameter, and the runtime class of an object.
As the name indicates, the declared type of a variable, field or parameter is the type you mention in the declaration. For instance, the declaration Foo bar;
declares a variable named bar
of type Foo
.
The runtime class of an object is determined by the class instance or array creation expression used to construct it, and remains the same throughout the lifetime of that object.
So the code:
Integer i = 1;
Number n = i;
Object o = n;
declares 3 variables of types Integer
, Number
and Object
, respectively, all of which refer to a single object with runtime class Integer
.
回答3:
The concrete, runtime type of f
is Fruit (as you correctly stated in your question).
So Beta b = f;
initilalizes a variable whose declared, compile-time type is Beta, and whose runtime type is Fruit. This won't compile though, because the compile-time type of f
is Fruit, and Fruit is not a subclass of Beta, so f
can't be assigned to a variable of type Beta.
In a = b;
, b
, whose runtime type is Fruit (see above) is assigned to the variable a
, declared as Alpha a
. So a
's compile-time type is Alpha and its runtime type is Fruit.
回答4:
First to clarify "Reference Variable" type:
Object obj;
Points to nothing and the Reference Variable obj would have NO type.
Now
Object obj = new String();
System.out.println(obj.getClass());//prints class java.lang.String
obj points to a String and the Reference Variable obj has type String.
The point is Java is a statically typed language and all reference type variables have a type assigned at compile time. The reference variable obj can point to some other object as long as it is a subclass of Object. In this case
almost anything. Consider
Object obj = new String();
System.out.println(obj.getClass());//prints class java.lang.String
Number num = new Byte((byte)9);
obj = num;
System.out.println(obj.getClass());//prints class java.lang.Byte
At Runtime, same as compile time, the reference variable obj has type Byte.
The static/dynamic type of an object, for me, has to do with inheritance.
More specifically the overriding mechanism. Also known as Dynamic Polymorphism
and Late Binding.
Consider overriding the equals() in class Object:
public class Types {
@Override
public boolean equals(Object obj){
System.out.println("in class Types equals()");
return false;//Shut-up compiler!
}
public static void main(String[] args){
Object typ = new Types();
typ.equals("Hi");//can do this as String is a subclass of Object
}
}
Now we know that the type of the reference variable typ is Types.
Object typ = new Types();
When it comes to
typ.equals("Hi");
This is how I think the compiler thinks.
If the equals() is
1.NOT static and final, which it is.
2.Referenced from a base class (more on this soon).
then the compiler defers which method gets called to the JVM. The exact method that is invoked depends on the Dynamic Type(more soon) of the variable that calls the method. In our case the reference variable is typ.
This is known as Dynamic Method Invocation.
Now Referenced from a base class:
From the above code
Object typ = new Types();
typ.equals("Hi");
Type Object could be regarded as the base type of typ, also known as the Static Type of a reference variable and the equals() is referenced from the base type, in this case Object.
if we had
Types typ = new Types();
There would be no reference from a base type and hence no Dynamic Method Invocation.
Now to the Dynamic Type of a reference variable.
Object typ = new Types();
typ.equals("Hi");
The Dynamic Type of typ is Types and according to Dynamic Method Invocation, the equals() in class Types would be called at runtime.
Also lets say we had another class that extends Types, TypesSubClass.
And TypesSubClass also had a overridden equals(). Then
Object typ = new TypesSubClass();
typ.equals("Hi");
Would make the Dynamic Type of typ TypesSubClass and TypesSubClass's
equals() would be called at runtime.
To be honest, I personally didn't know why we needed all of this and have posted a question regarding this. check
What is the reason behind Dynamic Method Resolution in a staticlly typed language like Java
回答5:
You should take a look at this article: http://www.sitepoint.com/typing-versus-dynamic-typing/
Static typing is when a language does not require the variable to be initialized.
eg.
/* C code */
static int num, sum; // explicit declaration
num = 5; // now use the variables
sum = 10;
sum = sum + num;
Dynamic typing is when a language requires the variable to be initialized.
eg.
/* Python code */
num = 10 // directly using the variable