I am learning Generics, and while learning come across a sample code which, according to me should print'ok'
However i am getting following excetpion.
Exception in thread "main" java.lang.ClassCastException: Test$B cannot be
cast to java.util.Collection
Can some one help me on this behavior.
public class Test {
#SuppressWarnings("unchecked")
public static <U extends B> U get() {
return (U) new B();
}
public static void main(String[] args) {
A<B> a = new A<>(get());
}
static class A<T> {
A(Collection<? extends T> lst) {
System.out.println("Bad constructor");
}
A(T e) {
System.out.println("ok");
}
}
static class B {
}
}
Related
Consider the following scenario:
public abstract class A {}
public class B extends A {}
public interface Provider<T extends A> {
List<String> list(T param);
}
public class ProviderB implements Provider<B> {
#Override
public List<String> list(B param) {
return Collections.singletonList("ProviderB");
}
}
public class Factory {
public static Provider get(int x) {
if (x == 1)
return new ProviderB();
throw new RuntimeException("Not supported");
}
}
public class Main {
public static void main(String[] args) {
Provider provider = Factory.get(1);
A a = new B();
List<String> result = provider.list(a);
}
}
In Main at List<String> result = provider.list(a); , I'm getting:
Unchecked call to list(T) ..
Unchecked assignment java.util.List .. Reason 'provider' has raw type.
I do know some basic stuff about type erasure in generics. How would you solve the warnings ?
EDIT:
Actually main will look like this:
public static void main(Map<Integer, ? extends A> types) {
for (Map.Entry<Integer, ? extends A> entryType : types.entrySet()) {
Provider provider = Factory.get(entryType.getKey());
List<String> result = provider.list(entryType.getValue());
}
}
Working on a specific need. Most of online tutorial talks about applying wildcard implementation with Collections. In below example, extends works OK but when I apply super with wildcard bounding getting error. I wish to restrict a method with it super type like said in the below example. Is there any limitation with super that I supposed to know.
class SuperClass3 {
public void display() {
System.out.println("This is display3 method");
}
}
class SuperClass2 extends SuperClass3 {
public void display() {
System.out.println("This is display2 method");
}
}
class SuperClass1 extends SuperClass2 {
public void display() {
System.out.println("This is display1 method");
}
}
Extends works well (with Type bounding NOT with wildcard bounding)...
public <T extends SuperClass2> void displayOutput(T obj) {
obj.display();
}
Try to do the same with Super not working. Throw compile error on method signature.
public <T super SuperClass2> void displayOutputWithSuper(T obj) {
//obj.display();
}
Complete Example ...
package com.tutorial.generic.bounds.wildcard;
import java.util.List;
public class UpperBoundWildcardExample {
class SuperClass3 {
public void display() {
System.out.println("This is display3 method");
}
}
class SuperClass2 extends SuperClass3 {
public void display() {
System.out.println("This is display2 method");
}
}
class SuperClass1 extends SuperClass2 {
public void display() {
System.out.println("This is display1 method");
}
}
public <T extends SuperClass2> void displayOutput(T obj) {
obj.display();
}
public void addData(List<? extends SuperClass2> data) {
}
public <T super SuperClass1> void displayOutputWithSuper(T obj) {
obj.toString();
}
/*
* This wont work
*
* public void addData(<? extends SuperClass2> data){
*
* }
*/
public static void main(String[] args) {
UpperBoundWildcardExample obj = new UpperBoundWildcardExample();
// Oops!!! Error
// obj.displayOutput(obj.new SuperClass3());
// It suppports SuperClass2 & which extends SuperClass2
obj.displayOutput(obj.new SuperClass2());
obj.displayOutput(obj.new SuperClass1());
}
}
#Shaan
This might be helpful
Bounding generics with 'super' keyword
let's say that you have this generic method declaration:
<T super Integer> void add(T number) // hypothetical! currently illegal in Java
And you have these variable declarations:
Integer anInteger
Number aNumber
Object anObject
String aString
Your intention with (if it's legal) is that it should allow add(anInteger), and add(aNumber), and of course add(anObject), but NOT add(aString). Well, String is an Object, so add(aString) would still compile anyway.
Consider the class hierarchy
public class A {
public void say() {
System.out.println("I am A");
}
}
and
public class B extends A {
public void say() {
System.out.println("I am B");
}
}
In a third class I have two different methods
private static void print(A input) {
}
private static <T extends A> void print2(T input) {
}
What is the "difference" between them?
I can both call them with an instance of A and all subclasses of A:
public class Test {
private static void print(A input) {
input.say();
}
private static <T extends A> void print2(T input) {
}
public static void main(String[] args) {
B b = new B();
print(b);
print2(b);
}
}
Thank you for your help!
P.S.: The difference between
private static void print(java.util.List<A> input) {
}
private static <T extends A> void print2(java.util.List<T> input) {
}
is clear!
Well from a practical reason there is not so much difference there.
You could call the second method by
<B>test2(new B());
It would fail then when you try to use is with an A
<B>test2(new A()); //Compile error
Although this does not make a big use for it.
However:
The generic declaration does make sence when you e.g. add the return-types.
public void <T extends A> T test2(T var) {
//do something
return var;
}
that you could call with:
B b = new B();
B b2 = test2(b);
while calling a similar method without generics would require a cast.
I have some difficulty to simplify more the problem. Sorry if they are too many code here.
I try to improve the architecture of the code above because I hate warning and cast and I feel something wrong.
Now, the code.
I have a util class with these two parametrized methods (same signature as OpenJPA's CriteriaBuilder...)
public class MyUtil {
public void equal(List<?> l, Object value) {
// do something (see CriteriaBuilder.equal method)
}
public <Y extends Comparable<? super Y>> void greaterThan(List<? extends Y> l, Y value) {
// do something (see CriteriaBuilder.greaterThan method)
}
}
Then, I want to be able to abstract them to call it via an interface.
public interface IOperation<T> {
// maybe make this method generic ? but how ?
public abstract void doOp(List<T> l, T value);
}
public abstract class AbstractOperation<T> implements IOperation<T> {
protected MyUtil myUtil;
}
public class EqualOp extends AbstractOperation<Object> {
#Override
public void doOp(List<Object> path, Object value) {
myUtil.equal(path, value);
}
}
public class GreaterThanOp<T extends Comparable<? super T>> extends AbstractOperation<T> {
#Override
public void doOp(List<T> path, T value) {
myUtil.greaterThan(path, value);
}
}
I create a factory
public class OperationFactory {
private static OperationFactory instance;
public static OperationFactory getInstance() {...}
public IOperation<?> get(String op) {
if ("=".equals(op)) {
return new EqualOp();
} else if (">".equals(op)) {
return new GreaterThanOp<Comparable<? super Object>>();
}
throw new InvalidParameterException();
}
}
Then I use it :
public class Client {
public void needOp(String op) {
IOperation<String> operation = (IOperation<String>) OperationFactory.getInstance().get(op); // How to avoid this cast ?
List<String> l = null;
operation.doOp(l, "a string");
}
}
My question is : is it possible to avoid this cast in the Client class ? How ? Is there a way to have a better architecture ?
Thanks for reading
I'm assuming you can require your type to be Comparable.
Parameterize EqualOp like GreaterThanOp:
public class EqualOp<T extends Comparable<T>> extends AbstractOperation<T> {
#Override public void doOp(List<T> path, T value) ...
And define get() like this:
public <T extends Comparable<T>> IOperation<T> get(String op) {
if ("=".equals(op)) {
return new EqualOp<T>();
} else if (">".equals(op)) {
return new GreaterThanOp<T>();
}
...
Consider the following program:
import java.util.List;
import java.util.ArrayList;
public class TypeTest {
public static class TypeTestA extends TypeTest {
}
public static class TypeTestB extends TypeTest {
}
public static final class Printer {
public void print(TypeTest t) {
System.out.println("T");
}
public void print(TypeTestA t) {
System.out.println("A");
}
public void print(TypeTestB t) {
System.out.println("B");
}
public <T extends TypeTest> void print(List<T> t) {
for (T tt : t) {
print(normalize(tt.getClass(), tt));
}
}
private static <T> T normalize(Class<T> clz, Object o) {
return clz.cast(o);
}
}
public static void main(String[] args) {
Printer printer = new Printer();
TypeTest t1 = new TypeTest();
printer.print(t1);
TypeTestA t2 = new TypeTestA();
printer.print(t2);
TypeTestB t3 = new TypeTestB();
printer.print(t3);
System.out.println("....................");
List<TypeTestB> tb1 = new ArrayList<TypeTestB>();
tb1.add(t3);
printer.print(tb1);
}
}
The main method now prints:
T
A
B
....................
T
What should I do to make it print the followings?
T
A
B
....................
B
I'd like to avoid writing a loop such as the following for each of the type that can be printed:
public void printTypeTestB(List<TypeTestB> t) {
for (TypeTestB tt : t) {
print(tt);
}
}
The root of your problem is that Java method overloads are resolved at compile time based on the declared type of the method argument expressions. Your program seems to be trying to use runtime dispatching to different method overloads. That simply doesn't work in Java.
The fact that you are using generics in your example is a bit of a red herring. You would have the same problem if you replaced the type parameter <T> with TypeTest.
Concider creating a visitor interface which knows about all relevant subtypes.
public class TypeTestFoo {
interface TypeTestVisitor {
void visit(TypeTestA t);
void visit(TypeTestB t);
void visit(TypeTest t);
}
interface TypeTest {
void accept(TypeTestVisitor visitor);
}
public static class TypeTestA implements TypeTest {
public void accept(TypeTestVisitor visitor) {
visitor.visit(this);
}
}
public static class TypeTestB implements TypeTest {
public void accept(TypeTestVisitor visitor) {
visitor.visit(this);
}
}
public static final class Printer implements TypeTestVisitor {
public void visit(TypeTestA t) {
System.out.println("A");
}
public void visit(TypeTestB t) {
System.out.println("B");
}
public void visit(TypeTest t) {
System.out.println("T");
}
}
public static void main(String[] args) {
Printer printer = new Printer();
TypeTest t1 = new TypeTest() {
public void accept(TypeTestVisitor visitor) {
visitor.visit(this);
}};
t1.accept(printer);
TypeTestA t2 = new TypeTestA();
t2.accept(printer);
TypeTestB t3 = new TypeTestB();
t3.accept(printer);
System.out.println("....................");
List<TypeTestB> tb1 = new ArrayList<TypeTestB>();
tb1.add(t3);
for (TypeTestB each : tb1) {
each.accept(printer);
}
}
}
This should print out what you wanted:
T
A
B
....................
B
The types are listed in the interface which allows for compile-time overloading. On the other hand, this is a single point where you have put the subtypes for which you wan't to parameterize behavior. Java is not a very dynamic language... :)
candidate for the convoluted "visitor pattern".
or simply move print() method from Printer to TypeTest