Is there a way one could avoid type erasure and get access to a type parameter?
public class Foo<T extends Enum<?> & Bar> {
public Foo() {
// access the template class here?
// i.e. :
baz(T.class); // obviously doesn't work
}
private void baz(Class<T> qux) {
// do stuff like
T[] constants = qux.getEnumConstants();
...
}
}
I need to know about T, and do things with it. Is it possible, and if so, how can it be done without passing in the class in the constructor or anywhere besides the parameter?
EDIT: The main purpose of this question is to find out if there is any practical way around type erasure.
AFACT, there is no practical way around type erasure because you can't ask for something which the runtime doesn't have access to. Assuming of course you agree that sub-classing generic classes for each enum which implements Bar interface is a practical work around.
enum Test implements Bar {
ONE, TWO
}
class Foo<T> extends FooAbstract<Test> {
public Foo() {
ParameterizedType genericSuperclass =
(ParameterizedType) getClass().getGenericSuperclass();
baz((Class<T>) genericSuperclass.getActualTypeArguments()[0]);
}
private void baz(Class<T> qux) {
T[] constants = qux.getEnumConstants();
System.out.println(Arrays.toString(constants)); // print [ONE, TWO]
}
}
interface Bar {
}
class FooAbstract<T extends Enum<?> & Bar> {
}
If you're willing/able to hand a class token to the constructor:
public Foo(Class<T> clazz) {
baz(clazz);
}
private void baz(Class<T> qux) {
// ...
}
That way, you can produce objects of type T with Class.newInstance(), attempt to cast arbitrary objects to T using Class.cast(), etc.
What do you intend to do in baz()?
As pholser points out in his answer, the only way to achieve this is by passing in the Class object representing the type T. It's because of Type Erasure that something like T.class isn't possible because T is erased before runtime.
You seem resistant against passing in the Class object, but it's the only way to use the method getEnumConstants(). Here is a self contained example:
public class Foo<T extends Enum<?> & Bar> {
final Class<T> clazz;
public Foo(Class<T> clazz) {
this.clazz = clazz;
}
public void baz() {
T[] constants = clazz.getEnumConstants();
System.out.println(Arrays.toString(constants));
}
public static void main(String[] args) {
new Foo<MyEnum>(MyEnum.class).baz(); //prints "[A, B, C, D]"
}
}
public interface Bar { }
public enum MyEnum implements Bar { A, B, C, D; }
Use a super type token as proposed by Neil Gafter and used by libraries like guice for this purpose.
See http://gafter.blogspot.com/2006/12/super-type-tokens.html for the original description and I've check out the guice source for CA radio life working implementation.
there is another q which has an answer with worked example inline here How can I pass a Class as parameter and return a generic collection in Java?
In some cases you can use a workaround suggested by Richard Gomes.
When creating instances of anonymous classes, the type parameter class info is available.
class A<T>
{
A()
{
java.lang.reflect.ParameterizedType parameterizedType = (java.lang.reflect.ParameterizedType) (this.getClass().getGenericSuperclass());
System.out.println(parameterizedType.getActualTypeArguments()[0]);
}
}
public class Example {
public static void main(String[] args) {
A<String> anonymous = new A<String>() {}; // prints java.lang.String
}
}
Note that multiple instances created this way will be of different anonymous classes, and if that's a problem you might want a class A_String_Factory with a createNew() function based on clone to replace the calls to new.
Related
Given the following setup:
public class TestType {
public static void main(String[] args) {
List<Constants> list = new ArrayList<>();
accept(list); //Does not compile
}
static void accept(Iterable<MyInterface> values) {
for (MyInterface value : values) {
value.doStuff();
}
}
}
interface MyInterface<T> {
T doStuff();
}
enum Constants implements MyInterface<Integer> {
ONE, TWO, THREE;
#Override
public Integer doStuff() {
return ordinal();
}
}
Why won't the compiler accept the list as parameter to accept()?
List extends Iterable via Collection so that isn't the problem.
On the other hand, the compiler tells me that
incompatible types: java.util.List<enums.Constants> cannot be converted to java.lang.Iterable<enums.MyInterface>
But Constants IS a MyInterface... isn't it?
The problem is with how Generics work. Specifically, Generics are non-reified... meaning that the compiler will not see an Iterable<enum.Constants> as an Iterable<enum.MyInterface> even if Constants is a sub-class of MyInterface.
However, there is a way to get around it: Generic wildcards.
If you change static void accept(Iterable<MyInterface> values) to static void accept(Iterable<? extends MyInterface> values), it should work.
You need to use Iterable<? extends MyInterface> instead of Iterable<MyInterface> because even though Constants is a subtype of MyInterface, Iterable<Constants> is not a subtype of Iterable<MyInterface> - and I'll show you why:
If it was so (let's use List instead of Iterable for the next example), I would be able to do this:
List<Constant> constantsList = new ArrayList<Constants>(); // list of constants
List<MyInterface> ifaceList = constantsList; // you said this would be OK ...
// assume MyOtherImplementation is another implmentation of MyInterface
ifaceList.add(new MyOtherImplementation()); // OK, MyOtherImplementation implements MyInterface
Constant myConst = constantsList.get(0); // Oops! I just got an instance of MyOtherImplementation from List<Constant> - not cool.
Generic types do not inherit this way, although it may seem counter-intuitive at first glance. Using Iterable<? extends MyInterface> will allow you to use any Iterable (e.g., a List) of a type that extends MyInterface (e.g. Constants).
If you don't use Java Generics, I believe it's not possible to have two methods in the same class that differ only in their return type.
In other words, this would be illegal:
public HappyEmotion foo(T emotion) {
// do something
}
public SadEmotion foo(T emotion) {
// do something else
}
Is the same true when overloading methods that return a generic type that may implement different interfaces, such as if the following two methods were present in the same class definition:
public <T extends Happy> T foo(T emotion) {
// do something
}
public <T extends Sad> T foo(T emotion) {
// do something else
}
Would this be illegal?
This is legal since the input parameter too differs based on the type..
For this reason, following is legal,
public <T extends Happy> T foo(T emotion) {
// do something
}
public <T extends Sad> T foo(T emotion) {
// do something else
}
But following is not,
public <T extends Happy> String foo(T emotion) {
// do something
}
public <T extends Happy> T foo(T emotion) {
// do something else
}
Thanks...
This ran just fine.
public class Main {
public static void main(String[] args){
Main main = new Main();
main.foo("hello");
main.foo(new Integer(5));
}
public <T extends String> T foo(T emotion) {
return (T) "test";
}
public <T extends Integer> T foo(T emotion) {
Integer integer = 5;
return (T) integer;
}
}
It will compile, but where you get into problems is if either Happy or Sad is a superclass of the other.
For instance, the following compiles:
public <T extends Number> T sayHi() {
System.out.println("number");
return null;
}
public <T extends Integer> T sayHi() {
System.out.println("integer");
return null;
}
However, you run into problems when you try to compile the following:
Integer test = sayHi();
In this case, you simply cannot add <Integer> to the front because Integer is still both a Number and an Integer.
However the following compiles
Double test2 = <Double>sayHi();
so basically as long as a Sad object cannot be an instance of a Happy object and visa versa, your code should work as long as you call it with the or in front of the method name.
You can use generic to distinguish the method in Java. The JVM doesn't see this type however provided the argument or return type is different it will still compile in the Sun/Oracle compiler. This doesn't compile for the IBM/eclipse compiler.
This shows you want is happening at the byte code level. http://vanillajava.blogspot.com/2011/02/with-generics-return-type-is-part-of.html
This is legal, as others have said. However, I want to point out what happens when types extend each other.
Let's say we have two interfaces (works for classes as well just change the signature):
interface Emotion {}
interface Happy extends Emotion {}
And two functions:
<T extends Emotion> void foo(T obj) {} // Referred as foo1
<T extends Happy> void foo(T obj) {} // Referred as foo2
If an object conforms to Emotion the JVM will choose foo1.
If an object conforms to Happy the JVM will choose foo2 and not foo1.
Notice the order of precedence. That is how the JVM resolves the ambiguity. However, this is only valid when you pass the generic parameter as an argument.
No static member can use a type parameter, but is it possible to call a static member using the generic type parameter? For example:-
abstract class Agent<A>{
void callAgent();
Agent(){
A.add();
}
}
Here add() is a static method.
There are some C# questions and answers on a similar topic but I'm not too sure how to go about it in Java.
No you cannot do it if A is a generic type. (Bozho answered to fast :) and probably thought A was concrete type.
What will work is the following.
abstract class Agent extends Blah<ConcreteA>{
void callAgent();
Agent() {
ConcreteA.add();
}
}
but it's probably not what you want to do.
After reading your comments it sounds like what you really want to do is:
abstract class Agent<A extends SomeClassThatSupportsAdd> {
void callAgent();
protected abstract A createNew();
Agent() {
A a = createNew();
A.add();
}
}
Your subclasses will have to override createNew().
If you still do not like that you can take a look at AspectJ which will allow you to do some constructor magic (see how spring does #Configurable) but that gets far trickier and complicates things.
Another option is Scala. Java does not do inheritance on static methods so you can't get parameterized modules (groups of functions in some languages this is called a functor ... ocaml). However Scala supports a singleton "object" that does allow for parametric functional polymorphic inheritance.
No, you cannot. The compiler does not know A (which resolves to Object) has the add method.
And you shouldn't need to invoke static methods on generic types in the first place. If you want specific behaviour for each type, define it as non-static, use extends BaseClass in the generics declaration, and invoke it.
Technically, you can also invoke a static method that way, but it's ugly:
class Base {
public static void add() { }
}
class Foo<A extends Base> {
void bar() {
A a = null; // you can't use new A()!
a.add();
}
}
This is not possible because the A type will not necessarily contain an add() method. The compiler will not permit this, because it can't guarantee that it will work.
In fact, you can invoke a static method on a type parameter (although it isn't done dynamically).
Try this:
public class Main<T extends Collections> {
public static void main(String[] args) {
new Main<>().foo();
}
void foo() {
List<Integer> list = Arrays.asList(2, 3, 1);
T.sort(list);
System.out.println(list);
}
}
I have no idea why the language designers decided it was a good idea to allow this.
It is handy to get a value from an enum you don't know beforehand.
public static <T extends Enum<T>> T enumFromName(String name, Class<T> clazz) {
return StringUtils.isEmpty(value) ? null : T.valueOf(clazz, name);
}
Having:
enum ProductType { FOOD, ELECTRONICS, ... }
You can do:
ProductType p = enumFromName("FOOD", ProductType.class);
I guess you can also take advantage of this in your own classes, although I would not recommend using static too much.
You can use reflection for calling static method of class T. For example:
public Agent<T>{
private final Class<T> clazz;
public Agent(Class<T> clazz){
this.clazz = clazz;
executeAddMethodOfGenericClass();
}
public void executeAddMethodOfGenericClass() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method = clazz.getMethod("add");
method.invoke(null);
}
}
But i can get exception. Be careful.
i've stumbled upon a curiosity in the java inheritance, and I wanted you to ask for better ideas on that:
Assume two interfaces A and A1
Interface A1 extends A
Interface A has a method which returns a generic type.
The generic type would be like GenericType<T>.
A basic idea is now to change this generic return type from
GenericType<Object> in Interface A into
GenericType<String> in Interface A1
Well seems to be easy at first (bad things will come later on)
We declare Interface A like
public interface InterfaceA {
public GenericType<? extends Object> getAGenericType();
}
and Interface A1 like
public interface InterfaceA1 extends InterfaceA
{
#Override
public GenericType<String> getAGenericType();
}
As you see we are forced to write GenericType<? extends Object> in Interface A itself to allow overriding it with generic based "subclasses".
(In fact the generic parameter of the generictype is subclassed not the generic type itself)
Now assume the GenericType has its own method looking like:
public interface GenericType<D>
{
public void doSomethingWith( D something );
}
Now trying to instantiate A1 works great.
Rather trying to instantiate A will suck. To see why look at this "use the interface" class:
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<? extends Object> aGenericType2 = a.getAGenericType();
Object something = null;
aGenericType2.doSomethingWith( something );
}
}
You ask: "And now?"
It does not work on the last lines. In fact the parameter "something" is not even from type "Object" it is from Type "? extends Object". So you cannot pass the declared "Object" type. You can't pass anything at all.
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
Do you have ideas how to model such a use case, where the subclasses will have to override the return type, while the return type is a generics?
Or how would you go around such a model case?
Or am I just missing a simple point in the generic declaration and my example is possible this way?
----------- (1) edit due to answers -----------
A very good basic idea is making the interface A more abstract! I had exactly the same idea first, but... (this has to come)
Assume doing this:
We introduce a new interface AGeneric
public interface InterfaceAGeneric<T>{
public GenericType<T> getAGenericType();
}
Now we will have to extend A and A1 from this new interface:
public interface InterfaceA extends InterfaceAGeneric<Object>{}
public interface InterfaceA1 extends InterfaceAGeneric<String>{}
That works fine, althought it breaks the path of the original inheritance.
If we want A1 still be extendable from A, we have to change A1 to
public interface InterfaceA1 extends InterfaceA, InterfaceAGeneric<String>{}
and there a problem is again. This does not work, since we extend indirectly the same interface with different generic types. This is unfortunately not allowed.
You see the problem?
-
And to point to another circumstance:
If you cast the GenericType<? extends Object> to GenericType<Object> it obviously works.
Example:
public class LookAtTheInstance
{
public static void main( String[] args )
{
InterfaceA a = new InterfaceA()
{
#Override
public GenericType<? extends Object> getAGenericType()
{
return new GenericType<Object>()
{
#Override
public void doSomethingWith( Object something )
{
System.out.println( something );
}
};
}
};
;
#SuppressWarnings("unchecked")
GenericType<Object> aGenericType2 = (GenericType<Object>) a.getAGenericType();
Object something = "test";
aGenericType2.doSomethingWith( something );
}
}
So it seems for me that the resolving of the parameter type of the method
public interface GenericType<D extends Object>
{
public void doSomethingWith( D something );
}
is wrong.
If D is unified with "? extends Object" why the parameter type is not forced to be "Object"?
Wouldnt this make more sence?
A basic idea is now to change this generic return type from GenericType in Interface A into GenericType in Interface A1
This is not possible, because Java Generics are invariant. [1]
As you found out, you cannot have an interface declaring a method that returns GenericType<Object> and in a sub interface override the method to return GenericType<String>: The latter return type is not a subtype of the former. And for good reason!
You tried to
extend indirectly the same interface with different generic types. This is unfortunately not allowed.
There is no way this could possibly work: E.g. what should be the type of E in public E set(int index, E element) in a class that implemented both List<String> and List<Object>? Your subclassed interface would have to produce a similar hybrid: The return value of getAGenericType in the sub interface would have to implement both the GenericType<String> and the GenericType<Object> interface. And as we saw, this is impossible.
The compiler does not know what you are going to do with the type parameter in GenericType (although it theoretically could find out, it doesn't). If you had a variable of type GenericType<String> and assigned a GenericType<Object> to it, you may very well end up putting a Long instance where a String is expected, and get a ClassCastException where you won't expect one.
In the doSomethingWith method of your variable GenericType<? extends Object> aGenericType2 you can pass one thing: null. null is the only object reference that has a subtype of ? extends Object. The lower bound type of ? extends Object is the null type, which cannot be expressed in Java, and only implicitly exists as the type of the null reference.
[1] http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29#Java
I don't know if this is what you are expecting, but you can declare your interface something like:
public interface Interface <K extends Object> { ... }
While your class might look like:
public class InterfaceImpl implements Interface<String> { ... }
#Override annotation:
When overriding a method, you might
want to use the #Override annotation
that instructs the compiler that you
intend to override a method in the
superclass. If, for some reason, the
compiler detects that the method does
not exist in one of the superclasses,
it will generate an error.
With this annotation you cannot change return type of function.
If you want to override return type, just make interface A more abstract, add generic to this interface:
public interface InterfaceA<T> {
public GenericType<T> getAGenericType();
}
Sample about overriding a generic method in a generic class.
The trouble is that InterfaceA doesn't know what type it's holding. If you get InterfaceA to take a generic argument then you could do this:
public interface InterfaceA<T>
{
public GenericType<T> getAGenericType();
}
public interface InterfaceA1 extends InterfaceA<String>
{
#Override
public GenericType<String> getAGenericType();
}
public class LookAtTheInstance
{
#SuppressWarnings("null")
public static void method()
{
InterfaceA<String> a = null;
InterfaceA1 a1 = null;
GenericType<String> aGenericType = a1.getAGenericType();
GenericType<String> aGenericType2 = a.getAGenericType();
String something = null;
aGenericType2.doSomethingWith( something );
}
}
I'm several years late to the party, but I found this page while searching for a related question and none of the answers really hit on the central issue, which I think is worth clarifying. Let's look at a slightly-more-fleshed-out example:
interface GenericType<D> {
D getAValue();
void doSomethingWith(D value);
}
class StringType implements GenericType<String> {
#Override
public String getAValue() {
return "Hello World";
}
#Override
public void doSomethingWith(final String value) {
System.out.println(value.length());
}
}
interface InterfaceA {
GenericType<? extends Object> getAGenericType();
}
interface InterfaceA1 extends InterfaceA {
#Override
GenericType<String> getAGenericType();
}
class AnActualA1 implements InterfaceA1 {
#Override
public GenericType<String> getAGenericType() {
return new StringType();
}
}
class LookAtTheInstance {
public static void method() {
InterfaceA1 a1 = new AnActualA1();
// 'g1' is a StringType, which implements GenericType<String>; yay!
GenericType<String> g1 = a1.getAGenericType();
// Everything here is fine.
String value = g1.getAValue();
g1.doSomethingWith("Hello World");
// But if we upcast to InterfaceA???
InterfaceA a = (InterfaceA) a1;
// Note: a.getAGenericType() still returns a new StringType instance,
// which is-a GenericType<? extends Object>.
GenricType<? extends Object> g = a.getAGenericType();
// StringType.getAValue() returns a String, which is-an Object; yay!
Object object = g.getAValue();
// StringType.doSomethingWith() method requires a String as the parameter,
// so it is ILLEGAL for us to pass it anything that cannot be cast to a
// String. Java (correctly) prevents you from doing so.
g.doSomethingWith(new Object()); // Compiler error!
}
}
Conceptually, GenericType is NOT a GenericType, since a GenericType can only doSomethingWith() Strings, while a GenericType needs to be able to doSomethingWith() any object. GenericType is a compromise which the compiler allows you to use as a "base class" for any GenericType where D is-an Object, but only allows you to use a reference of that type to call methods that are type-safe for any possible runtime value of '?' (such as getAValue(), whose return value can always be safely cast to an Object since D is-an Object regardless of runtime type).
It's hard to tell what (if anything) the original poster was actually trying to model with this code, and in particular how much of the generic-ness of GenericType was really needed, but perhaps the inheritance should have gone the other way around?
/**
* I can do something with instances of one particular type and one particular
* type only.
*/
interface GenericType<D> {
void doSomethingWith(D value);
}
/**
* I can do something with instances of any type: I am-a GenericType<String>
* because I can totally do something with a String (or any other kind of
* Object).
*/
interface NonGenericType extends GenericType<Object>, GenericType<String> {
#Override
void doSomethingWith(Object value);
}
interface StringHandlerFactory { // nee InterfaceA1
GenericType<String> getAGenericType();
}
/**
* I extend StringHandlerFactory by returning a NonGenericType (which is-a
* GenericType<String>, satisfying the interface contract, but also so much
* more).
*/
interface ObjectHandlerFactory extends StringHandlerFactory { // nee InterfaceA
#Override
NonGenericType getAGenericType();
}
The downside being that there's no good way to express to the java compiler that NonGenericType extends GenericType, even though conceptually it could in this case, since GenericType never uses D as a return value. You have to manually specify each GenericType that you want it to extend. :(
So you end up declaring nice interfaces which, as it turns out, cannot be instantiated right.
I think that the purpose of InterfaceA is not to be instantiated at all, because one of its dependable classes are generic. That's what you meant declaring:
public GenericType<? extends Object> getAGenericType()
So, I have an abstract class like:
public abstract class AbstractParent <E extends Enum<E>> {...}
Somewhere in a non-abstract method inside AbstractParent, I would like to iterate over the values of E. Is this possible?
For a better example:
public abstract class AbstractParent <E extends Enum<E>> {
...
protected void doSomething() {
//iterate over the values of E and perform an action using them
}
}
public class Child extends AbstractParent<Child.Index> {
public static enum Index {
...
}
public Child() {
super();
this.doSomething(); //this should iterate over Index's values
}
}
EDIT:
So, thanks to mdma, this works awesomely:
public abstract class AbstractParent <E extends Enum<E>> {
...
protected void doSomething() {
//iterate over the values of E and perform an action using them
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
Type t = pt.getActualTypeArguments()[0];
E[] enumValues = ((Class<E>)t).getEnumConstants();
// enumValues is now an iterable array of the values inside Index
}
}
public class Child extends AbstractParent<Child.Index> {
public static enum Index {
...
}
public Child() {
super();
this.doSomething(); //this should iterate over Index's values
}
}
Thanks LOADS to mdma, you deserve more points than I can give.
EDIT2: Generics on superclasses and interfaces are not erased. You can get the generic type at runtime and use that to fetch the enum values. See Class.getGenericSuperclass. This will save you having to pass the value or a class in the constructor.
Original:
You cannot do this with generics. However, if you pass in the corresponding class also, e.g. a constructor like
AbstractParent(Class<E> enumClass)
{
this.enumClass = enumClass;
}
Then you can use that to fetch the corresponding enum values via
public E[] getValues()
{
return this.enumClass.getEnumConstants();
}
EDIT: Although the clients are not professional programmers, the compiler will ensure the correct class is passed. You can also make the usage clear by providing examples, and unit tests.
You could also have the constructor take and actual value of the Enum, and derive the class from that. This might be simpler to use, since the parameter is then an E rather than the more "scary" Class<E>.
E.g.
AbstractParent(E enumValue)
{
this.enumClass = enumValue.getClass();
}
Since generics are erased at runtime, the only way this is possible is by having a constructor that requires a Class<E> parameter on which you can then call getEnumConstants().