java subtype relationship - java

While reading Horstmann's book, I've encountered this about subtype relationship in Java:
S is a subtype of T if:
S is an array type and T is Cloneable or Serializable
And I couldn't truly understand what this is supposed to mean. Can anyone help?
Thanks!

This is a simple example of subtyping.
The Array type implements the Cloneable and Serializable interfaces.
However, these interfaces do not specify any methods as part of the method contract. In fact, these are only marker interfaces whose existence gives details to the compiler and users of your classes without directly requiring any functionality.
For example:
Note that this interface does not contain the clone method. Therefore, it is not possible to clone an object merely by virtue of the fact that it implements this interface. Even if the clone method is invoked reflectively, there is no guarantee that it will succeed.

I think what is causing your confusion is that "cloneable" and "serializable" are attributes in the English language, and the phrase "is Cloneable" is commonly used to express that a class implements the Cloneable interface. However, here they only denote exactly the interface names Cloneable and Serializable, and "is" is to be understood as "is exactly/equals". That is, if T IS the interface Cloneable or if T IS the interface Serializable, then any array type is a subtype of T.
An array type is any type of the form U[], where U is an arbitrary type, i.e., non-void primitive or reference type (note that an array type, even of a primitive type, also is a reference type). This has nothing to with the class java.lang.reflect.Array, which is not an array type!
You cannot assign any array to a reference variable of a class implementing Cloneable or Serializable, but only to a reference variable of exactly the type Cloneable or Serializable. Hence, if you have
int[] a = ...; // primitive array
Object[] b = ...; // reference type array
int[][] c = ...; // reference type array, since int[] is a reference type
then the following is legal:
Cloneable x = a; x = b; x = c;
Serializable y = a; y = b; y = c;

Related

How to get the original type (instead of E) for a Parameterized type with generics using reflection? [duplicate]

