Get "real" class of generic type - java

How can I get the "real" class of a generic type?
For Example:
public class MyClass<T> {
public void method(){
//something
System.out.println(T.class) //causes a compile error, I wont the class name
//something
}
}
If T = Integer
Output:
java.lang.Integer
If T = String
Output:
java.lang.String
Thanks

If you have a instance variable of type T in your class, and it happens to be set, then you could print the class of that variable.
public class Test<T> {
T var;
public static void main(String[] args) {
Test<Integer> a = new Test<Integer>();
System.out.println(a.boo());
a.setVar(new Integer(10));
System.out.println(a.boo());
}
public String boo() {
if (var == null) {
return "Don't know yet";
}
return var.getClass().getSimpleName();
}
public void setVar(T var) {
this.var = var;
}
public T getVar() {
return var;
}
}

You can't. The information is stripped from the code at compile time, a process that is known as type erasure. For more, please look here: Type Erasure
edit: sorry my bad, the information is not loaded at run time.

As others have explained, you cannot do it in that fashion but this is how it's usually achieved in java.
public class MyClass<T> {
public void method(Class<T> clazz) {
// something
System.out.println(clazz.getName());
// something
}
}
and you use it like this
new MyClass<String>().method(String.class);

In the case of your situation, you can't. However, you might be able to use Super Type Tokens for this type of thing: http://gafter.blogspot.com/2006/12/super-type-tokens.html
An example implementation of these is the TypeReference class of the Jackson json processing library.
This is advanced stuff and probably more than you wanted to know ;-)

Note that approaches relying on 'getClass()' on an instance received with a generic type will get the actual type of that object, which is not necessarily the generic type - which would be the type by which the caller knew the instance.
For example, consider the case where the caller handles an object by an interface; when passing to generic constructs, the generic type will be the interface, not the instance's actual class.
Consider the following example "Pair" class, which allows two object references to be returned through a POJO:
public class Pair<U,V>
{
public final U first;
public final V second;
public static <U,V> Pair<U,V> of (U first, V second)
{
return new Pair<U,V> (first, second);
}
protected Pair (U first, V second)
{
this.first = first;
this.second = second;
}
}
We were considering how to modify the 'Pair.of()' factory function to return a Comparable Pair derived class, if U and V were both Comparable. However, while we can tell whether 'first' and 'second' are comparable using instanceof, we don't know that 'U' and 'V' are themselves comparable.
For this to work, the exact type of Pair returned by Pair.of() must depend on the generic types, not the actual argument types.

Related

Java Generics with Static Factory methods

I'm trying to create a Variable class that can represent either an Integer or Double value using generics.
Below is the code that I have tried. Because of erasure I use an enum to store the intended type of the Variable and then try and use this to initialise the value to the correct type.
public class Variable<T> {
private enum Type {INTEGER, DOUBLE};
private Type type;
private T value;
public static Variable<Integer> createAsInteger() {
return new Variable<Integer>(Type.INTEGER);
}
public static Variable<Double> createAsDouble() {
return new Variable<Double>(Type.DOUBLE);
}
private Variable(Type type) {
this.type = type;
if(type == Type.INTEGER) {
value = new Integer(0);
} else {
value = new Double(0.0);
}
}
public static void main(String[] args) {
Variable.createAsInteger();
Variable.createAsDouble();
}
}
However when I compile it I get the following message...
error: incompatible types: Integer cannot be converted to T
value = new Integer(0);
and likewise for the Double.
Can anyone explain why this is happening and if there is a way round this without having to write two separate classes, one for Integer and one for Double?
Edit
Thanks for all your answers...based on them I now realise there are better ways of doing this. However I'm trying to get my head round why this approach isn't working so that I don't make the same mistake in the future.
When I define my class as public class Variable<T extends Number> as suggested, I still get the same error.
Your architecture seems to defile the concept of generics.
The simplest way would be to have an upper bound in your type parameter:
class Variable<T extends Number> {...}
Then you can have a generic factory method creating a Variable<X> based on your required class:
static <X extends Number>Variable<X> create() {
return new Variable<X>();
}
You can then invoke it as:
Variable.<Integer>create(); // returns an instance of `Variable<Integer>`
This will not limit to Integer and Double, but rather any Number.
If you have to, you can limit those choices by performing the following:
Add a parameter to your create method: create(Class<X> clazz)
Check the value of your clazz argument within the method's body:
if (!clazz.equals(Integer.class) && !clazz.equals(Double.class)) {
// TODO complain
}
Otherwise, you can ensure you use a private constructor and provide static createAs... non-generic methods such as createAsInteger etc., that would return a new Variable<Integer> etc.
The problem here is that T can be anything. What if T was for instance String, your code would amount to:
String value = new Integer(0);
You could lay out your factory methods like this:
public static Variable<Integer> createAsInteger() {
return new Variable<>(new Integer(0), Type.INTEGER);
}
Where you have a constructor like:
private Variable(T value, Type type) {
this.value = value;
this.type = type;
}
You get the error because you are typizing a method inside a generic class. You can't define some inside the T generic class.
By the way you are mistaking the design pattern.
You have to design a generic class for Variable, also the constructor must have T as argument type.
In an other class you implement the factory with the createInteger and the createDouble methods.
You can make your class inherit from Numbers and use type checking to invoke appropriate method for Integer or Double.
public class Variable<T extends Number> {
public static Variable<T extends Number> Variable<T> create(Variable<T> var){
if (var instanceOf Integer){
// Take appropriate action
}
else if (var instanceOf Double){
// Take appropriate action
}
}
}
By this, there is no peculiar need of maintaining a separate enum for Types.

