This question already has answers here:
Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?
(19 answers)
Closed 8 years ago.
Making a API for internal use, I need some Java abstraction and I don't know how to do it.
There is an Interface A with derived interfaces.
Let's say one of the extended interfaces of A is called B.
And let's say there is an class C implementing B.
I have a Factory/Pool class F from which I want to get a list of instances (or set or similar collection).
What I want is basically this:
List<B> instances = F.getAllSuitableInstances(parameters);
Get me all the instances specified by my parameters as a collection of B.
First attempt was with this function signature
public List<A> getAllSuitableInstances(parameters);
but when I try to cast the resulting List to a List for use, I
get told "incompatible types" - even though B is derived from A.
So I tried what the java libraries do:
public <T> List<T> getAllSuitableInstances(parameters, T);
and try calling that with B as second parameter. But that doesn't work
either, since T has to be supplied as an instance for some reason, and
interfaces cannot have instances.
I know I could use <?> with casting but I'd like to make this as typesafe as possible.
So, what is the (best) way to get this done?
even though B is derived from A.
You have to be careful here -- Java's generics are invariant, meaning that Something<Superclass> is not a superclass of Something<Subclass> (e.g. List<Number> is not a superclass of List<Integer>). There are plenty of questions on SO about this, so I won't repeat information that other people can explain much more effectively, like here and here.
As for your second signature, it seems to me that the T in (parameters, T) is unnecessary.
public <T> List<T> getAllSuitableInstance(parameters);
should work, unless I'm misunderstanding your requirements. The disadvantage of this is that T could be anything, so you're somewhat limited in the methods you can invoke on objects of type T, but if you aren't doing that then no concern is warranted.
If the methods in your interfaces are necessary to get your method working (doesn't seem like it, but just in case), you can always add bounds (e.g. public <T extends A> List<T>...) to your generic type, so the compiler knows that all instances of T inside your method are type A or subtypes of A.
If you need to use the type of T in your method (say for instanceof checks), one option is passing in a Class object and using its methods to perform the runtime equivalent of instanceof checks and casting (among other options):
public <T> List<T> getAllSuitableInstance(parameters, Class<? extends T> clazz); // Might be able to use just Class<T> too
Hopefully that helps. Let me know if I got something wrong about what you needed.
This is a common misunderstanding when it comes to programming with generics, but it is an important concept to learn
when we have two concrete types A and B (for example, Number and Integer), MyClass<A> has no relationship to MyClass<B>, regardless of whether or not A and B are related.
The common parent of MyClass<A> and MyClass<B> is Object.
No need to even pass the class as you mentioned in second option
this should work for you
public <T> List<T> getAllSuitableInstances(parameters) {
List<T> list = new ArrayList<>();
//content add to list
return list;
}
Related
This question already has an answer here:
Type parameter vs unbounded wildcard
(1 answer)
Closed 7 years ago.
I have a method where I want to accept class types that must extend an abstract class. What is the difference between
<T extends AbstractClass> void myMethod(Class<T> clazz);
and
void myMethod(Class<? extends AbstractClass> clazz); ?
I wouldn't be able to directly reference the type inside the method in the second case. Is there any difference in which class types could be passed to these two methods?
No, there is no difference between the argument types compatible with the two method signatures you presented. Personally, I would use the parameterized version if I needed to reference the exact type represented by the argument, but otherwise I would use the wildcard version.
In the 1st one you will also be able to return T (or any type parameterized with T: List<T>, Set<T> and so on...) , without needing to cast it
<T extends AbstractClass> T myMethod(Class<T> clazz);
And use it as :
Subclass parameterInstance =...
Subclass i1 = myMethod(parameterInstance.getClass());
This question has been asked many places, notably here and here.
Both questions deal primarily with unbounded wildcards and generic types but the same principles apply here. I'd also recommend reading one of the links (Angelika Langer - Java Generics FAQs) provided by one of the answers to the other questions (placed here for convenient).
Whilst in your specific case there is no difference, the difference comes down simply to how you would be dealing with the type data internally (within the method). Go with what seems to describe your purpose the best. If you are dealing with data of unknown type and you require the specific input type to be specifically usable within the method, you'll need to go with the generics approach. If on the other hand, you do not and can suffice with treating all input data as simply of the bounding type (e.g. AbstractClass in your case) you may go with the bounded wildcard approach.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
Java Generics — Assigning a list of subclass to a list of superclass
With raw types you can easily say something like this.
[...] // MyClass is generic with upper bound of Object
MyClass c = new MyClass<Double>();
[...]
But this isn't allowed
MyClass<Number> c = new MyClass<Double>()
I don't understand why this is. My book tells me why the second doesn't work, because you can't add a Integer to a MyClass<Double>. What it doesn't explains is why MyClass<Double> is a subclass of MyClass<Object> (or the equivalent raw type form), since double is subclass of object.
So why is the first allowed if the second form isn't. Please realize I am new to this.
Edit: Taking it a step further what would happen in the first example if Number was the upper bound?
You can see here the effects of type erasure
class Untitled {
public static void main(String[] args) {
}
public static<T> void c(T t)
{
t.SubClassMethod();// this won't work because class Object has no such method. But if I change the upperbound to SubClass it will.
t.toString() // this will because class Object has such a method
}
}
My point is that why should it matter what the Generic is declared as if it ultimately becomes treated as the upper bound anyway?
Try this:
MyClass<? extends Number> c = new MyClass<Double>();
The first thing to eliminate your confusion is to understand that the Raw Type is not part of the generics system at all. It is in no way equivalent to Something<Object>. Basically, the reason the Raw Type exists at all is just for backward compatibility. When Generics were introduced in Java 5, some existing classes and interfaces were retroactively made generic. In order for old code that didn't have generic declarations to compile in the Java 5 or later compiler, the Raw Declarations are legal.
Any comparison between the way the Raw Type behaves and the way the Parameterized type behaves is in a way a bit fundamentally spurious. The intent of the design is not that the Raw Type be considered an 'alternative' to declaring a parameter. New code that uses the Raw Type is incorrect code. It's legal to compile it so that old code still works.
My point is that why should it matter what the Generic is declared as
if it ultimately becomes treated as the upper bound anyway?
Because the entire point of the generics is to prevent ClassCastException. It will be treated as the actual declared type when someone, for example, someone takes the object back out of the list and assigns it to the specific type they're expecting. The compiler is making a promise that it guarantees this will succeed, so it has to restrict what goes in and out.
Suppose that MyClass is like this:
public class MyClass<T>{
T value;
public void foo(T arg){
value = arg;
}
}
and then those two other classes:
class A{ }
class B extends A { }
now imagine what happens if you do:
MyClass<A> container = new MyClass<B>();
container.foo(new A());
you'd try to put an A into a field of type B. The restriction you are facing is thought to prevent such things. C# has a nifty solution in terms of in and out parameters to generics...
Any MyClass<XXX> is a MyClass, but contrary to what you are saying, MyClass<Double> is not a subclass of MyClass<Object>.
You can find more about it if you search for erasure, like here.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Method has the same erasure as another method in type
In one of my classes I wanted to define these two methods:
private void add(List<ChangeSet> changeSetList) {
for (ChangeSet changeSet : changeSetList) {
add(changeSet);
}
}
private void add(List<Change> changeList) {
for (Change change : changeList) {
add(change);
}
}
Then I get the following error:
Method add(List<Change>) has the same erasure add(List<E>) as another method in type DataRetriever
Why isn´t this allowed? What is the problem with method definitions like that? And what should I do to avoid it? I don´t want to rename one of the methods.
That's just how the type system of Java "works". The generics List<Change> and List<ChangeSet> aren't actually different types. The generic parameters are just hints for the compiler to perform certain checks and certain casts. As far as the JVM and the type system is concerned, though, both types are actually "erased" to List<Object> (or just List if you will), and the two types are really the same, with no internal differences. Therefore, you cannot actually overload on different generics parameters, since as far as overload resolution is concerned, the two types are identical.
This limitation is part of the language syntax, not the Java runtime itself. Essentially, this rule is intended to avoid conflicts in legacy code that still uses raw types.
A compiler like javac will reject this type of overloading, but if you create a class through other means (writing your own compiler, or using a byte-code engineering library like ASM) with signatures that differ only by type parameters, the javac compiler will resolve calls the correct method in your class.
Here's an illustration of why this was not allowed, drawn from the JLS. Suppose, before generics were introduced to Java, I wrote some code like this:
class CollectionConverter {
List toList(Collection c) {...}
}
You extend my class, like this:
class Overrider extends CollectionConverter{
List toList(Collection c) {...}
}
After the introduction of generics, I decided to update my library.
class CollectionConverter {
<T> List<T> toList(Collection<T> c) {...}
}
You aren't ready to make any updates, so you leave your Overrider class alone. In order to correctly override the toList() method, the language designers decided that a raw type was "override-equivalent" to any generified type. This means that although your method signature is no longer formally equal to my superclass' signature, your method still overrides.
Now, time passes and you decide you are ready to update your class. But you screw up a little, and instead of editing the existing, raw toList() method, you add a new method like this:
class Overrider extends CollectionConverter {
#Override
List toList(Collection c) {...}
#Override
<T> List<T> toList(Collection<T> c) {...}
}
Because of the override equivalence of raw types, both methods are in a valid form to override the toList(Collection<T>) method. But of course, the compiler needs to resolve a single method. To eliminate this ambiguity, classes are not allowed to have multiple methods that are override-equivalent—that is, multiple methods with the same parameter types after erasure.
The key is that this is a language rule designed to permit continued use of raw types, not a limitation arising from the erasure of type parameters.
If you eliminate legacy code (for example, by using your own, not-strictly-Java language), this type of overload functions perfectly. Because method resolution occurs at compile-time, before erasure, type reification is not required to make this work.
in addition to the answers by adarshr and Kerrek, why not just make it generic like below:
private <T> void add(List<T> changeList) {
for (T change : changeList) {
add(change);
}
}
that should work for both cases...
Because generics are only a compile time aid to you. After compilation, there will be no generics related information stored in the bytecode.
Take a look at this:
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
After type-erasure both methods will have a signature of private void add(List), which isn't allowed.
You need to either rename the methods or pass another argument like the class of the list values.
This question already has answers here:
When should I use the java 5 method cast of Class?
(5 answers)
Java Class.cast() vs. cast operator
(8 answers)
Closed 4 years ago.
I recently stumbled upon a piece of code that went like this:
Object o = .. ;
Foo foo = Foo.class.cast(o);
I was actually not even aware that java.lang.Class had a cast method, so I looked into the docs, and from what I gather this does simply do a cast to the class that the Class object represents. So the code above would be roughly equivalent to
Object o = ..;
Foo foo = (Foo)o;
So I wondered, why I would want to use the cast method instead of simply doing a cast "the old way". Has anyone a good example where the usage of the cast method is beneficial over doing the simple cast?
I don't think it's often used exactly as you have shown. Most common use I have seen is where folks using generics are trying to do the equivalent of this:
public static <T extends Number> T castToNumber(Object o) {
return (T)o;
}
Which doesn't really do anything useful because of type erasure.
Whereas this works, and is type safe (modulo ClassCastExceptions):
public static <T extends Number> T castToNumber(Object o, Class<T> clazz) {
return clazz.cast(o);
}
EDIT: Couple of examples of use from google guava:
MutableClassToInstanceMap
Cute use in Throwables#propagateIfInstanceOf, for type safe
generic throw spec
In Java there is often more than one way to skin a cat. Such functionality may be useful in cases where you have framework code. Imagine a method which accepts a Class object instance and an Object instance and returns the Object case as the class:
public static void doSomething(Class<? extends SomeBaseClass> whatToCastAs,Object o)
{
SomeBaseClass castObj = whatToCastAs.cast(o);
castObj.doSomething();
}
In general, use the simpler casting, unless it does not suffice.
In some cases, you only know the type to cast an object to during runtime, and that's when you have to use the cast method.
There is absolutely no reason to write Foo.class.cast(o), it is equivalent to (Foo)o.
In general, if X is a reifiable type, and Class<X> clazz, then clazz.cast(o) is same as (X)o.
If all types are reifiable, method Class.cast() is therefore redundant and useless.
Unfortunately, due to erasure in current version of Java, not all types are reifiable. For example, type variables are not reifiable.
If T is a type variable, cast (T)o is unchecked, because at runtime, the exact type of T is unknown to JVM, JVM cannot test if o is really type T. The cast may be allowed erroneously, which may trigger problems later.
It is not a huge problem; usually when the programmer does (T)o, he has already reasoned that the cast is safe, and won't cause any problem at runtime. The cast is checked by app logic.
Suppose a Class<T> clazz is available at the point of cast, then we do know what T is at runtime; we can add extra runtime check to make sure o is indeed a T.
check clazz.isInstance(o);
(T)o;
And this is essentially what Class.cast() does.
We would never expect the cast to fail in any case, therefore in a correctly implemented app, check clazz.isInstance(o) must always succeed anway, therefore clazz.cast(o) is equivalent to (T)o - once again, under the assumption that the code is correct.
If one can prove that the code is correct and the cast is safe, one could prefer (T)o to clazz.cast(o) for performance reason. In the example of MutableClassToInstanceMap raised in another answer, we can see obviously that the cast is safe, therefore simple (T)o would have sufficed.
class.cast is designed for generics type.
When you construct a class with generic parameter T, you can pass in a
Class. You can then do the cast with both static and dynamic
checking, which (T) does not give you. It also doesn't produce unchecked
warnings, because it is checked (at that point).
The common sample for that is when you retrieve from persistent layer a collection of entity referenced with a Class Object and some conditions. The returned collection could contain unchecked objects, so if you just cast it as pointed G_H, you will throw the Cast Exception at this point, and not when the values are accessed.
One example for this is when you retrieve a collection from a DAO that returns an unchecked collection and on your service you iterate over it, this situation can lead to a ClassCastException.
One way to solve it, as you have the wanted class and the unchecked collection is iterate over it and cast it inside the DAO transforming the collection in a checked collection and afterwards return it.
Because you might have something this:
Number fooMethod(Class<? extends Number> clazz) {
return clazz.cast(var);
}
A "cast" in Java, e.g. (Number)var, where the thing inside the parentheses is a reference type, really consists of two parts:
Compile time: the result of the cast expression has the type of the type you cast to
Run time: it inserts a check operation, which basically says, if the object is not an instance of that class, then throw a ClassCast Exception (if the thing you're casting to is a type variable, then the class it checks would be the lower bound of the type variable)
To use the syntax, you need to know the class at the time you write the code. Suppose you don't know at compile-time what class you want to cast to; you only know it at runtime.
Now you would ask, then what is the point of casting? Isn't the point of casting to turn the expression into the desired type at compile time? So if you don't know the type at compile time, then there is no benefit at compile-time, right? True, but that is just the first item above. You're forgetting the runtime component of a cast (second item above): it checks the object against the class.
Therefore, the purpose of a runtime cast (i.e. Class.cast()) is to check that the object is an instance of the class, and if not, throw an exception. It is roughly equivalent to this but shorter:
if (!clazz.isInstance(var))
throw new ClassCastException();
Some people have mentioned that Class.cast() also has a nice return type that is based on the type parameter of the class passed in, but that is just a compile-time feature that is provided by a compile-time cast anyway. So for that purpose there is no point in using Class.cast().
I just saw this C# question and wondered, if something similar could happen in Java. It can, with
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
the call
new A<Integer>(43);
is ambiguous and I see no way how to resolve it. Is there any?
You can drop the generics during construction (and suppress a warning):
A<Integer> a = new A(42);
or, less preferably use reflection (where again you'd have to suppress warnings)
Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
Yes, members of a parameterized type JLS3#4.5.2 can end up in conflicts that are precluded in a normal class declaration(#8.4.8). It's pretty easy to come up with many examples of this kind.
And in Java, neither constructor in your example is more specific than the other, because there is no subtyping relation between T and Integer. see also Reference is ambiguous with generics
If method overloading creates this kind of ambiguity, we can usually choose to use distinct method names. But constructors cannot be renamed.
More sophistries:
If <T extends Integer>, then indeed T is a subtype of Integer, then the 2nd constructor is more specific than the 1st one, and the 2nd one would be chosen.
Actually javac wouldn't allow these two constructors to co-exist. There is nothing in the current Java language specification that forbids them, but a limitation in the bytecode forces javac to forbid them. see Type Erasure and Overloading in Java: Why does this work?
Another point: If <T extends Integer>, since Integer is final, T can only be Integer, so Integer must also be a subtype of T, therefore isn't the 2nd constructor also more specific than the 1st?
No. final isn't considered in subtyping relations. It is actually possible to drop final from Integer one day, and Java even specifies that removing final does not break binary compatibility.
Indeed, it is ambiguous, and so doesn't compile if you try new A<Integer>(new Integer(0)).