I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using the code
List<Integer> l = new ArrayList<>();
Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
This, however does not work for me, resulting in
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
If I remove the class cast, the type of the actual argument is E, which is the type definition from List interface.
My question is, therefore, am I doing something wrong here? This behaviour is something I would have expected anyway, since the types are supposed to be erased during compile time, correct?
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
For example if you did this:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class, because Integer is "baked into" the IntegerList.
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken:
Represents a generic type T. You can use this class to get the generic type for a class. > For example, to get the generic type for Collection<Foo>, you can use:
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>.
Note that this would not work (even if the TypeToken class wouldn't prevent it by making its constructor protected):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
The javadoc will tell you what you are doing.
Class#getGenericSuperclass() states
Returns the Type representing the direct superclass of the entity
(class, interface, primitive type or void) represented by this Class.
If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code. [...]
The direct superclass of ArrayList is AbstractList. The declaration is as such in the source code
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type object returned by it, you will see
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments() which states
Returns an array of Type objects representing the actual type
arguments to this type.
will return the Type
E
since E is the actual type argument used in the ArrayList class definition.
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
If you are creating instances on the fly it won't work:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you)
(It's called Type Erasure)

What makes an object assignment-compatible with another class?

I'm wondering what specifically allows an object of one class to be cast as another class. Looking at the Class.isInstance(Object obj) javadoc, it suggests that an object has to be 'assignment-compatible' with another class in order to be cast to that class. But what constitutes 'assignment-compatible'?
I'm trying to figure out how the following returned a ClassCastException:
public class A
{
multiple private attributes
No constructor
multiple public methods
}
public class B extends A
{
blank default constructor
2 additional private attributes
4 additional public getter / setter methods for these attributes
}
The line
B b = (B)variable.getA() // where getA() returned an instance of class A
returns a ClassCastException A cannot be cast as B. I know that casting from a parent class to a subclass is a bad idea. I did not write the code in question, I'm just looking at it in a production support capacity.
Class B is the only class in the codebase that extends from A. So the result of getA() is not an object of another subclass of A (say C) cast to A.
So why in this instance can Java not cast an object of class A to the seemingly compatible class B?
Consider these two cases:
A a = new B();
B b = (B)a; <-- Ok.
A a = new A();
B b = (B)a; <-- ClassCastException
So in order to cast an object to B it must be an instance of B (or a subclass of B).
In your case it is however an instance of A.
The javadoc for Class.isInstance(Object obj) gives the definition of assignment compatible:
Specifically, if this Class object represents a declared class, this method returns true if the specified Object argument is an instance of the represented class (or of any of its subclasses); it returns false otherwise. If this Class object represents an array class, this method returns true if the specified Object argument can be converted to an object of the array class by an identity conversion or by a widening reference conversion; it returns false otherwise. If this Class object represents an interface, this method returns true if the class or any superclass of the specified Object argument implements this interface; it returns false otherwise. If this Class object represents a primitive type, this method returns false.
Basically, you can assign an object of type A to variable of type B if type A extends or implements type B.
Thrown to indicate that the code has attempted to cast an object to a subclass of which it is not an instance. For example, the following code generates a ClassCastException:
Object x = new Integer(0);
System.out.println((String)x);
more info here and here.
If we replaced A and B with meaningful names that help us think about the problem, then the answer becomes clearer. If A becomes Mammal and B is Dog, then we can reasonably say that all Dogs are Mammals, but we cannot say that all Mammals are Dogs. Even if they superficially shared the same attributes, there is no guarantee that all Mammals would fulfill the contract of being a Dog, and the compiler shouldn't try to assume so.
Just wanted to add the official specification to support
Ricardo's correct answer that "you can assign an object of type A to variable of type B if type A extends or implements type B":
The JLS defines assignment-compatibility as follows:
5.2. Assignment Contexts
If the type of an expression can be converted to the type of a variable by assignment conversion, we say the expression (or its value) is assignable to the variable or, equivalently, that the type of the expression is assignment compatible with the type of the variable.
The term "assingment conversion" is only defined as applying the appropriate conversion from the list given in the "Assignment Contexts"-chapter:
The term "conversion" is also used to describe, without being specific, any conversions allowed in a particular context. For example, we say that an expression that is the initializer of a local variable is subject to "assignment conversion", meaning that a specific conversion will be implicitly chosen for that expression according to the rules for the assignment context.
The most relevant for reference types being
5.1.5. Widening Reference Conversion
A widening reference conversion exists from any reference type S to any reference type T, provided S is a subtype of T (ยง4.10).
Subtypes include implemented interfaces (see 4.10.2. Subtyping among Class and Interface Types ).
There are additional rules for numeric and generic types, but they are not relevant for the example given in the question.

Polymorphism in Java - can I set an object to a specific type?

I am a programmer who is getting to grasps with polymorphism after a long break and I was wondering if the following is possible. Say I had a super class in which there were some instance variables A, B and C. In all subclasses A and B are strings and behave as such in all subclasses however in all of the subclasses, the type of C may depend on the state of the subclass. I was wondering if it is possible to set C as type 'Object' in the superclass and then specify its type in each subclass using wrapper classes. e.g
public class SuperClass {
String A;
String B;
Object C;
public SuperClass(){}
}
}
public class SubClassA extends SuperClass {
public SubClassA () {
C = new String(); //notice this type is different from its type in the next class
}
}
public class SubClassB extends SuperClass {
public SubClassB () {
C = new Integer();
}
}
your thoughts would be appreciated :)
Thanks
No. "Set an object to a specific type" does not mean anything. In fact, "Set an object." does not mean anything.
A, B, and C in your example are not objects, they are variables. There are three kinds of variable in Java; primitives (e.g, int, boolean, double), array reference variables, and object reference variables. A, B, and C are object reference variables. That means, A, B, and C each hold the identity of some object.
Initially, they all hold null which is a special object reference that means "no object."
Your subclass constructors each create a new object, and store its identity in C.
Objects have types which can be known at run-time, and variables have types which are only known at compile time. The compiler will reject your code if it can prove that you assign the identity of some object to an object reference variable with an incompatible type.
The type of variable C, Object, is compatible with any object. You can assign a String reference to it, or you can assign an Integer reference to it, or you can assign a ForkJoinPool.ForkJoinWorkerThreadFactory reference to it. The downside, is that the compiler will only let you perform operations through C that can be performed on every type of object. The compiler won't allow you to call C.toUpperCase()---not even if it holds a reference to an actual String object.---because you have explicitly declared that C may hold references to things that are not Strings.
I would not write the code that you wrote, but it's hard to say what I would write instead, because your example doesn't actually do anything. You'll get better answers in this forum if you ask questions about how to solve actual problems.
Understand, first and foremost, the difference between an object and a reference. An object is something that you create with new and it has a specific type (class) that is fixed from the moment it's created. A reference is a "pointer" to an object.
A single reference can point to different types of objects at different times, so long as the declared type of the reference is the class of the object or its superclass. Object is the superclass of all objects (including arrays, but not "scalars" like int, char, float, etc) and hence a reference declared with type Object can point to any object.
Of course, if you have a reference declared as Object then even if you (supposedly) know what's in it, the compiler and JVM haven't a clue. So you need to "cast" the reference to the appropriate type before you can use it. Eg, knowing that you previously stored a pointer to a String object into C, you might do:
String castFromC = (String)C;
Char charFromC = castFromC.charAt(5);
If it turns out that C is not a String but is instead an Integer, then the (String) "cast" operation will fail at runtime with a ClassCastException.
From my understanding of your concern, your posted code looks OK to me. However, it will force you to cast C to a specific type for it to be "operable" since you just declared the object reference C as just a "reference pointing to an Object type of Java object".
To avoid the ugly typecasting, you can generify your superclass like this
class SuperClass<T> {
String A;
String B;
T C;
public SuperClass(){}
}
And in your subclasses, you can use it like this
class SubClassA extends SuperClass<String> {
public SubClassA () {
C = new String();
}
}
class SubClassB extends SuperClass<Integer> {
public SubClassB () {
C = new Integer(0);
}
}
Also, it is a convention that your instance variables should have a meaningful name starting with lowercase, declared private, and exposed to other classes with public getters and setters.

