Coming from C++, some Java code looks very strange to me. Can someone explain to me what the following code fragment is supposed to do?
#SuppressWarnings("unchecked")
private static <T> Class<T> getGenericType(Class<?> clz) {
return (Class<T>) ((ParameterizedType) clz.getGenericSuperclass())
.getActualTypeArguments()[0];
}
I read this in a response to another question (see here) which I am trying to understand in detail.
Suppose you have a generic class Foo, like so:
public class Foo<T> {
T myVar;
}
In a lot of ways, this is like a template in C++. T is some type, could be String, could be Integer, could be Object, could be SomeTypeYouveNeverHeardOf, all depending on the code that uses Foo, not the code inside Foo.
And a subclass of it, Bar:
public class Bar extends Foo<String> {}
Bar is not a generic class, though it uses one as its superclass. It specifies that, for all instances of Bar, the type variable T is actually String, so the myVar instance variable it inherits from Foo will always be a String.
Now with that setup out of the way, let's turn to your method.
First, it takes a Class object as its parameter. Let's say we call it with Bar.class. The first thing your method does is call getGenericSuperclass() on it, which retrieves an object representing its superclass - Foo<String>.
Now, getGenericSuperclass() is declared to return a Type object, but the code is assuming that the class passed in has generic inheritance (that is, that it extends something like Foo<String> rather than just Foo), and in that case it will actually return a ParameterizedType. So it type casts it and calls getActualTypeArguments() to retrieve what the type arguments are - the String part of extends Foo<String>. This is returned as an array because in the more general case it could be dealing with things like extends ComplexObject<String, Integer, Foo, Object>.
Having acquired a size 1 array of Class objects, it then returns the array's first member. In this example, the returned value is String.class.
What this method does on my system, now that I test it, is throw an exception at runtime. So I guess what it does is "nothing useful."
public class GenericTest
{
public static void main( String[] args )
{
ArrayList<String> al = new ArrayList<>();
System.out.println( getGenericType( al.getClass() ) );
}
#SuppressWarnings( "unchecked" )
private static <T> Class<T> getGenericType( Class<?> clz )
{
return (Class<T>) ( (ParameterizedType) clz.getGenericSuperclass() )
.getActualTypeArguments()[0]; // line 28
}
}
run:
Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
at quicktest.GenericTest.getGenericType(GenericTest.java:28)
at quicktest.GenericTest.main(GenericTest.java:21)
C:\Users\Brenden\AppData\Local\NetBeans\Cache\8.1\executor-snippets\run.xml:53: Java returned: 1
BUILD FAILED (total time: 2 seconds)
Related
public class Foo<T extends Bar>{
private Class<T> _type;
public Foo( Class<T> _type ){
this._type = _type;
}
public Collection<T> hypothetical( List<T> items ){ //PROBLEMATIC
return dostuffWithItems( items );
}
}
Usage:
Foo<? extends ChildBar> foo = new Foo<ChildBar>( ChildBar.class );
List<ChildBar> items = ( List<ChildBar> ) foo.hypothetical( new ArrayList<ChildBar>() ); //COMPILER ERROR: The method hypothetical(List<capture#2-of ?>) in the type Foo<capture#2-of ?> is not applicable for the arguments (List<ChildBar>)
The compiler would either accept
casting List<ChildBar> items argument to List<?>
or changing the hypothetical( List<T> items ) signature to either
a) hypothetical( List<ChildBar> items ) or
b) hypothetical( List<? extends Bar> items )
However, none of the alternatives assure that the hypothetical method's List items argument T type is the equivalent runtime type of the Foo class T parametric type. I am currently using an extra method to verify the parametric types at the moment.
Is there a better way within Java generics constructs to achieve this automatically without the extra logic? Or better yet, why can I not declare foo as Foo<? extends Bar> and then fill in the actual type parameter at runtime?
I edited your code and added the missing stuff to make it compilable, and I can confirm that the only problematic parts are:
The missing dostuffWithItems method.
The typos with the hypothetical method name.
Assigning a Collection<ChildBar> to a List<ChildBar>.
The first two are easy to fix.
The last one requires you to either change the change the API method, or change the code where you are calling it. Neither of these is (IMO) problematic. Furthermore, the
It is worth noting that you would get all of these errors if the types were non-generic. You can't assign a Collection to a List without a typecast.
Here's my code for you to play with. (Copy and paste into appropriately named files ...)
public class Bar {
}
public class ChildBar extends Bar {
}
import java.util.*;
public class Foo<T extends Bar> {
private Class<T> _type;
public Foo( Class<T> _type ) {
this._type = _type;
}
public Collection<T> hypothetical( List<T> items ) {
return items; // dummy implementation ...
}
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Foo<ChildBar> foo = new Foo<ChildBar>( ChildBar.class );
Collection<ChildBar> items =
foo.hypothetical( new ArrayList<ChildBar>() );
}
}
The accepted answer doesn't precisely explain why the snippet in the question (after edits) is rejected by the compiler.
We start from the observation that the snippet from #Stephen C's answer is accepted, while revision 8 of the question is rejected. The difference is: in the latter version the variable foo is declared with a wildcard-parameterized type Foo<? extends ChildBar>, while Stephen C had copied Foo<ChildBar> from an earlier revision (we all seem to agree that this is a suitable way to resolve the compile error).
To understand why this difference is crucial please see that with Foo<? extends ChildBar> foo this wildcard propagates as a capture into the signature for the invocation of foo.hypothetical, so this invocation is rendered as hypothetical(List<capture#2-of ?>), meaning that the parameter has an unknown (upper-bounded) type parameter. List<ChildBar> is not compatible to that type, hence the compile error.
Also note that all mentions of "runtime" in this thread are inappropriate, all this is statically resolved at compile time. Perhaps you meant invocation type, or type of the actual argument, as opposed to the declared type (of the formal parameter). The actual runtime type is unknown to the compiler.
This seems to be currently impossible in Java.
Foo<? extends ChildBar> foo = new Foo<ChildBar>( ChildBar.class );
This leave foo with an ambiguous parametric type. It is obvious that ChildBar would become the true de facto parametric type. The call to the foo.hypothetical() method with the List<ChildBar> exposes this assumption to be untrue. Although foo.hypothetical only accepts a List<> argument containing elements of the foo parametric type, it still fails to recognize that the argument was a list of ChildBar objects.
For this use case, the object parametric type must be specified during foo declaration in order make it a part and parcel of the foo runtime reference.
Foo<ChildBar> foo = new Foo<ChildBar>( ChildBar.class );
All conforming List<ChildBar> arguments of the foo.hypothetical method will now correctly be accepted as carrying elements of the foo's declared parametric type.
So, I am delving into Java and curious about this type parameter usage.
<T>T getInstance
and then the arg
Class<T> type
I am a little confused here because if we require a return type, thus denoted by T then why isn't the arg the same... for instance
private static String getInstance(String arg)
So I'd figure it would be
private static Class<T> getInstance(final Class<T> type)
so, I am confused why the difference in expression of return type vs. argument
There is no need to have the return type the same as the parameter type and by no means any rule that dictates that.
When a method is defined as
private static <T> T getInstance(final Class<T> type)
it means that the return object will be of type T, whereas the argument passed to the method is an instance of the generic java.lang.Class type parameterized to T.
This means the method may be invoked as follows:
String string = getInstance(String.class);
Hence this method takes an instance of type Class and returns an object of the type corresponding to this Class argument.
On the other hand, when the method is defined as
private static <T> T getInstance(final T type)
then you are forced to pass an object of type T in order to get the instance. Imagine it will be called as follows:
String string = getInstance("a");
Notice how the object "a" of type String is quite different than String.class of type Class.
T and Class<T> are totally different.
The first says, "an object of some type, T." The second says, "an object of type java.lang.Class, which represents the class for some type T."
Put another way, here are two possible implementations:
Class<T> getInstance(Class<T> type) {
return type;
}
T getInstance(Class<T> type) {
return type.newInstance();
}
For instance, if T is a String, then the first of those will return String.class, and the second will return an empty string, "".
Think of what the method does: it returns an instance from a Class.
Usage:
final String string = getInstance(String.class);
So what is the return - well it's String. And what is the argument - it's the class String, which is represented by Class<String>.
So the method signature becomes:
String getInstance(Class<String> string);
Parameterising out the String as T gives you the signature in your question.
This is a trick that Java has implemented to combat the chicken-and-egg problem when you must create an object inside a type-erased generic method.
Class<T> is made generic so that you could call getInstance in a type-safe manner. Without <T> in the Class all of your Ts would get erased, leaving you with
Object getInstance() {...}
and no way to get a reference of the class T, which has been erased.
Passing Class<T> solves this problem, because now the erased signature looks like this:
Object getInstance(Class cl) {...}
Although the type is erased again, now you have a Class object, which can be used as a "factory" to make new objects of class T. The fact that Class<T> is generic on the type that it creates lets Java compiler perform type checking, ensuring that the cast inserted implicitly by the compiler is going to succeed at runtime.
You should distinguish a class from its instance. It can be tricky because in Java classes are also objects, and as such they also have a class (the class of the class!). Say:
class Foo { ... }
An instance of Foo has type Foo;
The class Foo itself is the (only) instance of another class, precisely Class<Foo>.
So in the above declaration, from left to right:
<T> is the generic parameter, making the method a generic method;
T is the return type: The method returns an instance of class T;
getInstance is the name of the method;
Class<T> means that you must pass as parameter the (only) instance of the class T, that itself has class Class<Foo>.
You can access such singleton instance by the implicit static field Foo.class. Every declared class has it, although you will not find it in the source code (tricky reflection issues).
Finally, why Class is generic? Well, to have something like that:
package java.lang;
public final class Class<T> {
public static T newInstance();
...
}
so Foo.class.newInstance() returns a Foo, Baz.class.newInstance() returns a Baz, and so on. Neat, isn't it?
In this code, why can type not be declared as Class<? extends B>?
public class Foo<B> {
public void doSomething(B argument) {
Class<? extends Object> type = argument.getClass();
}
}
This problem is that Java's syntax doesn't allow getClass() to say it's returning a type which matches the class its defined in, and this is not a special case as far as the compiler is concerned. So you are forced to cast the result.
There are many cases where you would like to be able to specify this type, e.g. for chaining, so I would hope they include this feature one day.
You could write
Class<? extends this> getClass();
or
public this clone(); // must return a type of this class.
or
class ByteBuffer {
this order(ByteOrder order);
}
class MappedByteBuffer extends ByteBuffer {
}
// currently this won't work as ByteBuffer defines order()
MappedByteBuffer mbb = fc.map(MapMode.READ_WRITE, 0, fc.size())
.order(ByteOrder.nativeOrder());
This is all about generic type erasure. From here:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods. [at compile time]
So you cannot get Class of actual type of B but only ? or ? extends Object.
If your bounds will be turn into <B extends SomeClass> instead of <B> only then you can fetch Class object of type <? extends SomeClass>.
Object.getClass() is defined to return a Class, where T is the statically known type of the receiver (the object getClass() is called on). Take special note of the vertical bars, the erasure operator. The erasure of a type variable is the erasure of its leftmost bound. In your case that's the implicit bound Object. So you get back a Class, not a Class<? extends T>.
The right way to do it is,
abstract class AbstractExecutor<E> {
public void execute() throws Exception {
List<E> list = new ArrayList<E>();
Class<E> cls = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
E e = cls.getConstructor(String.class).newInstance("Gate");
list.add(e);
System.out.println(format(list));
}
// ...
}
Because the class of a given object is not guaranteed to be the same as the type it is stored in.
eg.
Object o = "some string";
Class<Object> clazz = o.getClass(); // actually Class<String>
By looking at the type you should expect the Class for Object, but in reality you get the class for String. What problem is this you might ask -- Object is a superclass of String, so String implements all the methods implemented by Object.
Problems
The problems are that when getting a Field the class will return the fields of the actual class and not the generic type. In addition, whilst Method is able to invoke the correct method if there is an overriding method in the given object, it is not able to do the reverse and find an implementation of the method that will work on the given object.
For instance, Object declares hashCode, so all objects have a hash code method. However, the following will produce a runtime exception:
Object.class.getMethod("hashCode").invoke("some string"); // works
String.class.getMethod("hashCode").invoke(new Object()); // fails
This is because the Method object for hashCode is expecting a String. It's expecting to generate a hash code from the sequence of characters, but the provided object does not have a char array for the method to work on, so it fails.
Meaning the following looks like it should work, but won't because the actual method returned by getMethod is the hash code method for String.
Object obj = "string";
Class<Object> clazz = obj.getClass();
clazz.getMethod("hashCode").invoke("another string");
This question already has answers here:
Get generic type of class at runtime
(30 answers)
Closed 4 years ago.
I have a small problem in java while using genericity. I have a class A :
public class A<T>
In a method of A, I need to get the type name of T.
Is there a way to find the string s using T ?
(If I create A<String> temp = new A<String>();, I want to be able to get java.lang.String at one point - I have to use genericity because one of my methods will have to return a List<T>).
This seems quite easy but I do not see how to do it.
You can't do this in general because of type erasure - an instance of A<String> doesn't know the type of T. If you need it, one way is to use a type literal:
public class A<T>
{
private final Class<T> clazz;
public A<T>(Class<T> clazz)
{
this.clazz = clazz;
}
// Use clazz in here
}
Then:
A<String> x = new A<String>(String.class);
It's ugly, but that's what type erasure does :(
An alternative is to use something like Guice's TypeLiteral. This works because the type argument used to specify a superclass isn't erased. So you can do:
A<String> a = new A<String>() {};
a now refers to a subclass of A<String>, so by getting a.getClass().getSuperClass() you can eventually get back to String. It's pretty horrible though.
You can get the name of the generics from the subclass. See this example.
We Define a parent class like this:
public class GetTypeParent<T> {
protected String getGenericName()
{
return ((Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]).getTypeName();
}
}
We then define its child class in this way:
public class GetTypeChild extends GetTypeParent<Integer> {
public static void main(String[] args) {
GetTypeChild getTypeChild = new GetTypeChild();
System.out.println(getTypeChild.getGenericName());
}
}
You can see that in the main method, or in any instance method, I am capable to get the name of the generics type, in this case the main will print: java.lang.Integer.
Short answer: Impossible.
Slightly longer answer: Once your code is compiled, the type parameters is discarded.
Thus, Java cannot know what you set there.
You could, however, pass the class in question to your object and operate on it:
public class Example<T> {
private final Class<T> clazz;
public Example(Class<T> clazz){
this.clazz = clazz;
}
...
}
As is normally the case, Apache has a solution for this one with TypeUtils:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/TypeUtils.html
A quick example from the above question:
TypeUtils.getTypeArguments(temp.getClass(), A.class).get(A.class.getTypeParameters()[0])
Disclaimer: I did not attempt building this first, but have used this utility in a similar fashion in the past.
Generics in Java are implemented by erasure, so no, you won't be able to get the name of the "type" which was used to create your generic collection at run-time. Also, why not just inspect the elements to know what type it belongs to?
If you're doing it in a subclass which has it's parent class defining the generic type, this is what worked for me:
// get generic type class name
String name = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].toString();
// then when you've got the name, you can make the Class<T> object
Class.forName(name.replace("class ", ""))
Reason why I couldn't do it with #getClass() instead of #toString() in the first snip is that I was always getting the "Class" class, which is useless to me.
I was wondering what is the difference between the following two method declarations:
public Object doSomething(Object obj) {....}
public <T> T doSomething(T t) {....}
Is there something you can/would do with one but not the other? I could not find this question elsewhere on this site.
Isolated from context - no difference. On both t and obj you can invoke only the methods of Object.
But with context - if you have a generic class:
MyClass<Foo> my = new MyClass<Foo>();
Foo foo = new Foo();
Then:
Foo newFoo = my.doSomething(foo);
Same code with object
Foo newFoo = (Foo) my.doSomething(foo);
Two advantages:
no need of casting (the compiler hides this from you)
compile time safety that works. If the Object version is used, you won't be sure that the method always returns Foo. If it returns Bar, you'll have a ClassCastException, at runtime.
The difference here is that in the first, we specify that the caller must pass an Object instance (any class), and it will get back another Object (any class, not necessarily of the same type).
In the second, the type returned will be the same type as that given when the class was defined.
Example ex = new Example<Integer>();
Here we specify what type T will be which allows us to enforce more constraints on a class or method. For example we can instantiate a LinkedList<Integer> or LinkedList<Example> and we know that when we call one of these methods, we'll get back an Integer or Example instance.
The main goal here is that the calling code can specify what type of objects a class will operate upon, instead of relying on type-casting to enforce this.
See Java Generics* from Oracle.
*Updated Link.
The difference is that with generic methods I don't need to cast and I get a compilation error when I do wrong:
public class App {
public static void main(String[] args) {
String s = process("vv");
String b = process(new Object()); // Compilation error
}
public static <T> T process(T val) {
return val;
}
}
Using object I always need to cast and I don't get any errors when I do wrong:
public class App {
public static void main(String[] args) {
String s = (String)process("vv");
String b = (String)process(new Object());
}
public static Object process(Object val) {
return val;
}
}
You don't need to do additional class casting. In first case you will always get an object of class java.lang.Object which you will need to cast to your class. In second case T will be replaced with the class defined in generic signature and no class casting will be needed.
At runtime, nothing. But at compile time the second will do type checking to make sure the type of the parameter and the type of the return value match (or are subtypes of) whatever type T resolves to (the first example also does type checking but every object is a subtype of Object so every type will be accepted).
T is a generic type. Meaning it can be substituted by any qualifying object at runtime. You may invoke such a method as follows:
String response = doSomething("hello world");
OR
MyObject response = doSomething(new MyObject());
OR
Integer response = doSomething(31);
As you can see, there is polymorphism here.
But if it is declared to return Object, you can't do this unless you type cast things.
in the first case it takes a parameter of any type e.g.string and return a type foo. In the second case it takes a parameter of type foo and returns an object of type foo.
There are few reasons that you can consider Generics over Object type in Java:
Generics is flexible and safe. At the same time, working with Object that requires type-casting is error-prone
Type Casting in Java is slow
ref : [1]: https://www.infoworld.com/article/2076555/java-performance-programming--part-2--the-cost-of-casting.html