Java Generics & Return Types

I am curious as to how you return a generic data type from a function without casting. It seems that the whole point of generics was to remove the need for casting with collections and those compile-time errors that arose from it.
Yet with a method of say this signature:
public E get( K key )
I cannot return type E without doing a cast from another type, e.g. return (E) "test";
Doesn't this defeat the entire purpose of using generics? What am I missing here. How do I return a variable of type E?
Yes you can do that using generic. here is a sample code:
public class Sample<E,K>{
Map<K, E> map = new HashMap(){{
put("key", "value");
}};
public static void main(String[] args) {
Sample<String,String> sample = new Sample<String,String>();
String val = sample.get("key");
System.out.println(val);
}
public E get( K key ) {
E e = map.get(key);
return e;
}
}
Generics are meant to improve re-utilization of your classes and/or methods when the object class being specified in the "template" has nothing or little to do with the functionality that the class class or the method itself provides.
The best example of this are data structures where your generic types are black boxes. You don't care about them, just aggregate them in some way and what is important is how you index,sort,find,traverse,... this objects.
The case you're proposing (return (E) "test";) is against that principle because you are building one of these objects and for that you need to know its class details.
Imagine you want to provide a class to represent pairs of objects. You don't care at all about the nature of these objects, you just want to provide a way of grouping to objects references. This is a typical case of use of generic types:
public class Pair<T,S> {
public T getFirst() {
return first;
}
public void setFirst(T first) {
this.first = first;
}
public S getSecond() {
return second;
}
public void setSecond(S second) {
this.second = second;
}
private T first;
private S second;
}
Pair has nothing to do with first or second beyond aggregating them.

Overloading / generics in Java

