Getting the class of a Java generic, and interface implementation of generics - java

I'd like to make a class that looks basically like this:
public class MyClass<T implements Serializable) {
void function() {
Class c = T.class;
}
}
Two errors:
- I cannot call T.class, even though I can do that with any other object type
- I cannot enforce that T implements Serializable in this way
How do I solve my two generics problems?
Cheers
Nik

You can't get the type.
Generics are implemented using something called type-erasure.
When a generic type is instantiated,
the compiler translates those types by
a technique called type erasure — a
process where the compiler removes all
information related to type parameters
and type arguments within a class or
method. Type erasure enables Java
applications that use generics to
maintain binary compatibility with
Java libraries and applications that
were created before generics.
The essence of this is that the type information is used by the compiler and discarded, hence not available at runtime.
With regards to the enforcing T implements Serializable, you just need the following:
public class MyClass<T extends Serializable>)
{
public void function(T obj)
{
...
}
}
This is simply referring to the is a relationship, so an class that implements Serializable, is a Serializable and can be passed to function.

you do this:
public class MyClass<T implements Serializable) {
void function(Class<T> tc) {
...
}
}
Basically, you have to pass in the class at run time in order to see it. You could also do something like this:
public class MyClass<T implements Serializable) {
Class<T> ct;
public MyClass(Class<T> ct){this.ct = ct;}
void function() {
... //you know what the class is here
}
}
It's kind of annoying, but not really that big of a hassle overall.

Something along these lines should do it.
private Class<T> dataType;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
dataType = (Class<T>) paramType.getActualTypeArguments()[0];
} else if (type instanceof Class) {
dataType = (Class<T>) type;
}

You can't do T.class because java does not actually know which class T is at runtime.
All that information is lost at compilation.
To get the class object for T you can either call getClass() on an instance of T (if you have access to one) or require the user to pass the class object as an argument to function, like:
void function(Class<T> c)

This is not possible without tricks.
The Java Generics FAQ provides an idea for a workaround.

Related

An interface has two type parameters. Can I implement the interface with the two types being the same, such that they are then compatible?

