Ed Thomas
Ed Thomas

Reputation: 1191

Why doesn't Class have a nice generic type in this case?

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();
    }
}

Upvotes: 10

Views: 202

Answers (4)

Peter Lawrey
Peter Lawrey

Reputation: 533530

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());

Upvotes: 4

Dunes
Dunes

Reputation: 40713

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");

Upvotes: 0

Harish Raj
Harish Raj

Reputation: 1575

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));
}

// ...

}

Upvotes: 0

bellum
bellum

Reputation: 3710

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

Upvotes: 0

Related Questions