How to inherit from a base generic class - java

Have a base genric class like ClassBase<T>
I found I can use
ClassDerived extends ClassBase
or
ClassDerived<T> extends Classbase<T>
So basically it means I can remove generics in the derived class, is that right?

Since all generic type information is erased in the compilation process, of course you can do that. However, most compilers will generate a warning unless the warning is turned off or suppressed. For instance, if I write class Foo extends HashMap {}, Eclipse reports: "HashMap is a raw type. References to generic type HashMap should be parameterized"

You can extend the raw version of a generic class, that's correct. Of course your second example:
ClassDerived<T> extends Classbase
... actually re-introduces a type parameter.

Related

Why won't Java let you inherit from a generic type-variable?

public class MyClass<T> extends T {...}
The above declaration will fail to compile with the error:
error: unexpected type
class MyClass<T> extends T {}
^
required: class
found: type parameter T
where T is a type-variable:
T declared in class MyClass
I can't really think of a reason for this to happen, so I am wondering if someone can shed some light on why it is that Java won't let you inherit from a generic type-variable.
The most obvious reason I can think of isn't even about type-erasure; it is the fact that when you make A a subclass of B, the Java compiler needs to know what constructors B has. If a class does not have a no-arguments constructor, then its sub-classes must call one of its defined constructors. But when you declare
public class MyClass<T> extends T {...}
It is absolutely impossible for the compiler to know what the super constructors are, since T is not fixed at compile-time (that's the whole point of generics after all), which is a situation that cannot be allowed in Java.
Java has quite a lot of language restrictions unlike C++ for example. What you want is not possible for many reasons listed in the comments (T might be final or have abstract methods). However, you are allowed to extend from a supertype having the generic type parameter:
public class MyClass<T> extends AnotherClass<T>
You might find the following alternative interesting:
public class MyClass<T extends AnotherClass> extends AnotherClass
What you want to do does make not much sense.
Your question is not so weird as it may look like :) Consider how would you deal with following:
Suppose your real class for T has a single constructor with 3 parameters. How would you implement the constructor of inherited class, if you don't know how to call the super constructor?
Suppose your real class for T has public final methods and you have defined methods with the same signature in the inherited class. What method would your object have? You cannot resolve such conflict.
Simple deductions based on your question.
T is a type.
MyClass extends T - MyClass is enhanced version of T.
MyClass < T> extends T - MyClass is enhanced T, but only for Type T.
there is no reason to state ' I extend T but only for type T'.
If you extend T, MyClass is already a Type of T & definitely not some X,Y or Z.
Generics are needed if you want to ensure Type safety, if you extend it is already type safe.

Misunderstanding of class of returned instance from generic method of class called from subclass instance in Java

Example:
interface S {}
interface SS extends S {}
abstract class A<T extends S> {
T get() {…}
}
abstract class B<BT extends SS> extends A<BT> {}
Why does ((B)someInstanceOfB).get() return an object of type S (and we should cast it to SS manually), when the compiler could determine that returned object is at least of type SS?
Why doesn't the compiler make implicit class cast to have clearer code? The code is of version 1.5+ and this is not secret for compiler. (Solved)
Update: Why doesn't the compiler compile B class as it implicitly has method BT get() { return super.get(); } ?
Is this problem solved in Java 1.7+?
By casting to B you're using a raw type.
Using a raw type removes all generic information from the object, no matter where it is.
That means that for the raw type B the get method looks like it is returning a S (because that's the erasure (i.e. the actual type used at runtime) of the type parameter T).
To avoid this, never use raw types! They are meant exclusively for backwards compatibility and interaction with legacy code.
Cast to B<? extends SS> instead.
And no: this problem will probably never be "solved" in any future version of Java, as it's non-existing when you use generics correctly.
Regarding Update: no, B does not have a method BT get(). It has a method T get() where T is bound to the type parameter BT which has a lower bound SS. But since all generic type information is discarded when you use a raw type, T will still fall back to the original erasure, which is S.
The rule is quite simple and basically says "when you use a raw type it acts as if the class has no generics at all". The implications, however, are not always obvious, as in this case.
You didn't parameterize your instance of B.
Let's say you have the class C implementing SS:
Then, new B<C>().get(); would return an object of type C.
On the new B().get(); line, your IDE must have told you "B is a raw type. References to generic type B should be parameterized.".

"Cannot be cast to java.lang.Class", namely: which type is not a class

This may seem a dumb question (as it could be very project specific) but in this case it's general enough:
I'm running a piece of code which gives the ClassCastException, with the error message I wrote as title. Here the mentioned cast is from an object of type java.lang.reflect.Type to Class<?>.
Apart from primitive types, which type in Java is not a class?
Thanks for your answers
A Class is a Type but a Type isn't necessary a Class, since Class implements Type.
Basically, your myType could also be any of the implementing classes of the interfaces GenericArrayType, ParameterizedType, TypeVariable or WildcardType, since they all extend the Type interface.
Try to print myType.getClass() to see the type you mean: you'll get Class<TheSaidType>.
From the Javadoc for Type you can see it has a number of implementing types.
All Known Subinterfaces:
GenericArrayType, ParameterizedType, TypeVariable<D>, WildcardType
All Known Implementing Classes:
Class
Th sub-interfaces are implemented using internal data structure classes.

Getting the .class of a generic class

Suppose you have a certain class C, which supports generics (so C<X> defines a type). I would like to do something like:
I'd like to obtain an instance of the Class<C<X>> class. I would say that this can be obtained through the following expression:
C<X>.class
But the compiler doesn't agree with me on that :P
Any hint?
This is not possible because of type erasure. The type parameters are not available at runtime - all the instances of C<Whatever> are actually instances of simply C. Therefore, you can only write a class literal like C.class.
However, if you subclass a generic class with defining a concrete type parameter, such as this:
class StringC extends C<String> {}
... it is actually possible to obtain the value of the type parameter (which is String) via reflection. See these blogs:
http://gafter.blogspot.cz/2006/12/super-type-tokens.html
http://www.artima.com/weblogs/viewpost.jsp?thread=208860
The closest you can get is
#SuppressWarning("unchecked")
Class<C<X>> cxClass = (Class<C<X>>) (Class) C.class
As generics are a compile time feature, this doesn't really do much as you can see.

Why do all enums extend enum<e>

Isn't it impossible to extend a generic type with an undefined type parameter ex:
class Foo extends enum<E>
How do they extend it?
edit: also where is the values() method defined?
Thanks in advance
It is indeed illegal to extend a generic type with an undefined type parameter. However, enums don't do that. If you're decompiling some java code and saw a <E> there (And your enum type is not named E), your decompiler isn't processing generics properly.
An enum implicitly extends Enum<YourEnumType>. That is, implicitly the compiler generates a class YourEnumType extends Enum<YourEnumType>. By passing down its own type, it allows Enum's compareTo and valueOf functions to reject values from different types of enums.

Categories

Resources