I have an interface and an enum as follows:
public interface SomeInterface {
......
}
public enum SomeEnum implements SomeInterface {
......
}
public class SomeClass {
public void someMethod(Set<SomeInterface> s) {
...
}
}
Now to call someMethod(Set<SomeInterface> s) I create an enum set containing all of the elements, so I do following:
Set<? extends SomeInterface> choosen = EnumSet.allOf(SomeEnum.class);
SomeClass obj = new SomeClass();
obj.someMethod(choosen)
I get compile time error:
error: method someMethod in class SomeClass cannot be applied to given types;
required: Set<SomeInterface>
found: Set<CAP#1>
reason: actual argument Set<CAP#1> cannot be converted to Set<SomeInterface> by method invocation conversion
where CAP#1 is a fresh type-variable:
CAP#1 extends SomeInterface from capture of ? extends SomeInterface
IMP: I know that the error can be resolved by changing the method to someMethod(Set<? extends SomeInterface> s), but I CAN NOT change the signature of someMethod
Cast your Set to a Set<?> and then to the Set<Whatever> you want. This should resolve your issue...
Casting and ignoring the warning are obviously not type safe. (It may be safe in this particular case, but I would not recommend it anyhow).
But the most appropriate solution also depends on what someMethod is going to do with the Set<SomeInterface>. If it is only going to read from the given set, then you can pass in an unmodifiable view on the set:
Set<? extends SomeInterface> set = ...
Set<SomeInterface> viewOnSet = Collections.unmodifiableSet(set);
someMethod(viewOnSet);
This works because the unmodifiableSet view allows the returned view to be more specific: It is not possible to add new elements to this set, and thus, it is type-safe.
However, if the someMethod is going to modify the set, then you can use the approach that was already mentioned, namely creating a copy of the set with the desired type:
Set<? extends SomeInterface> set = ...
Set<SomeInterface> newSet = new LinkedHashSet<SomeInterface>(set);
someMethod(newSet);
Got another way of achieving what I want is:
Set<SomeInterface> choosen = new HashSet<SomeInterface>(EnumSet.allOf(SomeEnum.class));
someMethod(choosen);
Similar to what McDowell metioned in copyUp() method.
Related
This question already has an answer here:
Java generics : Type mismatch: cannot convert from Integer to K
(1 answer)
Closed 5 years ago.
Given this code sample:
class A {
}
public class TestGenerics {
private static <T extends A> T failsToCompile() {
return new A();
}
private static <T extends A> T compiles(T param) {
return param;
}
}
how come the first method doesn't compile, but the second one does?
The error is:
Incompatible types. Required: T. Found: A
Essentially what I'm trying to achieve is to return a concrete instance of a sub-type (for example of class B, that extends A). Sort of a factory method.
Edit: OK, for those who downvoted, I decided to elaborate a bit further. See the updated example, which no longer uses String (yes I'm aware that String is final, no need to state the obvious)
Edit 2: alternative version of the question:
How would you implement this method so that it compiles (without unchecked casts and warnings)?
abstract <T extends A> T failsToCompile();
Edit 3: Here's a code sample closer to the problem I'm trying to solve:
class Foo { }
class Bar extends Foo { }
class A<T extends Foo> { }
class B extends A<Bar> { }
public class TestGenerics {
private static <T extends Foo> A<T> failsToCompile() {
return new B();
}
}
Here, the method return type is A<T>. Considering that T is defined as a Foo or its subclass, and the definition of B is as follows: B extends A<Bar>, why can't I just return new B()? I guess the problem comes down to the fact that you can't assign List<Animal> dList = new ArrayList<Dog>(); and I understand why. But is there an elegant solution to this?
Ignoring the fact that String is final (so you can't have a sub-class of String), you can pass the generic class Class<T> into the method for the generic case. Like,
private static <T extends String> T get(Class<T> cls)
throws InstantiationException, IllegalAccessException {
return cls.newInstance();
}
I'm trying to elaborate my comment a bit more into an answer to the "why".
What you're showing in your question are generic methods (and not generic types), see e.g. Oracles "The Java™ Tutorials", Generic Methods.
Reasoning
Let's consider the explicit call for the working method: TestGenerics.<A>compiles(new A());
This instantiates the generic type T of your method call to class A. Remember that type erasure removes all these funky generic types when compiling, that the JVM doesn't see generic types and that the compiler handles generics. The compiler knows now, that you want to call the method with the generic type T "set" to class A. From that, it can deduct that the returned type is also of class A (as T is returned according to the methods code and as T is instantiated to A). That's all you gain here from using generics.
You can remove the <A> from your method call and make it look like an "ordinary" method call, as the compiler can deduct that T has to be A: TestGenerics.compiles(new A());
Let's look at TestGenerics.<B>compiles(new B()); with class B extends A {}. As above, the compiler knows that this method call will return an object of class B.
Now imagine the (not compiling) code TestGenerics.<B>compiles(new A());. The compiler will throw an error as the object passed to the method is not of type B. Otherwise the method would return an object of class A - but the generic type asserts that the method returns here an object of typeB.
That's actually equivalent to the example (B b = failsToCompile()) Andreas gave in his comment.
Until you instantiate a generic type - even if you set bounds (like T extends A) - it doesn't have a class type. You therefore can't return a concrete class, as this would not satisfy the generic type parameter.
Pizza Example
Just for fun, let's try to make a real world example for above reasoning: Pizza. For the sake of the example, let's assume that every Pizza is a subtype of the Margherita, i.e. you add ingredients to a Margherita to get your favorite other pizza.
class PizzaMargherita {};
class PizzaProsciutto {
PizzaProsciutto() {
super();
addIngredient(new Prosciutto());
}
}
Your compiles() method now bakes the pizza:
public static <P extends Margherita> P bake(P pizza) {
heat(pizza);
return pizza;
}
Bake a Margherita and get a (baked) Margherita out of your oven, bake a Prosciutto and get a Prosciutto.
Now think of this:
public static <P extends Margherita> P doesntBake(P pizza) {
return new PizzaMargherita();
}
An oven always returning a Margherita, independent of what you put into it ?!? The compiler doesn't approve that.
-> You need the concrete pizza to bake it or you need a workaround, like the type token:
public static <P extends Margherita> P bakePizza(Ingredients<P> ingredient) {
P pizza = buildPizza(ingredients);
return bake(pizza);
}
Workaround type token
You have to use a runtime-type token as #Elliott Frisch shows in his answer:
private static <T extends A> T failedToCompile(Class<T> c)
throws InstantiationException, IllegalAccessException {
return c.newInstance();
}
You can't instantiate a generic type - new T() doesn't work, as the JVM doesn't know anything about the generic type T. What you're looking for in edit 2 therefore doesn't work. But TestGenerics.<A>failedToCompile(A.class); works, as A.class is part of the java byte code.
Workaround type token & generic class
Depending on your specific requirements, a generic factory class might help you:
class Factory<T extends A> {
private final Class<T> typeToken;
public Factory(Class<T> typeToken) {
this.typeToken = typeToken;
}
public T build()
throws InstantiationException, IllegalAccessException {
return this.typeToken.newInstance();
}
}
You will still need some form of Map to get the correct factory to build the class you need, but you can now use whatever is available at the point where you need to create the Object of type T.
Map<String, Factory<?>> factories = new HashMap<>();
Map<DAO, Factory<?>> factories = new HashMap<>();
Map<ValueObject, Factory<?>> factories = new HashMap<>();
factories.get(valueObjectTypeA);
Others have clearly explained why the failsToCompile method doesn't compile. Andreas has even shown an example...
As to how to circumvect this, I think you should consider using a Supplier, which is just the factory you need:
private static <T extends A> T nowItCompilesFine(Supplier<? extends T> factory) {
return factory.get();
}
And you call it:
A a = nowItCompilesFine(() -> new A());
Or using a reference to a constructor:
A a = nowItCompilesFine(A::new);
Same with any descendant of A:
class Child extends A { }
List<Supplier<? extends A>> factories = Arrays.asList(A::new, Child::new);
Supplier<? extends A> factoryA = factories.get(0);
A a1 = nowItCompilesFine(factoryA);
Supplier<? extends A> factoryChild = factories.get(1);
A a2 = nowItCompilesFine(factoryChild);
System.out.println(a2.getClass().getSimpleName()); // Child
I was playing around with generics and now I am curious why I need to cast the "new Special()" to E before adding it to the Set.
I know that this is not really needed in this case, because I could use a Set of Base as well...
private static class Base {}
private static class Special extends Base{}
private <E extends Base> Set<E> doSomething(){
Set<E> someset = new HashSet<>();
someset.add(new Special());
return someset;
}
Suppose you had this:
final class SomethingElse extends Base {}
and this:
private <E extends Base> doSomething(Set<E> someset) {
someset.add(new Special());
}
Can you see the problem now?
E extends Base means that "E is an unknown type that extends Base". It doesn't mean "E is any type that extends Base."
In the example above, the problem is that one could call doSomething() like this:
Set<Special> onlySpecials = new HashSet<>();
doSomething(onlySpecials);
onlySpecials.stream()
.findFirst()
.ifPresent(Special::someSpecializedMethod); /* Boom! ClassCastException! */
Imagine that Base have two subtype: Special and VerySpecial.
And you call doSomething like this:
Set<VerySpecial> set = doSomething();
In this case your set will contain Special instance which is not what you expected because its type don not allow that.
Suppose I have and API method declared as following
public class Dummy {
public static class Result<ValueT extends Comparable> {
public ValueT value;
}
public static <ValueT extends Comparable> Result<ValueT>
getResult(Class<? extends Result<ValueT>> ofType) throws Exception {
return ofType.newInstance();
}
}
Now I'd like to invoke it relying on Java compile-time type verification and just can't find correct syntax to do this:
Attempts:
getResult(Result<Integer>.class) <-- expected syntax
public static void invokeGetResult() {
Result<Integer> intResult = getResult(Result<Integer>.class);
}
results in
error: <identifier> expected
Result<Integer> intResult = getResult(Result<Integer>.class);
^
getResult(Result.class) <-- just to try
public static void invokeGetResult() {
Result<Integer> intResult = getResult(Result.class);
}
results in
error: method getResult in class Dummy cannot be applied to given types;
Result<Integer> intResult = getResult(Result.class);
^
required: Class<? extends Result<ValueT>>
found: Class<Result>
reason: cannot infer type-variable(s) ValueT
(argument mismatch; Class<Result> cannot be converted to Class<? extends Result<ValueT>>)
where ValueT is a type-variable:
ValueT extends Comparable declared in method <ValueT>getResult(Class<? extends Result<ValueT>>)
getResult((Class<Result<Integer>>)Result.class) <-- just to try
public static void invokeGetResult() {
Result<Integer> intResult = getResult((Class<Result<Integer>>)Result.class);
}
results in
error: incompatible types: Class<Result> cannot be converted to Class<Result<Integer>>
Result<Integer> intResult = getResult((Class<Result<Integer>>)Result.class);
^
If the only purpose of passing the Class<...> is to instantiate it, consider using a Supplier<...> instead. It does not have this problem, and does not throw any exceptions.
Here is an example:
class SomeClass extends Result<Integer> {...}
public static <T extends Result<?>> T getResult(Supplier<T> constructor) {
return constructor.get();
}
Use like:
getResult(SomeClass::new); // Passes the constructor.
There isn't really such thing as a Class<Result<Integer>>. Class objects represent reifiable classes at runtime, and there is only one single Class object at runtime for the class Result, which you can get via the expression Result.class, which has type Class<Result>. There are no Class objects representing Result<Integer> or Result<String>, etc.
You can take the expression of type Class<Result> (which you get from Result.class) and do a bunch of unsafe casts on it to turn it into a Class<Result<Integer>> or something like that, for example:
`(Class<Result<Integer>>)(Class<?>)Result.class`
but not that this is unsafe. It is unsafe because the interface of Class has certain methods that return T (the type parameter of the class Class) based on runtime type operations with the class. For example, Class has a method .cast() which checks whether the passed object is an instance of the class, and if not, throws an exception, and if it is, then returns the object, as type T. If you call Result.class.cast(), it returns a Result, and the method indeed checks at runtime that the object is a Result. But if you call .cast() on an expression of type Class<Result<Integer>>, it returns type Result<Integer>, but the class could not have checked at runtime that the thing is a Result<Integer>, because 1) this is just the same Result class object, and 2) generic information doesn't exist at runtime. So you would get a Result<Integer> that might not be a Result<Integer>.
So basically, you need to think about what you are using this class object to do, and how it makes sense to have it as a Class<Result<Integer>> when all you can have at runtime is a class object representing the raw type Result.
Here you have a method that takes Class<? extends Result<ValueT>>. I am wondering why you have the wildcard here. Are you trying to have it accept subclasses of Result? Because if not, then the only thing that can be passed in is the unique Result class object itself, which means the parameter is basically pointless because it's always the same thing that can be passed in; in that case you might as well get rid of the parameter and just do:
public static <ValueT extends Comparable<? super ValueT>> Result<ValueT>
getResult() throws Exception {
return new Result<ValueT>();
}
If you are going to accept subclasses of Result, then you're assuming that all subclasses must have a no-parameter constructor, as you are calling .newInstance() on it, which is bad design. You should use something like a Supplier as Jorn Vernee's answer suggests.
EDIT: I did not understand clearly the original intentions. This example should work for your call, however it is a bit hacky and not so recommended.
public class Dummy {
public static class Result<ValueT extends Comparable> {
public ValueT value;
}
public static <ValueT extends Comparable> Result<ValueT>
getResult(Class<? extends Result<ValueT>> ofType) {
return null;
}
}
You can call it like this:
Dummy.Result<Integer> result = Dummy.getResult(new Result<Integer>(){}.getClass());
The compile time verification should work with this example, as you are creating an anonymous empty class and it's type information can be retrieved successfully.
You could also do a type cast as #Jorn suggested in comments, although your compiler will warn you about the fact it is an "unchecked cast".
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 2 interfaces accordingly to abstract factory pattern:
public interface GenericObjectInterface<T extends Number>{
public T getResult();
}
public interface AbstractFactoryInterface{
public <T extends Number> GenericObjectInterface<T> createGenericObject();
}
I have an abstract class implementing GenericObject, but it's still unaware of the concrete type (it does only generic operations on Number):
public abstract class GenericAbstractClass<T extends Number> implements GenericObjectInterface<T>{ }
Then I have a series of concrete class extending that perform generic parameter substitution:
public class IntegerObject extends GenericAbstractClass<Integer>{
public Integer getResult(){}
}
....
Now, from inside an implementation of the factory I build the concrete type, that's implementing GenericObjectInterface but has lost it's generic parameter:
public class ConcreteFactory{
public <T extends Number> GenericObjectInterface<T> greateGenericObject(Class<T> c){
if (c.class.isInstance(Integer.class)){
IntegerObject obj = new IntegerObject();
//I would like to return obj
GenericObjectInterface<T> a = new IntegerObject(); //errror
GenericAbstractClass<T> a = new IntegerObject(); //errror
return a;
}else if (c.class.isInstance(Double.class)){
}
}
}
I would like to return obj that implements GenericObjectInterface but I don't know how can I do it.
how can I solve this?
I'm used to abstract factory but I've never used it with generics. Am I doing some mistakes in interpreting the pattern?
If your method returns an IntegerObject why don't you just return GenericObjectInterface<Integer>? You already know the parameter type.
In that case, just add a generic parameter to AbstractFactoryInterface, too:
public interface AbstractFactoryInterface<T extends Number> { ... }
public class ConcreteFactory implements AbstractFactoryInterface<Integer> { ... }
In your implementation the type of T would be inferred from the assignment, and thus you could do this:
GenericObjectInterface<Double> g = new ConcreteFactory().greateGenericObject();
In that case T would be Double but you'd use Integer internally, resulting in this:
GenericObjectInterface<Double> a = new IntegerCell();
Since the compiler can't ensure that T will always be of type Integer it won't allow you to do that assignment.
Abstract factory is characterized by the factory method returning an interface or abstract class reference instead of the concrete reference. It does not extend to type parameters.
Think of it this way: should you be able to do this?
public class ConcreteListFactory {
public <T> List<T> createList() {
return new ArrayList<String>();
}
}
What if the caller wanted a List<Integer>?
If you want your factory to return a generified type, you should have your concrete class accept the type parameter. Otherwise have your factory method return a GenericObjectInterface<Integer>.
Alternatively, you could have your method accept a type token (Integer.class). For example:
public <T extends Number> GenericObjectInterface<T> createGenericObject(Class<T> clazz) {
if ( clazz.equals(Integer.class) ) {
return (GenericObjectInterface<T>) new IntegerObject();
}
}
This will result in an unchecked cast warning but you can prove to yourself that it is safe, and thus suppress the warning or ignore it.
Generally, factories are not implemented as generics because you can't examine the type of the generic to determine the type of object to create (you can't do T.getClass) which is why #Mark's example causes the class to be passed in as an argument.
I think, more usually you would have multiple concrete factories. One for each Number type that you intend to support.
public interface AbstractFactoryInterface<T extends Number> {
public GenericObjectInterface<T> createGenericObject();
}
class IntegerFactory implements AbstractFactoryInterface<Integer>...
class LongFactory implements AbstractFactoryInterface<Long>...
You could then create a Map<Class, AbstractFactoryInterface>...
Map<Class, AbstractFactoryInterface> myMap = ...;
myMap.put(Integer.class, new IntegerFactory());
myMap.put(Long.class, new LongFactory ());
casting is perfectly fine here. if c==Integer.class, then T=Integer, casting GOI<Object> to GOI<T> is absolutely correct. It is a checked cast because you have checked that T=Integer before casting, therefore the unchecked warning can be legitimately suppressed.