This is an existing interface:
public interface MyInterface<T, U> {
public T foo(U u);
}
I want to implement this interface under the assumption that T and U are the same type. I thought maybe I could leave the type parameters in as they are, and then as long as I only ever instantiate this particular implementation with two of the same type, that it might work:
public class MyOuterClass<A> {
public class MyClass<T, U> implements MyInterface<T, U> {
#Override
public T foo(U u) {
return u; //error here
}
//even though in the only instantiation of MyClass, T and U are the same
private MyClass<A, A> myInstance = new MyClass<A, A>();
}
But, perhaps unsurprisingly, this doesn't work, as types T and U are incompatible.
So then I thought maybe I could change MyClass to specify that its types would always be the same, by changing it to something like MyClass<A, A> implements MyInterface<A, A> or similar, but I get errors saying that T is already defined.
Is there a way to implement MyClass so that its two types will be the same?
(I'm more of a C++ guy than Java, so sorry if I'm missing something fundamental about Java's generic's here.)
Your myclass needs to look like this:
public class MyClass<T> implements MyInterface<T, T> {
#Override
public T foo(T in) {
return in;
}
}
Let's review what your suggested class definition does:
public class MyClass<T, U> implements MyInterface<T, U>
In this code, T and U do two things each:
in the first occurance they define a type variable of your MyClass class
in the second occurance they specify the concrete type of the MyInterface class
Since inside the body of your class T and U are unbounded type variables (i.e. nothing is known about the actual types), they are assumed to be incompatible.
By having only a single type variable in your MyClass you make your assumption explicit: there's only a single type, and I'm using it for both types of the interface.
Last but not least: remember that the compilation of a type is complete once the source is fully handled. In other words: contrary to what C++ does, "instantiation" of a generic type ("template type" or similar in C++; Sorry for my rusty terminology) does not handle. MyClass<Foo> and MyClass<Bar> are the same type, as far as the JVM is concerned (only the compiler actually distinguishes them).
Define a single type parameter for MyClass:
class MyOuterClass<A> {
public class MyClass<T> implements MyInterface<T, T> {
public T foo(T u) {
return u;
}
}
// Need only one 'A' here.
private MyClass<A> myInstance = new MyClass<A>();
}
When you say
public class MyClass<T> implements MyInterface<T, T> {
... you are defining one generic variable for MyClass and you are saying that it fulfills both the roles T and U in MyInterface.

How to convert generic parameter to a class

public abstract class BaseDaoImpl<E extends AbstractEntity> implements BaseDao<E> {
.....
public BaseDaoImpl() throws DataAccessException {
logger = LoggerFactory.getLogger(E); <<-- error here.
}
In the above code I get a error in the call to getLogger(E).
E cannot be resolved to a variable
This makes sense, but getLogger(E.class) (or variants thereof) does not work either.
I don't want to pass the literal class in the constructor, so a solution like changing the the constructor header to:
public BaseDaoImpl(Class<E> clazz) ... is not an option.
How do I get the class type from E?
Note that the answers to: How to get class of generic type when there is no parameter of it?
do not help.
Without changing the constructor you can't learn anything about E at runtime that you didn't already know statically. That's because in Java, there just simply isn't any runtime effect of a generic parameter -- the compiler literally erases all references to E in the code it generates. So if you want code that can tell what class its type parameter is being instantiated with, you have to add in some kind of argument (e.g. a Class object) yourself. There's just no way around it.
It is possible by reflection as pointed out by #CorayThan . A simple way to do it is from method signature
interface BaseDao<E>
E find(long id);
class FooDao implements BaseDao<Foo>
Foo find(long id)
So type E can be found through
this.getClass().getDeclaredMethod("find", long.class).getReturnType();
However, it is a very good option to pass a Class in the constructor. Because the constructor is not meant to be called by user codes, the verbosity is not an issue here.
abstract class BaseDaoImpl<E>
BaseDaoImpl(Class<E> clazz)
class FooDao extends BaseBaoImpl<Foo>
FooDao()
super(Foo.class);
// usages:
BaseDao<Foo> fooDao = new FooDao(); // clean & simple API
Because generics are implemented in the Java language using type erasure, you cannot do anything that would require runtime type information. See this page for more info.
This works for me.
public abstract class BaseDaoImpl<E extends AbstractEntity> implements BaseDaoImpl<E> {
protected final Class<E> type;
public BaseDaoImpl() {
this.type = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public Class<E> getType() {
return type;
}
public BaseDaoImpl() throws DataAccessException {
logger = LoggerFactory.getLogger( getType() );
}
}
Already been answered.
Basically, you can't unless you use reflection.
I wouldn't recommend using reflection, but if you want to, you should be able to use:
GenericClass.class.getTypeParameters()

Java generic programming with unknown generic type of interface

I'm using several interfaces with generics types. While combining it together I have some problems when I have to use them from a part of the code that is unaware of the concrete type of the generic parameter.
Suppose I have the following interface:
public interface MyObjectInterface<T extends Number> {}
The object implementing that interfaceare stored in a generic collection with the same generic type:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
Concrete instances of MyCollectionInterface hold several MyObjectInterface of the same generic parameter:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
Now, I have several questions on how to use these generic interfaces from a client class that is
(and must be) unaware of the concrete type of generics.
Suppose I have the following class:
public class ClientClass{
private MyCollectionInterface<?> collection; //1st possibility
private MyCollectionInterface collection; //2nd possibility
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //this doesn't compile
}
public void foo(MyObjectInterface<? extends Number> o){
this.collection.updateObject(o); //this doesn't compile either
}
public void bar(MyObjectInterface o){
MyObject b = o; //warning
this.collection.updateObject(o); //this compile but with warnings
}
}
First Question :
Considered the fact that ClientClass doesn't care of which concrete type extending Number is the collection, should I declare collection with or without "?" ? If I use the second version I get the following warning:
MyCollectionInterface is a raw type. References to generic type
LatticeInterface should be parameterized
Second Question :
Why method foo doesn't compile?
Third question:
It seems that I need to use bar signature to call updateObject method. Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. Can I remove this warning?
Last questions:
Am I doing something weird with this generic interfaces and I should refactor my code?
Do I really have to care about all these warnings?
How can I use safety a generic interface from a class where I don't know its concrete type?
Ok, I played a bit with your code and reached a conclusion.
The problem is that your ConcreteCollection (and its interface MyCollectionInterface) declare the method updateObject as receiving an argument of type MyObjectInterface<T> (where T extends Number) - note that the type is a concrete one (not a wildcard).
Now, in your client class you are receiving a collection and storing it as MyCollectionInterface<?> but the instance that is passed to ClientClass' constructor will be of a concrete type, for instance:
new ClientClass(new ConcreteCollection<Integer>());
This means that the method updateObject of that instance would only accept an argument of type MyCollectionInterface<Integer>.
Then, in method foo you are trying to pass a MyObjectInterface<?> to updateObject, but since the compiler doesn't know which generic type your collection accepts (it could be Integer like in my example but it could also be Double or any other type that extends Number), it won't allow any object to be passed.
Long story short, if you declare your reference as MyCollectionInterface<?> you won't be able to call updateObject on it. So you have two choices:
1) Pick a concrete type and stick with it:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
But then you are limiting the collections you can receive in your constructor (which may not be a bad idea), or:
2) Modify your interface to accept a wildcard type:
public interface MyCollectionInterface<T extends Number> {
public void updateObject(MyObjectInterface<? extends Number> o);
}
public class ConcreteCollection<T extends Number> implements MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<? extends Number> o) {}
}
private MyCollectionInterface<?> collection;
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //compiles
}
Also, note that even in 2) you could still run into the same problem in your implementation of the updateObject method unless you declare your list something like this (with ArrayList for example):
List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
In which case you could as well remove the <T extends Number> from MyCollectionInterface and ConcreteCollection since T isn't used anymore.
#Your last questions:
1) Probably yes
2) You should
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether.
Sorry for the long answer, hope this helps.