Difference between Dynamic and Static type assignments in Java

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!
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.
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.
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
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.
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

Is there an alternative to Class.isAssignableFrom that works with Type objects?

In Java, Class has an isAssignableFrom method defined as follows:
public boolean isAssignableFrom(Class<?> cls)
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false. If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false.
Specifically, this method tests whether the type represented by the specified Class parameter can be converted to the type represented by this Class object via an identity conversion or via a widening reference conversion. See The Java Language Specification, sections 5.1.1 and 5.1.4 , for details.
Parameters:
cls - the Class object to be checked
Returns:
the boolean value indicating whether objects of the type cls can be assigned to objects of this class
Class implements the Type interface. Is there an equivalent isAssignableFrom method that works on Types instead of just Classes? For example, is there a method that determines if a variable of type List<String> (which would be represented via an instance of ParameterizedType) can be assigned to a variable of type List<? extends Object>?
Have a look at javaRuntype -- I've found it useful. It can produce representations of types from instances of java.lang.reflect.Type, and test assignability between them.
Guava's TypeToken utility provides that functionality. Your query could be answered like this:
// represents List<String>
ParameterizedType stringList = ...;
// represents List<? extends Object>
TypeToken objectList = new TypeToken<List<? extends Object>>(){};
boolean isAssignable = objectList.isAssignableFrom( stringList );
You can cast between any List<...>-s, the protection is weaker than normally.
Try this
List<String> a = new Vector<String>();
List<Integer> b = new Vector<Integer>();
Integer i = new Integer(0);
b.add(2);
a = (List<String>) (Object) b;
System.out.println((Object)a.get(0));
no exceptions will be thrown.
This is because generics are only compile time notion.
If you write
System.out.println(a.get(0));
you will get ClassCastException because println function version determined at compile time will be println(String arg).
Ah, so the answer to the question: it should be incorrect to have such an alternative.
There is TypeUtils.isAssignable(Type, Type) in Apache Commons Lang3

Categories

Resources