Type conversion error in Generic - java

I have just started learning about Generic.Here i'm trying to set value of global obj to the local obj's value.But i'm getting type conversion error.What is the cause for this error?
class GenUpperBound<T>
{
T obj;
public <T extends Number> void set(T obj)
{
this.obj=obj;
}
public static void main(String...q)
{
GenUpperBound<Integer> w=new GenUpperBound<>();
w.set(10);
}
}
Here is the error....
GenupperBound.java:6: error: incompatible types: T#1 cannot be converted to T#2
this.obj=obj;
^
where T#1,T#2 are type-variables:
T#1 extends Number declared in method <T#1>set(T#1)
T#2 extends Object declared in class GenUpperBound
1 error

The constructor-scoped type-parameter <T extends Number> hides the class-scoped type-parameter <T>. Those two T's do not represent the same type.
This is why the compiler rejects to compile your code, because the argument in the constructor could be potentially of a different type than the type, by which the class is parameterized. For example:
new GenUpperBound<String>(new Integer(1));
The difference can be clearly seen if you change the constructor-scoped type-parameters' name to U:
class GenUpperBound<T> {
T obj;
public <U extends Number> void set(U obj) {
this.obj=obj;
}
...
}
Now this compiles fine, too, but T and U clearly represent different types.
You could fix this problem with:
class GenUpperBound<T extends Number> {
T obj;
public void set(T obj) {
this.obj=obj;
}
...
}
Now there isn't a second T type-parameter, but the constructor uses the class-scoped one. In this case statements like new GenUpperBound<String>(new Integer(1)); will not compile, because the argument is not of the same type as the one that the instance is parameterized with.

Try this:
class GenUpperBound<T extends Number>
{
T obj;
public void set(T obj)
{
this.obj=obj;
}
public static void main(String...q)
{
GenUpperBound<Integer> w=new GenUpperBound<>();
w.set(10);
}
}

You have to declare your class like
class GenUpperBound<T extends Number>
because otherwise your obj could for example be of type String and you can't assign a Number to a String.

Related

How does using wildcard in return type differ from defined generic type?

I have the following class, which compiles fine
class MyClass<T> {
MyClass<? extends Number> foo() {
return new MyClass<Integer>();
}
}
but when I change my return type to this
class MyClass<T> {
<R extends Number> MyClass<R> foo() {
return new MyClass<Integer>();
}
}
I start getting error on my return statement, saying
incompatible types: MyClass<java.lang.Integer> cannot be converted to MyClass<R>
it is because for second case
MyClass<Double> d = foo();
is valid call, but for first one is not.

Java Generics capture wildcard with extends