How to pass a parameterized class as an argument

My goal is to develop a class that can output an object of a specified class.
public class GetMe<T> {
public T get() {
Object obj = generateObject();
return (T) obj;
}
}
Now, I know this isn't possible due to erasure. So, we can pass in a class instance and use that to cast.
public class GetMe<T> {
public GetMe<T>(Class<T> clazz) {
this.clazz = clazz;
}
public T get() {
Object obj = generateObject();
return clazz.cast(obj);
}
}
This works great! As long as the class isn't parameterized. If it is, then I've got a problem.
I'm not allowed to use List<String>.class. If I pass in a ParameterizedType (which in itself is difficult to generate), there's no cast method to use.
Is there a way out of this quagmire?
I think super type tokens may solve this problem for you.
The problem with List<String> is that, because of erasure, it would at runtime indistinguishable from any other List<?>. The easiest way around this is to create a new class or interface which has the generic part "fixed", like
public interface StringList extends List<String> {
/* nothing to see here */
}
This way you have a type token (the StringList.class object) which you can pass around at runtime and specifies exactly what you want, but without the need for generics at runtime.
Here is just a small idea. I'm not really sure if it will fit in your context but nevertheless:
public class GetMe<T>
{
public List<T> getList() {
#SuppressWarnings("unchecked")
List<T> result = (List<T>) new LinkedList();
return result;
}
}
Cheers!
The first problem is how you plan to instantiate a List object. If you disclose more of what you are trying to build, we may be able to help you better.
You may want to use Type instead of Class. Type can represent all generic types, although it's not pleasant to work with.
abstract public class GetMe<T>
{
Type type;
public GetMe<T>(Type type)
{
this.type = type;
}
}
Another problem is how to create a generic type like List<String>. The "super type token" looks neat in syntax, in reality it's basically
static class XX extends TypeReference<List<String>>{}
....
Type typeListString = Util.extract(XX.class);
I would much prefer this way
List<String> f;
Type typeListString = getDeclaredField("f").getGenericType();
Actually, many of these frameworks that do fancy runtime generic magics are working on instance fields only.
I think the confusion comes from the fact that you're trying to create an object from List<> which in face it an interface, not an object.
So no matter what you'd try, you just can't create an instance of List<> , (interfaces aren't actual classes, and don't have constructors)
Try using a constraint to avoid having interfaces put in the declaration:
public class GetMe<T extends Object>
This will guarantee that T is an actual class and not an interface.

Difference between Java Generic Parameters

What is the difference between passing in generic parameter some generic class with and without his generic parameter?
Example:
Simple Generic class:
public class Foo<T> { /*...*/ }
Simple class that extend simple generic class setting the generic parameter to some irrelevant type:
public class FooFoo extends Foo<Type1> { /*...*/ }
Another generic class
public class Bar<T> extends FooFoo { /*...*/ }
Our base class that as generic parameter need something that extends class Foo
public class TestFooClass<T extends Foo<?>> { /*...*/ }
And the question what is the deference between this two parameters
public class BarTestOne extends TestFooClass<Bar> { /*...*/ }
public class BarTestTwo extends TestFooClass<Bar<?>> { /*...*/ }
Problem
Class<T> class = (Class<T>) ((Foo)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
In the first case code works in the second doesn't.
It looks like you are trying to determine the actual type that the TestFooClass is parameterized with?
In that context, the difference between using generic class with and without its generic parameter is that getActualTypeArguments()[0] will:
In the first case provide an instance of Class representing the raw type
In the second case provide an instance of ParameterizedType (thus one may get ClassCastException). If you call getRawType() on that ParameterizedType, you will get Class representing the raw type.
This:
BarTestOne one = new BarTestOne();
BarTestTwo two = new BarTestTwo();
Class<?> clazz1 = (Class<?>) ((ParameterizedType) one.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
Class<?> clazz2 = (Class<?>) ((ParameterizedType) ((ParameterizedType) two.getClass().getGenericSuperclass()).getActualTypeArguments()[0]).getRawType();
System.out.println(clazz1.equals(clazz2));
This will return true.
Alas, any deeper answer is beyond my knowledge of generics.
Bar means Bar<Object> and Bar<?> doesn't. For example, if you have a List, you can add to it, if you have a List<?> you can't, because the compiler doesn't know if your object is compatible with the "actual generic type" of the object.
As for the reflection code, I don't know. It says getClass(), which depends on the object you call it on; in this case the object is obviously this... From where is this code called?

Categories

Resources