I have a piece of code which does not compile:
import java.util.Optional;
public class Test {
private <T> Optional<T> g(
Class<T> typeClass) {
throw new RuntimeException("???");
}
private void f() {
Optional<Optional<Integer>> x;
x = g(Optional.class);
}
}
Compiler says that g(Optional.class) is wrong, because:
incompatible types: inference variable T has incompatible equality constraints Optional<Integer>,Optional
I alse tried passing Optional<Integer>.class, but it also does not compile - as far as I understand, this is an illegal syntax.
So, what argument should I pass to g() so this example compiles?
The problem here is that in order to call g() we must have an object of type Class<Optional<Integer>>. We can get this object in this way, for instance:
x = g((Class<Optional<Integer>>) Optional.empty().getClass());
And this is a solution of the problem.
Related
When a generic static method is written like this:
public static <T extends SuperClass> T foo() {
return new SupperClass();
}
, an incompatible types compilation error is thrown indicating that SuperClass cannot be converted to T.
On the other hand, when another generic static method is written like this:
public static <T extends SuperClass> void bar(T val) {
// do something....
}
the code compiles just fine when the function is called using: bar(new SuperClass()).
Also the same thing happens when using a generic class with the bounded generic type as it's type parameter,
whether it is the return type or a parameter of the function.
For example this causes the same compilation error to be thrown:
public static <T extends SupperClass> GenericClass<T> foo() {
return new GenericClass<SuperClass>();
}
indicating that GenericClass<SuperClass> cannot be converted to GenericClass<T>.However, this:
public static <T extends SuperClass> void bar(GenericClass<T> val) {
// do something....
}
compiles just fine when it is called using bar(new GenericClass<SuperClass>).
So to sum up the question, why can a generic method whose formal type is bounded with some supertype, and takes a parameter of this formal type, be called with an object of the supertype, while it can't return an object of the supertype when the return type is specified as the formal type ?
Thanks in advance.
The compiler is looking at the static type when doing compilation.
When you're trying to return a
new SupperClass()
object - the compiler must be sure that the static types are matched - and is doing so by converting from SupperClass to T.
When you'll do this casting yourself:
(T) new SupperClass()
it will give you a warning on unchecked cast - because technically you can program it but its successfulness depends on runtime types...
When you're returning void - you're returning nothing - so no casting needs to be done.
A comment on casting: casting up will always succeed (you can always loose information) casting down - depends on the dynamic type and not always succeed.
In the following sample, I can pass a Consumer<Optional<Integer> to foo, but not a Consumer<Optional<Number>>. On the other hand, I can pass either type to foo2, but then I can't call the accept method of the consumer from the method body. Is there a way to change the foo method so that this works? My initial intuition was to try void foo(Consumer<Result<? super T>> c) but that apparently doesn't mean what I would assume.
import java.util.Optional;
import java.util.function.Consumer;
public class test<T> {
public void foo(Consumer<Optional<T>> c) {
Optional<T> t = null;
c.accept(t); // compiles
}
public void foo2(Consumer<? extends Optional<? super T>> c) {
Optional<T> t = null;
c.accept(t); // doesn't compile
}
public static void bar() {
test<Integer> t = null;
Consumer<Optional<Number>> crn = null;
Consumer<Optional<Integer>> cri = null;
t.foo(cri); // compiles
t.foo(crn); // doesn't compile
t.foo2(cri); // compiles
t.foo2(crn); // compiles
}
}
The reason for this is that Optional isn't special from the point of view of the type system: we know that Optional only has a provider method (Optional.get()) and that it has no consumer methods (like Optional.set(T)); but the compiler doesn't.
So, the compiler it won't let you pass an Optional<Integer> where an Optional<Number> is required: it is preventing you from ever calling that mythical set method, in case you passed in a Double instead of an Integer.
The only way around this is to change the Optional<T> into an Optional<S>, where S is a supertype of T. You can do this by either:
Casting - which you know is safe, because of the immutability of Optional and its lack of consumer methods; but you get an unchecked warning (which is actually fine to suppress, because of the properties of Optional).
Creating a new Optional of the right type - maybe more pure, but has the runtime overhead of creating the new instance.
In order to write such a thing in a method, you would have to write it as a static method (probably in the test class, but it could be elsewhere); Java's type system isn't expressive enough to be able to write the required constraints on an instance method's signature:
public static <T, S extends T> void foo3(Consumer<Optional<T>> c, test<S> test) {
Optional<S> s = null;
#SuppressWarnings("unchecked") // Safe because of properties of Optional.
Optional<T> t = (Optional<T>) (Optional<?>) s;
c.accept(t);
}
and invoke like this (using the values of cri, crn and t from the question code):
foo3(cri, t); // compiles
foo3(crn, t); // compiles
Ideone demo
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 recently started writing a generic object mapper for a project and ran into something I don't quite understand. Given the following:
public class G<X> {
public G(Class<X> c) { }
public void m(X x) { }
public static <T> G<T> create(Class<T> c) {
return new G<T>(c);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<?> t = create(o.getClass());
t.m(o);
}
}
I get the following compilation error:
m(capture#402 of ?) in G<capture#402 of ?> cannot be applied to (java.lang.Object)
I can't seem to figure out a way to properly cast t to make this compile. What am I missing? Using JDK 1.6.
EDIT:
This is not an academic question. I'm trying to write a mapper from hibernate objects to their corresponding DTO to be passed around in the REST layer. The assumption is that for each ORM object Foo, there might exist a class FooDTO that has a constructor that takes an instance of Foo as a parameter. The generic class that maps Foo to FooDTO will encapsulate this assumption and throw appropriate exceptions if FooDTO doesn't exist or doesn't have the proper constructor:
class Mapper<Foo,FooDTO> {
private final Constructor<FooDTO> dtoConstructor;
Mapper(Class<Foo> fooClass, Class<FooDTO> fooDTOClass){
// find the constructor of FooDTO or throw ...
}
public FooDTO map(Foo f){
return dtoConstructor.newInstance(f);
}
// this factory is for convenience when we don't know the type of FooDTO:
public static Mapper<X,Object> create(Class<X> fromClass){
Class<Object> dtoClass = // ... find it
return new Mapper<X,Object>(fromClass,dtoClass);
}
}
This seems to break if I pass a generic object class to create.
Note that my actual implementation has all FooDTO classes extends from a generic super class, i.e., the signature of Mapper is actually something like Mapper<Foo,DTO<Foo>>. I don't think that's relevant here.
EDIT 2:
Actually the suggestion of changing the line G<?> t = create(o.getClass()); to G<Object> t = (G<Object>) create(o.getClass()); worked in this context.
Unfortunately I didn't realize that the fact that my class is more complex actually has an impact. Here's a more complete example (I apologize for the piecemeal question):
public class Y<T> {
}
public class G<X, Z extends Y<X>> {
public G(Class<X> c, Class<Z> s) {
}
public void m(X x) {
}
public static <T, S extends Y<T>> G<T, S> create(Class<T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
G<? extends Object, Y<? extends Object>> t = create(o.getClass());
t.m(o);
}
}
In this case the object Class<S> is created using reflection and some conventional location for objects of that type. That part works fine and should be irrelevant to this discussion. The error I am getting now is the following:
inconvertible types
found : G<capture#155 of ? extends java.lang.Object,Y<capture#155 of ? extends java.lang.Object>>
required: G<java.lang.Object,Y<java.lang.Object>>
And if I change the incriminated line to:
G<Object, Y<Object>> t = (G<Object, Y<Object>>) create(o.getClass());
I get a similar error:
java: inconvertible types
required: G<java.lang.Object,Y<java.lang.Object>>
found: G<capture#1 of ? extends java.lang.Object,Y<capture#1 of ? extends java.lang.Object>>
Once again, I apologize for the piecemeal information. I am sorting through this while I am writing.
You have passed the Class object from the getClass() method, which returns a Class<?>, meaning that you had to declare t to be a G<?>.
You cannot call a method with a generic type parameter when the generic type parameter of the variable is a wildcard. The compiler doesn't know which specific class the wildcard really is, so it cannot guarantee type safety when such a method is called. It's the same reason that add can't be called on a List<?>.
To get this to compile, you must use a class literal, to avoid having a Class<?>, and declare t not to have a wildcard.
G<Object> t = create(Object.class);
Then
t.mo(o);
will compile.
What you have here is a consumer. However, the following seems to compile (in Eclipse).
public static class G<X, Z extends Y<X>> {
public G(Class<? extends X> c, Class<Z> s) {}
public void m(X x) {}
public static <T, S extends Y<T>> G<T, S> create(Class<? extends T> c) {
Class<S> s = null; // find this via some reflection magic
return new G<T, S>(c, s);
}
public static void main(String[] args) {
Object o = ""; // irrelevant!
create(o.getClass()).m(o);
}
}
You're creating a G<Object> and then assigning it to a variable of type G<?>. The method invoked takes a variable of the generic type, which won't take anything for <?>. If you change the variable to G<Object> it will work.
Since you are specifying G<?>, javac is expecting to figure out what the generics are (what classes do they represent). Changing the statement to G t = create(o.getClass()); fixes the errors.
capture errors generally mean that the compiler is unable to figure out the classes...
Its not really clear what you are trying to do... Perhaps that information would be useful in helping you more...
I have simple generic class as shown below:
public class Test<T extends Number> {
public void doSomething() {
Test t = new Test();
t.getNumber();
}
public T getNumber() {
T d = new Double("1.5"); // I get an compiler error here!
return d;
}
}
The getNumber method returns T (which extends Number) and in its implementation it instantiates a Double. The compiler is throwing up an error on the line:
T d = new Double("1.5"); // I get an compiler error here!
The error is:
Incompatible types:
[ERROR] found : java.lang.Double
[ERROR] required: T
Since T extends Number, I would have expected this to work. Am I missing something?
T extends Number, but that does not mean that it extends Double. Double is only one of the known subclasses of Number.
It's not right to use generic parameters on the left and specific implementation on the right.
You should get a compiler warning when you instantiate test.
Imagine that you instantiate Test<Integer>. Then the line in the getNumber method becomes:
Integer d = new Double("1.5");
Obviously, it should throw a compiler error.
I think that you should not use a generic type argument - replace your class with:
public class Test {
public Number getNumber() {
Number d = Double.valueOf("1.5"); // No compiler error
return d;
}
}
Another solution would be to express the condition that you can use any superclass of Double as a type argument, ie:
public class Test<T super Double> {
public T getNumber() {
T d = Double.valueOf("1.5"); // No compiler error
return d;
}
}
A few general tips:
Do not box primitive types without a good reason.
Do not use new to instantiate boxed primitive types, use the static factory methods in the boxing classes instead.
Do not use generic types without a good reason. And when you go to the hassle of defining a generic type, do not instantiate it without a type parameter.
T d = (T)new Double("1.5");
You have to type cast to T. Even though it solves your problem I feel suspicious of what you are doing.
The generic type definition class Test<T extends Number> means that whoever chooses to create an object of your Test class can choose which type parameter to use. The user chooses, not you as the class implementor.
This means you can't be sure which type it will be, and thus your getNumber() method can only safely
return an object which somehow came in as a T object
return null
return an object which some other method returning T gave back.
return an object created from a Class<T> (or Class<? extends T>)
return an object from a Collection<T> (or Collection<? extends T>)
something similar