In this question, I saw that I can use a helper method to 'capture' the wildcard generic into a type T to do type safe operations, like so:
void foo(List<?> i) {
fooHelper(i);
}
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
But when I try to do that with the extends keyword, it doesn't work:
void bar() {
barHelper(String.class); //works fine
}
void bar(Class<? extends Comparable<?>> clazz) {
barHelper(clazz); //doesn't compile
}
<T> void barHelper(Class<? extends Comparable<T>> clazz) { }
I get the following error:
The method fooHelper
(Class<? extends Comparable<T>>)
in the type Test is not applicable for the arguments
(Class<capture#1-of ? extends Comparable<?>>)
Is there a way to capture a wildcard when using the extends keyword?
My background is, I have a list of classes that extends a given class A, each one of them with a different generic argument T. For each class, I want to get a reference to its T class, and I was trying to do it type safely.
I think generic constraints must be where the type parameter <T> is declared, so instead of
<T> void barHelper(Class<? extends Comparable<T>> clazz) { }
I would write
<A, B extends A> void barHelper(Class<B> clazz) { }
Or if the super/top class is known
<T extends MySuperType> void barHelper(Class<T> clazz) { }

Bounded types: Multiple bounds

I have read this article here and tried to figure out how to work with bound types. What I try to achieve is a parametrized method that handles four different cases:
T extends B only
T extends B and I (here D)
T extends I only
everything else
So here is the code:
public class Main {
public static void main(String... args) {
B b = new B();
D d = new D();
I i = new I() {
};
handle("aaasd");
handle(b);
handle(d); <---- Problem 1
handle(i);
}
public static class B {
}
public static interface I {
}
public static class D extends B implements I {
}
public static <T> void handle(T objT) {
System.out.println("T");
}
private static <T extends B> void handle(T obj) {
System.out.println("B");
}
public static <T extends B & I> void handle(T objT) { <--- Problem 2
System.out.println("B+I");
}
private static <T extends I> void handle(T obj) {
System.out.println("I");
}
}
The compiler complains and says two things:
Ambiguous call
The method handle(Main.D) is ambiguous for the type Main
I guess the problem is caused by the same cause as Problem number 2. The & I clearly bounds the type of T to a subtype of B AND I thus removing ambiguity in my opinion.
Same erasure handle
Method handle(T) has the same erasure handle(Main.B) as another method in type Main
My guess is that this is the real cause for all the problems. Java somehow removes bounding to I during runtime? But when I call the method with type B this doesn't call the annoted method.
Can someone explain how I fix the problem/distinguish between B, B&I and I?
Java somehow removes bounding to I during runtime?
No, Java removes every type information at runtime (except for reflection purposes) which is called type erasure.
Using bounds the compiler would be able to translate your code to handle(Object), handle(B) and handle(I) but in the T extends B & I case the compiler would get conflicts.
AFAIK, there's no way to fix this without having a common bound, e.g. T extends D instead of T extends B & I where D extends B implements I or to change the method name or add another parameter.
Another way might be to add the logic in the B+I case to either the B or I method and check for the second condition inside, e.g.
private static <T extends B> void handle(T obj) {
if( obj instanceof I) {
System.out.println("B+I");
}
else {
System.out.println("B");
}
}
There's a concept known as type erasure that applies to all generics in Java. With generic methods, after compilation, the methods in the byte code appear as their erasure, so
public static <T> void handle(T objT) {
System.out.println("T");
}
private static <T extends B> void handle(T obj) {
System.out.println("B");
}
public static <T extends B & I> void handle(T objT) { <--- Problem 2
System.out.println("B+I");
}
private static <T extends I> void handle(T obj) {
System.out.println("I");
}
actually become
public static void handle(Object objT) {
System.out.println("T");
}
private static void handle(B obj) {
System.out.println("B");
}
public static void handle(B objT) {
System.out.println("B+I");
}
private static void handle(I obj) {
System.out.println("I");
}
The left-most bound of a type variable is what a parameter of that type gets replaced with. As you can see, both your 2nd and 3rd method have the same name and same parameter types, ie. the same signature. This cannot be allowed by the compiler.
However, the syntax of bounds forces you to provide the class type before any interface types so
<T extends I & B>
wouldn't work. It also wouldn't work because your 4th method would again have the same erasure.
Additionally, invoking
handle(d);
is a problem since both the 2nd and 4th method could handle it, none is more specific. This is known as overloading ambiguity.

Java Generics - inserting inner type parameter

I am new to java. I am just trying to pass Comparable<String> into a method parameter of generic type <E extends Comparable<E>> . I believe the meaning of <E extends Comparable<E>> is any object that extends Comparable. Please let me know how to pass Comparable<String> or any object that extends Comparable<String> and has an other object in it.
Compiler is giving me error The inferred type Compare<String> is not a valid substitute for the bounded parameter <E extends Comparable<E>>
Code:
public class Compare<T> implements Comparable<T>{
public int compareTo(T o) {
return 0; // Not worried about logic
}
}
class CompareTest{
public <E extends Comparable<E>>void testGeneric(E e){
System.out.println("Executed");
}
public static void main(String args[]){
Compare<String> compare = new Compare<String>();
CompareTest test = new CompareTest();
test.testGeneric(compare);
//The inferred type Compare<String> is not a valid substitute for the bounded
//parameter <E extends Comparable<E>>
}
}
E extends Comparable<E> means: a type E that is able to compare to other objects of the same type E.
But your Compare type doesn't qualify. It can't compare with another Compare. A Compare<T> can only compare itself to a T, and not to a Compare<T>, since it's declared as
public class Compare<T> implements Comparable<T>
It's quite hard to understand what you want to achieve with this Compare type.
Your method
public <E extends Comparable<E>> void testGeneric(E e){
expects a type E that is a sub type of Comparable<E>. But you are passing it a Compare<String> which is not a sub type of <Comparable<Compare<String>>, but a sub type of Comparable<String>.
You'll have to clarify what you are trying to do if you need more help.
The error in my IDE says:
Inferred type 'Compare<java.lang.String>' for type parameter 'E' is not within its bound;
should implement 'java.lang.Comparable<Compare<java.lang.String>>'
It seems that E is inferred as Compare<String> instead of String. To get E to be String, try this:
public <E extends Comparable<E>> void testGeneric(Comparable<E> e){
To define a class as being comparable, the generic parameter to Comparable must be the class itself:
public class MyComparable implements Comparable<MyComparable> {
public int compareTo(MyComparable o) {
return 0;
}
}
Applying that to your class, you get the following code (which compiles):
public static class Compare<T> implements Comparable<Compare<T>> {
public int compareTo(Compare<T> o) {
return 0; // Not worried about logic
}
}
class CompareTest {
public <E extends Comparable<E>> void testGeneric(E e) {
System.out.println("Executed");
}
}
public static void main(String[] args) {
Compare<String> compare = new Compare<String>();
CompareTest test = new CompareTest();
test.testGeneric(compare);
}

Generics Subtyping issue in java

I am trying to learn Subtyping in Java and I am not an better person in generics so I am getting this issue or doubt-
import java.util.ArrayList;
import java.util.Collection;
interface Animal<T>{}
class Lion implements Animal<Lion>{}
class Butterfly implements Animal<Butterfly>{}
class Cage<T>{
public <T> void addAnimal(T t){
}
}
interface CageAnimal<E> extends Collection<E>{}
public class SubType<T> {
public <T> SubType() {
Lion lion = new Lion();
Butterfly butterfly = new Butterfly();
/**
* **Here inside Lion cage, we added Butterfly : WRONG**
*/
Cage<Lion> cageLion = new Cage<Lion>();
cageLion.addAnimal(lion);
cageLion.addAnimal(butterfly);
CageAnimal<Lion> cageAnimalLion = (CageAnimal<Lion>) new ArrayList<Lion>();
cageAnimalLion.add(lion);
//cageAnimalLion.add(butterfly);//Butterfly is Not Supposed to add here as it is the cage of Lion
}
}
In the above example when I declare Cage , why I am able to add Butterfly and in the Same case when I made CageAnimal type, I am not able to add any Buttefly
Cage<Lion> cageLion = new Cage<Lion>();
cageLion.addAnimal(lion);
cageLion.addAnimal(butterfly);
and in case of Cage
Cage<Animal> cageAnimalLion = new Cage<Lion>();
cageAnimalLion.addAnimal(lion);
cageAnimalLion.addAnimal(butterfly); //Throwing Compile Error
This line
public <T> void addAnimal(T t){
should probably be
public void addAnimal(T t){
Declare Cage class like this:
class Cage<T extends Animal> {
public void addAnimal(T t) { ... }
}
If you declare the addAnimal method in the following way...
public void <T> addAnimal(T t)
... you are "hiding" the T type parameter with a different type parameter with the same name. It is the same as if you declared the method like this:
class Cage<T extends Animal> {
public void <X> addAnimal(X t) { ... }
}
...which is obviously not doing its job. On the other hand, in the first version I wrote, both the T in declaration of the class and the method are the same.
Moreover declaring <T extends Animal> bound ensures that the cage can only be of type that extends an Animal, i.e. Cage<Lion>, Cage<Butterfly>, but Cage<String> is illegal.
And of course, you cannot cast an ArrayList to CageAnimal, that will fail at runtime with a ClassCastException, because ArrayList in not a subtype of CageAnimal.
Because CageAnimal and Cage are very different things. Looks how you've defined generic parameter for Cage:
public <T> void addAnimal(T t){
}
This <T> you put on the method, means that method has its own generic parameter, different from the one you've defined in class. If you remove it from method signature it will use generic parameter of the class.
E.g.
public void addAnimal(T t)
Your problem is that fundamentally your Cage will accept any T, and therefore any Animal. The various T's don't all refer to the same value of T, they're variables local to the class or method.
What you could write is something like this:
public class Cage<T> {
public void addAnimal(Animal<T> caged) {
}
}
Now you will at least get compiler errors in the common case of:
Cage<Lion> c=new Cage<Lion>();
c.add(new Butterfly()); // should error AFAIK
However it will be reduced to a warning in case of:
Animal butterfly=new Butterfly();
Cage<Lion> c=new Cage<Lion>();
c.add(butterfly); // warning about raw types... IIRC
Because, fundamentally Cage will still accept any Animal.
EDIT: Note that the earlier mentioned answer of removing the <T> local to the addAnimal method will work better for this purpose.
By declaring public <T> void addAnimal(T t) you're parameterising the method as well as the class Cage. This T has no relation to the T in Cage<T>.
You can either have:
class Cage<T extends Animal<T>> {
public void addAnimal(T animal) {
}
}
or, if you want the Animal returned then have:
class Cage<T extends Animal<T>> {
public T addAnimal(T animal) {
}
}
class Cage<T>{
public <T> void addAnimal(T t){
}
}
The Cage class has a generic method addAnimal. The generic type associated with the method causes the generic type associated with the class to be ignored and the type of the parameter to be used as the generic type for the method.
Try executing the following example to see what is happening:
public class TestCage {
/**
* #param args
*/
public static void main(String[] args) {
Cage<String> cage1 = new Cage<String>();
cage1.addAnimal(new String("test1"));
cage1.addAnimal(new Integer(1));
cage1.addAnimal2(new String("test2"));
//cage1.addAnimal2(new Integer(1)); //Uncomment to throw error
}
}
class Cage<T>{
public <T> void addAnimal(T t){
System.out.println("T: " + t.getClass().getName());
}
public void addAnimal2(T t){
System.out.println("T: " + t.getClass().getName());
}
}
In summary, by adding a generic method to the class, the generic type parameter of the class is ignored and the type of the parameter passed into the method is used as the generic type parameter of the method.
Try to take the <T> out of public <T> void addAnimal(T t).

Categories