I want to run certain tests in Lists. The Lists can contain entirely different classes.
I have one method to check the consistency of the list - not null, not empty, no more than x elements. This is common to all the lists. Then I want to test each of the objects, using overloading.
The idea would be something like:
public static <T> void check(List<T> list) {
//do general checks
for (T element : list) {
check(element);
}
}
and then
public static void check(SomeType element) {...}
public static void check(SomeOtherType element) {...}
But I also had to add a method like this:
public static void check(T element) {...}
And this was called at runtime - not my other methods with the specific classes. Although the class was exactly the same. I'm evidently missing some generics understanding.
Now if I don't use the general method at all and try to solve it this way:
public static void check(List<SomeType> list) {...}
public static void check(List<SomeOtherType> list) {...}
Compiler error - "Method check(List) has the same erasure check(List) as another method..."
So is there any elegant solution for this? I could just use different method names but would like to know how it's possible without that.
Thanks!
This isn't something about generics that you're missing. Java does not have double dispatch. The call to check must be resolved at compile-time, and check(T) is the only match since the compiler can't tell if T is SomeType or SomeOtherType in a given scenario. It needs to choose one method to call that will work for all possible Ts.
This is sometimes solved using the visitor pattern.
The problem should be solved by the caller. When it instanciate your class with a concrete type for T, it should also pass an instance of Checker<T> with the same concrete type:
public class SomeClass<T> {
private List<T> list;
private Checker<T> checker;
public SomeClass(Checker<T> checker) {
this.checker = checker;
}
public void check() {
checker.check(list);
}
}
public interface Checker<T> {
public void check(List<T> list);
}
...
SomeClass<Foo> someClass = new SomeClass<Foo>(new Checker<Foo>() {
#Override
public void check(List<Foo> list) {
// do whatever you want here
}
});
You can use instanceof to dispatch:
public static <T> void check(List<T> list) {
for (T element : list) {
check(element);
}
}
public static void check(T t) {
if (t instanceof SomeType) {
SomeType someType = (SomeType) t;
// code for SomeType ...
} else if (t instanceof OtherType) {
OtherType otherType = (OtherType) t;
// code for OtherType ...
} else {
// we got a type that we don't have a method for
}
}
With generics, the type parameter is actually erased during compilation, and the list object don't know anything about the static type of the object it contains. Since it doesn't know it, it can not use overloading to call methods with different parameters, because Java doesn't support multiple dispatch.
You have then three choices:
Make your objects implement a Checked interface with a check method that does the check logic. Downside is that the check logic is now dispersed in several places and it is not practical if you have objects of classes you don't have control of.
Use instanceof to call explicitly the check methods according to the dynamic type of the object. Downside is you potentially end up with a big if/else block a bit harder to maintain.
Implement the visitor pattern. Downside is that you have to change the object classes too, but the check logic stay in a single place.
Since the type of the variable is lost in check(List<T> list) you have two options:
1. Do different things by checking runtime type
check(T element) {
if (element.getClass().equals(SomeType.class)) {
check((SomeType) element);
} elseif (element.getClass().equals(SomeOtherType.class)) {
check((SomeOtherType) element);
}
This can be made a little more sophisticated, for example by wrapping each check in a Callable and using a Map<Class, Callable>
This is similar to visitor pattern.
2. Calling a virtual method on the element to be checked itself
If the checking logic can be pushed to the object to be checked itself (this is not necessarily a bad thing) then you don't need to check types:
interface Checkable { void check(); }
class SomeType implements Checkable { .... }
class SomeOtherType implements Checkable { .... }
Then:
public static <T extends Checkable> void check(List<T> list) {
for (T element : list) {
element.check();
}
}
These are the only two options, any implementation has to be a variation on one of these

return type of generic methods

If I have a method, for instance
public INode getNode(final int offset);
I assume it doesn't add something to make the method return type generic, for instance:
public <T extends INode> T getNode(final int offset);
Or did I miss something? I think generic return types are only of value if one of the parameters is of the same type (or a super/subtype)?
public <T extends INode> T getNode(final int offset);
Not only does this not provide any additional information to the caller, but is outright dangerous: The only way to implement that method signature is to use an unchecked cast, which can not be type safe, because a method's type parameters are specified by its caller (explicitly or implictly through type inference), and the type parameters aren't available to this method's implementation. For instance, consider the following program:
class NodeCollection {
private INode[] nodes = new INode[42];
public <T extends INode> T getNode(final int offset) {
return (T) nodes[offset];
}
public <T extends INode> setNode(final int offset, T node) {
nodes[offset] = node;
}
}
class ANode implements INode {}
class BNode implements INode {
void foo();
}
public class Test {
public static void main(String[] args) {
NodeCollection nc = new NodeCollection();
nc.setNode(0,new ANode());
BNode b = nc.getNode(0); // throws ClassCastException (sic!)
}
}
Best practice: Don't use an unchecked cast, unless you are really sure it'll be type correct at runtime.
I think generic return types are only of value if one of the parameters is of the same type (or a super/subtype)?
There are more cases, for instance:
public <T> T getFavorite(Class<T> clazz) {
return clazz.cast(favorites.get(clazz));
}
or
interface List<E> {
E get(int index);
}
or the examples in Colin's answer, where the type variable merely appears as type parameter in the return type, which is acceptable due to type erasure.
Edit:
I think there's no type save way if one wants to cast to the exact type of node (instead of instanceof has to precede it)
Of course there is, it's called visitor pattern.
In the example you give, it doesn't really add any value except forcing the developer of the implementation to cast the return value (in T). (Unless it has a way to get a T value, but for that it would need to call another method which returns T, so you're just moving the cast a bit further.
So not really a good idea in the case you're showing us.
There are a few cases where the generic applied only to the return value can be useful. For example:
public static <T> Collection<T> generateCollection() {
return new ArrayList<T>();
}
This allows you to create an object Collection of T without having to do any cast.
Or if you want the developer doing the implementation to cast his object (mostly works when the said object uses generics), example from Collections:
public static final <T> Set<T> emptySet() {
return (Set<T>) EMPTY_SET;
}
Resources:
angelikalanger.com: Java Generics FAQs - Generic Methods

Knowing type of generic in Java

I have a generic class, says :
MyClass<T>
Inside a method of this class, I would like to test the type of T, for example :
void MyMethod()
{
if (T == String)
...
if (T == int)
...
}
how can I do that ?
Thanks for your help
You can't, normally, due to type erasure. See Angelika Langer's Java Generics FAQ for more details.
What you can do is pass a Class<T> into your constructor, and then check that:
public MyClass<T>
{
private final Class<T> clazz;
public MyClass(Class<T> clazz)
{
this.clazz = clazz;
}
public void myMethod()
{
if (clazz == String.class)
{
...
}
}
}
Note that Java does not allow primitives to be used for type arguments though, so int is out...
Because of type erasure you can't... mostly. But there is one exception to that. Consider:
class A {
List<String> list;
}
public class Main {
public static void main(String args[]) {
for (Field field : A.class.getDeclaredFields()) {
System.out.printf("%s: %s%n", field.getName(), field.getGenericType());
}
}
}
Output:
list: java.util.List<java.lang.String>
If you need the class object, this is how you generally handle it:
public <T> T createObject(Class<T> clazz) {
return clazz.newInstance();
}
ie by passing the class object around and deriving the generic type from that class.
Additionally to cletus one exception I've mine: super type tokens. The super type token will preserve the type information.
new Type<Set<Integer>>() {}
The type information can be retrieved with Class.getGenericSuperClass.
if (object instanceof String)
System.out.println("object is a string");
As it was already stated you can get only generics-related information available at the static byte code level.
It's possible to resolve type arguments values and check if one type may be used in place of another then.
if you have subclass B extends A that should match, too, the approach clazz == A.class. Doesn't work. You should then use A.class.isInstance(b) where b is an object of type B.
If you want to do different things for different types would it still be generic?

Categories