I am unable to get this to compile and I don't see the reason why.
Ultimately I want to pass an Collection of objects who's class extends TClass into the generate method that takes a Collection of objects who's class extends TClass,
This should work.
Any help would be appreciated.
public interface Generator<IT extends ITClass, T extends TClass> {
IT generate(Collection<T> tClassCollection)
}
Generator<?, ? extends TClass> generator = generatorClass.newInstance();
Collection<? extends TClass> TClassCollection = ...
... generator.generate(TClassCollection);
I get this error
The method generate(Collection<capture#8-of ? extends TClass>) in the type
Generator<capture#7-of ?,capture#8-of ? extends TClass> is not applicable for the arguments (Collection<capture#9-of ? extends TClass>)
This should work
No; it would open a loophole in the type system if it did. Consider:
class SpecialT extends TClass {}
class SpecialGenerator extends Generator<ITClass, SpecialT> {}
Generator<?, ? extends TClass> generator = SpecialGenerator.class.newInstance();
Collection<? extends TClass> TClassCollection = Arrays.asList(new TClass());
generator.generate(TClassCollection);
A SpecialGenerator can only work with a Collection<SpecialT>, but you are trying to pass a Collection<TClass>, which can contain instances of types other than SpecialT.
A wildcard in a generic declaration doesn't mean "any type"; it means "some particular unknown type."
So, if you have a Generator<?, ? extends TClass>, it doesn't mean you can pass its generate() method any Collection as long as it contains a subtype of TClass.
On the contrary, it means that you can't invoke its generate() method in a type-safe way, because you don't know the type of elements it is capable of accepting.
Related
I was able to find how to declare generics with single argument and multiple constrains and generics with multiple arguments, but strangely enough, not a generic with multiple argument and constraints:
public class Page<U, T implements IPaginableBy<U>> extends ArrayList<T> { }
gives me syntax error after T: "java: > expected". Is it not possible to constrain a an argument on generic type more than one argument?
Change
public class Page<U, T implements IPaginableBy<U>> extends ArrayList<T> { }
to
public class Page<U, T extends IPaginableBy<U>> extends ArrayList<T> { }
Constrained type arguments always use the extends keyword.
I've a structure like this:
abstract class MyDomain{...}
abstract class FooDomain extends MyDomain{...}
abstract class BarDomain extends MyDomain{...}
class FirstConcreteBarDomain extends BarDomain{...}
class SecondConcreteBarDomain extends BarDomain{...}
I need a factory that creates MyDomain objects. My first attempt was this:
public interface ISpecializedObjectsFactory {
public <T extends MyDomain> T create(Class<?> clazz);
}
Implementend as:
public class FirstSpecializedObjectsFactory implements ISpecializedObjectsFactory {
#Override
public <T extends MyDomain> T create(Class<?> clazz) {
if(clazz.equals(BarDomain.class))
return new FirstBarDomain();
throw new InvalidParameterException();
}
Same for the SecondBarDomain.
FIRST QUESTION: Why this is generating an error that says that it cannot cast FirstBarDomain to T?
After this error I've introduced a cast: return (T) new FirstBarDomain();.
The problem is that the cast is unsafe and I want to be confident for the result, so I've introduced another constraint (assuming that each MyDomain object have always 2 levels of derivation):
public <T extends AnagrafeDomain, S extends T> S create(Class<T> clazz)
SECOND QUESTION: Assuming that this factory is the only entry point where MyDomain objects are created, and that the calls to the factory never use the concrete classes (but are always like: BarDomain subj = SpecializedObjectsFactory.getFactory().create(BarDomain.class);), the question is: is this new version safe?
The reason the cast is unsafe is because of this particular line:
public <T extends MyDomain> T create(Class<?> clazz) {
This infers the return type from the call site; in other words, consider the following class:
public abstract class MyFakeDomain extends MyDomain { }
The following code will then compile, but fail at runtime:
ISpecializedObjectsFactory factory = new FirstSpecializedObjectsFactory();
MyFakeDomain broken = factory.create(BarDomain.class);
This will throw a ClassCastException because of the type inference; the inferred type will be MyFakeDomain, resulting in an attempt to cast FirstBarDomain to MyFakeDomain, which is an illegal cast - hence the unsafe warning.
The type inference is also the reason why the cast must be present; whilst FirstBarDomain is definitely a subclass of MyDomain, we do not know if it is of type T, as T could be any MyDomain subclass, not necessarily FirstBarDomain.
However, if the caller is careful, your code will work fine - whether you consider this acceptable or not is up to you.
This gives us the answer to your second question: using BarDomain as the type to be inferred will not always be safe, as it could be another subclass of MyDomain. The only type that would be always safe here is MyDomain - however, if you are planning on only using MyDomain as the type, you might as well remove the generic type bound and just make the return type MyDomain.
The constraint that will give you the confidence you are looking for is limiting the classes that your factory receives:
public interface ISpecializedObjectsFactory {
public <T extends MyDomain> T create(Class<? extends MyDomain> clazz);
}
public class FirstSpecializedObjectsFactory implements ISpecializedObjectsFactory {
#Override
public <T extends MyDomain> T create(Class<? extends MyDomain> clazz) {
if(clazz.equals(BarDomain.class))
return (T) new FirstBarDomain();
throw new InvalidParameterException();
}
}
The compiler will not accept any call to create when the argument is not a subclass of MyDomain. However, it will accept an abstract class. If you want to know you received a concrete class, you can find the answer here How can I determine whether a Java class is abstract by reflection
I have the following generic class:
public class Evalutor<T>{
}
I would like to create the type called NumberEvalutor as follows:
public class NumberEvalutor<T> extends Evalutor<T extends Number>{ //Syntax error on token "extends", , expected
}
But I couldn't do it that way. Maybe you can advice another type-safe way?
Try with:
public class NumberEvalutor<T extends Number> extends Evalutor<T> {
}
Type parameters on class-level (like <T extends Number>) must be introduced after the class name and can be referred in the super-class/super-interface list. Otherwise, there won't be a way to (explicitly) specify their runtime value when creating class instances.
This one should work :)
public class NumberEvaluator<T extends Number> extends Evaluator<T> {
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to reference a nested generic parameter in java?
A quick question on Java generics if I may. Is there syntax for declaring a generic class-wide type that is NOT used as a generic parameter for instantiation. For example:
public class <U extends FooUType> BarType<T extends FooType<U>>{
public U getU(){return U;}
}
To create a BarType I want to write the following, which in itself contains U, but I don't want to have to specify U separately. So:
BarType<SomeT<FooUType>> instance
We get the type of U implicitly from the parameterized SomeT without having to specify U separately. As opposed to :
public class BarType<U extends FooUType, T extends FooType<U>>
which would require:
BarType<FooUType,SomeT<FooUType>>
I guess I'm looking for something akin to the same idea in methods:
public <U> boolean StupidMethod(String s){
...
}
I would rather not use <? extends FooUType> as this leads to problems with method return types inside the class that return <U extends FooUType> U.
Many thanks for the clarification!
As the comments said, this isn't possible.
I would rather not use <? extends FooUType> as this leads to problems with method return types inside the class that return <U extends FooUType> U.
So, here you're saying that some methods of the class return U... yet you don't want to have U as a type parameter. Well, you can't have it both ways. Either have this:
public class BarType<T extends FooType<U>, U extends FooUType>{
public U getU() { ... }
}
Or this:
public class BarType<T extends FooType<? extends FooUType>>{
public FooUType getU() { ... }
}
If it's just the noisy instantiation you're concerned with, you can use new BarType<> where applicable with Java 7. Without Java 7, declare a factory method so the callers can use type inference:
public static <T extends FooType<U>, U extends FooUType> BarType<T, U> make() {
return new BarType<T, U>();
}
Thanks all,
I went for a different solution in the end. Basically the class I was trying to hide the U in was abstract and so I added U as a generic parameter as there is no way round this. I then created the concrete classes that extend this and had them fill in the type of U silently so that the caller wouldn't need to bloat their code.
Something like this:
public abstract class MyAbsClass<U extends Foo, T extends Bar<U>>{...}
public class ConcreteClass<T extends SomeBar> extends MyAbsClass<SilentUType, T>
where SomeBar is not parameterized. The user can then just instantiate with T:
new ConcreteClass<SomeDerivedBar>()
This worked for my scenario neatly, so I hope it helps others.
I want to extend my BinaryTree class so that only Integer parameters are accepted and I can reuse the code.
public class BinaryTree<T extends Comparable<T>>
{/*code omitted for convenience*/}
public class BinaryTreeInt<T extends Integer> extends BinaryTree<T>
{/*code omitted for convenience*/}
I get following error on compilation-
BinaryTreeInt.java:1: type parameter T is not within its bound
public class BinaryTreeInt<T extends Integer> extends BinaryTree<T>
^
1 error
Can someone guide how to write code for such inheritance?
Integer is final so what you have is
public class BinaryTreeInt extends BinaryTree<Integer>
However the type implies its is int rather than Integer
The problem stems from the following potential class:
class FunnyNumber extends Integer { }
This class does not extend Comparable<T>, so it can't be used as the base T.
In other words, extends Comparable<Integer> is not the same as extends Comparable<T>.
Your second class should not be generic at all.
You should only use generics if you want to vary the type parameter.
Here, you want a single fixed type, so you should make a normal non-generic class that extends BinaryTree<Integer>. (or just use BinaryTree<Integer> directly and don't make a separate class at all)