Please have a look at below code listing :-
package com.test;
class XParam implements Comparable<XParam>{
#Override
public int compareTo(XParam o) {
// TODO Auto-generated method stub
return 0;
}
}
public class Main {
public static void main(String[] args) {
Comparable<XParam> param = new XParam() ;
SomeClass object = new SomeClass() ;
object.setData( param );
}
}
Now,
object.setData( param ); //third statementt in the main method in above code listing
compiles fine, if i make SomeClass generic with formal type parameter
<T extends Comparable<T>>
as shown below :-
class SomeClass<T extends Comparable<T>>{
public void setData(T data) {
}
}
But, object.setData( param ); gives below compile time error in eclipse :-
Bound mismatch: The generic method setData(T) of type SomeClass is not applicable for the
arguments (Comparable<XParam>). The inferred type Comparable<XParam> is not a valid
substitute for the bounded parameter <T extends Comparable<T>>
if i apply the same formal type parameter at method level, rather then adding it at class level as shown below :-
class SomeClass{
public <T extends Comparable<T>>void setData(T data) {
}
}
Any good explanation/reference to understand this concept is highly appreciated.
Thanks.
I think the only reason you're getting a bound mismatch with one way and not the other is because it doesn't seem you are parametrizing the declaration of SomeClass, and are thus using a raw type. If you use a raw type, the compiler doesn't bother with any generic checks, so you get no complaints.
I think that if you attempted to genericize your class with Comparable<XParam> you would get the same error you got when you tried to call the generic method with an incorrect bound.
As for the generic method, the error makes sense.
If your bound is T extends Comparable<T>, and you pass the method a Comparable<XParam>, the compiler will infer T == Comparable<XParam> and the method will look to see if the argument extends Comparable<T> == Comparable<Comparable<XParam>>. Which it doesn't.
I believe that your method will work if you call the method with an argument of type XParam, as XParam extends Comparable<XParam>.
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.
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".
This code:
public class Base<E> {
static void main(String[] args) {
Base<? extends Base> compound = new Base<Base>();
compound.method(new Base());
} // ^ error
void method(E e) { }
}
Gives such compilation error:
Error:(4, 17) java: method method in class Base<E> cannot be applied to given types;
required: capture#1 of ? extends Base
found: Base
reason: actual argument Base cannot be converted to capture#1 of ? extends Base by method invocation conversion
From what I understand, E becomes ? extends Base, something that extends Base. So, why new Base() can't be passed?
Base<? extends Base> compound means that compound is parameterized with some subtype of Base, but you don't know which one. If the parameter type is unknown, then the compiler can't check that new Base() matches that type.
E does become ? extends Base You might think that the method would accept any subtype of Base, but it doesn't. It only accepts one specific but unknown subtype of Base.
So you can't call any method that takes E as a parameter, but you can call a method that returns E.
Allowing your example to compile would lead to type-safety errors like:
List<? extends Object> list = new ArrayList<String>();
list.add(new Object()); // Error - Can't add object to list of Strings.
Try the following to define your method as a generic:
<E> void method(E e) { }
Note the the addition of the <E>.
This fixed the compilation error for me. Although, I would have expected the parameter you supplied at class-level to have applied.
I have lost in the Jungle of Generics, please help me :) I have something like this:
public class BaseClass<TYPE> {
public BaseClass(Class<TYPE> clazz) {};
}
public class FirstLevelClass<REFRESHABLE
extends RefreshableInterface> extends BaseClass<REFRESHABLE> {
public FirstLevelClass(Class<REFRESHABLE> clazz) {
super(clazz);
};
}
public class Argument<T extends AnyOtherClass>
implements RefreshableInterface {
public refresh() {}
}
pulbic class ProblematicClass
extends FirstLevelClass<Argument<AnyOtherClassDescendant>> {
public ProblematicClass() {
//Compiler error: Constructor
//FirstLevelClass<Argument<AnyOtherClassDescendant>>(Class<Argument>) is undefined
super(Argument.class);
}
}
As far as I think, the compiler should accept Argument since it implements RefreshableInterface.
Why do I get this error?
How can I make the ProblematicClass working?
ps: if you have better title for this, please change it. I could not make up better.
Issue is, your constructor expects a Class<T>, and T in your code is inferred as Argument<AnyOtherClassDescendant>.
So, you should pass a Class<Argument<AnyOtherClassDescendant>>, and you're passing Class<Argument>. But you can't pass that Class instance directly, as you cannot do Argument<AnyOtherClassDescendant>.class.
You can however, solve the issue by typecasting the class to required instance:
public ProblematicClass() {
super((Class<Argument<AnyOtherClassDescendant>>)(Class<?>)Argument.class);
}
Note, how you've to typecast Class<Argument> first to Class<?>, and then the resultant type to Class<Argument<AnyOtherClassDescendant>>. There is no simple way to achieve that.
The reason behind this is, there is only a single Class instance for all parameterized instantiation of a generic type, that is associated with the class itself. A single compilation unit of a generic type, compiles to just a single class file. I guess this is different in how C++ implements templates. There you get different machine codes for different instantiation.
So, if you execute the below code, you'll get true as output:
List<String> strList = new ArrayList<String>();
List<Integer> intList = new ArrayList<Integer>();
boolean isSameClassInstance = strList.getClass() == intList.getClass();
System.out.println(isSameClassInstance);
Just wonder why type parameter are not allowed after the class name on the constructor. I mean what's the reason behind this. Is it becos' the type parameter already defined on the class header and so doesn't make sense to have it on the constructor?
Class A <E> {
public E e;
A <E> {
}
}
Just curious
You can define type parameters for a constructor, using the same syntax used for methods.
However, it's important to realize this is a new type parameter, visible only during execution of the constructor; if it happens to have the same name as a type parameter on the class, it will hide that parameter in the larger scope.
class Foo<T>
{
<T> Foo(T bar) /* This "T" hides the "T" at the class level. */
{
...
If you define generics in class level they must be declared during declaration of class.
class A<T>{}
Do you want to declare T when declaring constructor, i.e. something like this:
class A {
public A<T>() {
}
}
But in this case you cannot use T before constructor when you wish to declare fileds:
class A {
private T t; // this will throw compilation error: T is undefined.
public A<T>() {
}
}
I think that this is the reason that Sun defined existing syntax for generics.
Although you can use generic type as parameter of constructor:
class A<T> {
public A(T t) {
}
}
Well, at least the following seems to compile in Eclipse:
public class A{
private boolean same;
public <T> A(T t1, T t2, Comparator<? super T> comparator){
this.same = (comparator.compare(t1, t2) == 0);
}
...
}
As the name says, it is a type parameter, and so its scope is wider than just a constructor or a method.