I am a little confused with something.
I have a class where its not a collection, but it does refer to generic objects:
public class XClass<E extends AnInterface>{
E instanceobject;
public void add(E toAdd){}
}
public interface AnInterface{}
public class A implements AnInterface{}
public class B implements AnInterface{}
I believe I read somewhere that <? extends AnInterface> is to be used (when declaring an instance of XClass) if you want multiple subtype-types in the generic object at the same time, whereas <T extends AnInterface> would only allow you to have a single type of subtype in the generic class at once?
However, I can just use:
XClass<AnInterface> xc = new XClass<AnInterface>();
A a = new A();
B b = new B();
xc.add(a);
xc.add(b);
and this way I can pass in multiple subtypes of Supertype to the generic class......
I am not seeing the purpose of using "?" and is there anything wrong with using the Interface as the generic parameter?
The reason why you can add objects of both type A and B is due to the fact that you parametized your XClass with the interface, so there is nothing wrong with adding two different classes that implement that interface.
If, on the other hand, you had defined XClass as:
XClass<A> xc = new XClass<A>();
then the expression xc.add(b); would give a compilation error, since all the objects added must have the same type as was declared, in this case, A.
If you declare you xc as, for instance:
XClass<? extends AnInterface> xc = new XClass<AnInterface>();
Then it's not legal anymore to add a or b, since the only thing we know is that xc is of some unknown but fixed subtype of AnInterface, and there is no way to know if that unknown type is A or B or anything else.
But let's say you're writing a method to accept a XClass type that you can iterate over the elements that were added before. Your only restriction (for the sake of the example), is that the items extend AnInterface, you don't care what the actual type is.
You can declare this method like:
public static void dummyMethod(XClass<? extends AnInterface> dummy){
//do stuff here, all the elements extend (implement in this case), AnInterface, go wild.
}
And now you can pass into this method anything like XClass<A>, XClass<B> or XClass<AnInterface>, and it will all be valid.
Keep in mind that you can't add to the object you pass, for the same reason above. We don't know what the unknown type is!
public static void dummyMethod(XClass<? extends AnInterface> dummy){
//do stuff here, all the elements extend (implement in this case), AnInterface, go wild.
dummy.add(new A()); //you can't do this, we have no idea what type ? stand for in this case
}
You can use E if you want to have an instance of XClass to use only one subclass of AnInterface and no other Classes implementing AnInterface that do not extend / implement E.
For example given
public class ClassOne implements AnInterface {} and public class ClassTwo implements AnInterface {}
If you were to use
public class XClass<E extends AnInterface> and <ClassOne>XClass xc = new <ClassOne>XClass() then you can only use an object of ClassOne in your add method not one of ClassTwo. Using ? would allow you to pass in any class implementing AnInterface, either ClassOne or ClassTwo.
Using Identifier E means "For this object I want to use type E and any subclasses", using ? means "I want to use any type that matches the the expression"
In your example you need type erasure in the method "add", so you should't use wildcards in your class.
Wildcards are only to be used when you do not need type erasure (i.e. you don't care about the type as long as it is a subclass of..) and also when you will need to subtype the generics itself.
The wildcard simply means that it will be some class that meets that criteria. So ? extends AnInterface means it will be one (and only one) class that extends AnInterface.
So it could be:
XClass<Impl1>
XClass<Impl2>
etc...
However, at runtime, you don't know what that class will be. For this reason calling methods which take the actual type as a parameter is inherently unsafe, since it's impossible for the compiler to know if the parameter is appropriate for the actual instantiated instance.
Take lists as an example. Something might be declared like this:
List<? extends Number> list = new ArrayList<Integer>();
What would happen if you try to do either of these:
list.add(new Double(0));
list.add((Number) new Long(1L));
It would not compile, because the generic parameter type is unknown at compile time. So the compiler can't tell if Double or Number would be appropriate to pass to the actual instance (in this case ArrayList<Integer>). This is when you get the infamous capture-of compile error.
This, however is permissible, since you know for certain at compile time that the list can take any instance of Number (which includes subclasses).
List<Number> list = new ArrayList<Number>();
list.add(new Double(0));
list.add((Number) new Long(1L));
Related
I need to pass Class<TableEditInfo<Generic Type>> to a method to create an array of that generic type, but I am not sure how to get TableEditInfo.class with a generic. I have tried this:
TableEditInfo<Integer> editInfo = new TableEditInfo<Integer>(someData);
c.add(editInfo.getClass(), editInfo)
but it shows me Unchecked cast: 'java.lang.Class<capture<? extends app.mainWindow.edit.TableEditInfo>>' to 'java.lang.Class<app.mainWindow.edit.TableEditInfo<java.lang.Integer>>'. It works but I don't know if this code is correct or is it not a good practise to do that. If its bad, how do I do it properly?
c is other class object that stores the TableEditInfo<T> array
add looks like that:
public void add(Class<TableEditInfo<T>> type, TableEditInfo<T> editInfo){
#SuppressWarnings("unchecked")
TableEditInfo<T>[] arr = (TableEditInfo<T>[]) Array.newInstance(type,1);
arr[0] = editInfo;
stack.push(arr);
}
basically it makes a singleton array, because I just need it for some specific reason.
The expression editInfo.getClass() has type Class<? extends TableEditInfo>. The ? extends is because the object's actual runtime class could be a subclass of TableEditInfo, and the lack of <T> is because there aren't really Class objects representing TableEditInfo<Integer> or TableEditInfo<String>, etc. -- there is only one Class instance at runtime representing the class TableEditInfo.
In any case, the simplest solution is to just remove the type parameter, which is useless. At runtime, the passed argument will always be the same -- it will point to the single Class instance representing the class TableEditInfo, namely, TableEditInfo.class.
You can replace Array.newInstance(type,1) with either new TableEditInfo[1] or new TableEditInfo<?>[1]. Both of those are legal. (The former can be assigned to TableEditInfo<T>[] directly with an unchecked conversion warning. The latter needs a cast to be assigned to TableEditInfo<T>[], which will cause an unchecked cast warning.)
I've written a bit of generic code for operating with different types of data, but I'm struggling with the numeric data.
I have a class layout like so:
public abstract class A<Number> {
.
.
.
}
public class B extends A<Double>{
.
.
.
}
however, I cannot use B as an A<Number>, even though B is a subclass of A<Double>, which should be a subclass of A<Number>.
What am I missing? What would the correct way to do it?
B can't be a A<Number> because if you had a method that looked like void doSomething(T) then it would not accept an Integer (whereas T returnSomething would work, as Double is assignable to Number).
You can assign a B to a A<? extends Number>, however. That means "the generic type is some unknown subtype of Number", which is often what you need.
public abstract class A<Number> has nothing to do with the java.lang.Number class.
Number is the name of your type parameter. If you meant to make your A class generic with a Number-related type parameter, then you probably needed something like
public abstract class A<T extends Number>
Where T is your type parameter that forces type arguments to be java.lang.Number or one of its subclasses. With this, you should be able to use:
A<Double> b = new B(); //with your current declaration of B
Now, with that said:
even though B is a subclass of A<Double>, which should be a subclass of A<Number>.
No, B<java.lang.Number> would not be compatible with A<java.lang.Double>. You can only use the same type argument on parent and child.
I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using the code
List<Integer> l = new ArrayList<>();
Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
This, however does not work for me, resulting in
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
If I remove the class cast, the type of the actual argument is E, which is the type definition from List interface.
My question is, therefore, am I doing something wrong here? This behaviour is something I would have expected anyway, since the types are supposed to be erased during compile time, correct?
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
For example if you did this:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class, because Integer is "baked into" the IntegerList.
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken:
Represents a generic type T. You can use this class to get the generic type for a class. > For example, to get the generic type for Collection<Foo>, you can use:
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>.
Note that this would not work (even if the TypeToken class wouldn't prevent it by making its constructor protected):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
The javadoc will tell you what you are doing.
Class#getGenericSuperclass() states
Returns the Type representing the direct superclass of the entity
(class, interface, primitive type or void) represented by this Class.
If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code. [...]
The direct superclass of ArrayList is AbstractList. The declaration is as such in the source code
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type object returned by it, you will see
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments() which states
Returns an array of Type objects representing the actual type
arguments to this type.
will return the Type
E
since E is the actual type argument used in the ArrayList class definition.
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
If you are creating instances on the fly it won't work:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you)
(It's called Type Erasure)
I'm not sure if this is possible or not, but what I want to accomplish is this:
public static <A,B extends SomeClass & A> B makeB(A thing) {...}
Essentially, using a reflection/generation driven process, I want to provide a thing of type B, where B is of class SomeClass and implements interface A, and A is user-supplied through Generics.
I am not asking about the mechanics of generating B - I have that under control. What I'm looking for is a way to restrict generic type argument <A> to interfaces, not classes, so that I can use the syntax B extends SomeClass & A for clean type safety.
Is this possible? Is anyone aware of an alternative approach to this problem?
Edit: I guess I didn't express myself very clearly, as it seems to be causing confusion in the comments:
B is intended to be a placeholder for a wildcard, so that the client can get a single object that is both a SomeClass and an A without having to do casting based on trust. The client will not have access to the name of the actual class that implements SomeClass and A, because it's being generated at compile time, hence this issue regarding type safety.
It's impossible to impose such a compile-time restriction. Generic type parameters are stand-ins for reference types; they make no distinction between class types and interface types. The fact that additional bounds in a type parameter's declaration must be interface types is merely incidental - your strategy to leverage this as a means to impute a type as an interface was clever, but it's defeated by the limitation that type parameters can't be used in multiple bounds.
Your only options are to settle for a runtime check using Class.isInterface() like Louis Wasserman pointed out, or to leave it up to the caller to be responsible with what it passes in. Either way, make sure to clearly document the method's expectations and behavior.
B is intended to be a placeholder for a wildcard, so that the client can get a single object that is both a SomeClass and an A without having to do casting based on trust. The client will not have access to the name of the actual class that implements SomeClass and A
This seems like a contradiction to me. There's no point to declaring B if the caller can't possibly know what it evaluates to. Remember: the caller of a generic method provides its type arguments. So a caller deciding B without anything to base it on can only be guessing - and that can never be type-safe.
It seems like what you really want your method to return is some type that is both a SomeClass and an A, but this is tricky because they don't share a common supertype:
public static <A> SomeClass&A makeSomeClass(A thing) {...}
(this is nonsensical syntax for demonstration purposes only)
As a workaround, consider alternative ways to represent both a SomeClass and some interface type. For example the candidate interfaces could have a common method for returning a SomeClass:
public interface IsSomeClass {
SomeClass asSomeClass();
}
public interface Foo extends IsSomeClass { }
The implementation of asSomeClass would in fact just return this. Then you could do:
public static <A extends IsSomeClass> A makeSomeClass(Class<A> type) {...}
And the caller of that method would be able to use the returned object as either type:
final Foo foo = makeSomeClass(Foo.class);
final SomeClass someClass = foo.asSomeClass();
If the interfaces themselves can't be modified, then another option is to use a wrapper class and composition instead:
final class SomeClassWrapper<A> {
private final SomeClass someClass;
private final A a;
//constructor and getters, etc.
}
And your method would return a wrapper instance instead, assigning the implementation instance to both someClass and a:
public static <A> SomeClassWrapper<A> makeSomeClass(Class<A> type) {...}
If SomeClass is always a class, the A in <B extends SomeClass & A> can only be an interface, because there is no multiple inheritance in Java. The only way & A can be satisfied is if A is an interface.
I think the problem here is that you want to return a B from this method.
You specify B as a type parameter, but it never appears anywhere else in the method signature.
How is the compiler supposed to infer the return type from the arguments????
There is no opportunity for the client code to specify what B is.
It seems like you should return either a SomeClass or an A.
Either one can be a B under the hood, but should appear as a SomeClass or an A to the client code.
I have a method that is expecting a List<SuperClass> as argument:
public void myMethod(List<SuperClass> list) {}
I want to call that method with a List<Subclass> something like:
List<SubClass> subList = new ArrayList<>();
// ...
myMethod(subList); // Got an argument mismatch error on this line.
Shouldn't I be able to do this when SubClass extends SuperClass?
No, generics don't work like that. What you could do is define your method as MyMethod(List<? extends SuperClass> list) (by convention it should be named myMethod(...) btw).
The problem with List<SuperClass> vs. List<SubClass> is that you could add new elements to such lists whereas the compiler wouldn't allow you to add something to a List<? extends SuperClass> - and this has a reason:
Consider the following:
class A {}
class B extends A {}
class C extends A {}
If you now have a List<A> you could add instances of A, B and C. However, if you pass a List<B> to a method as a List<? extends A> parameter, the compiler doesn't know whether it is allowed to add instances of A or C to that list (it wouldn't be allowed, but in case you'd pass a List<A> it would be). Thus the compiler restricts you not to do so.
Defining a parameter as List<A> tells the compiler that is is ok to put instances of all three classes to that list. Now if you would be allowed to pass a List<B> as such a parameter you could end up with a List<B> that contains instances of A and/or C. And this is clearly not what you want and could result in runtime bugs that should be prevented at compile time already - by using generics. That's why your approach doesn't work.
Worth noting, you can also create the list of your superClass from a list of subClass as such:
myMethod(new ArrayList<SuperClass>(list));