This question already has answers here:
Why can't a Generic Type Parameter have a lower bound in Java?
(6 answers)
Bounding generics with 'super' keyword
(6 answers)
Closed 8 years ago.
I just read topics about generic wild card. "?", "extends", and "super" from SCJP 6 book. My question is related to method declaration using super and extends.
class A {
}
class B extends A {
}
class C extends B {
}
class D extends C {
}
public class Class_1 {
public static void main(String args[])
{
List<B> bs = new ArrayList<B>();
List<A> as = new ArrayList<A>();
List<C> cs = new ArrayList<C>();
List<D> ds = new ArrayList<D>();
Class_1 class_1 = new Class_1();
class_1.getName3(ds);
class_1.getName4(bs);
class_1.getName1(cs);
class_1.getName2(as);
}
public void getName3(List<? extends B> list)
{
}
public void getName4(List<? super B> list)
{
}
public <T extends B> void getName1(List<T> list)
{
}
public <T super B> void getName2(List<T> list)
{
}
}
I am getting compilation error at class_1.getName2(as);. Why ? Error is saying
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method getName2(List<T>) from the type Class_1 refers to the missing type T
at com.ksh.scjp.gNc.Class_1.main(Class_1.java:26)
Related
This question already has answers here:
Cannot return object from generic method
(5 answers)
Generic method return type - compilation error [duplicate]
(3 answers)
Java generic, method that returns T where <T extends String> cannot return string
(2 answers)
Java Generics: Returning Bounded Generic Type
(3 answers)
Java compile error in method with generic return type
(1 answer)
Closed 1 year ago.
I am trying to define a static method which can return childs of a specific class. I am using generics for that it is not working.
Example code:
public class Test {
class A {
}
class B extends A {
}
public static <T extends A> T getA() {
return new B();
}
public static void main(String[] args) {
B b = getA();
}
}
As you can see I am saying getA() will return T which is a child of the "A" class. I return B instance there, and it is a child of A but still it is not compiling. Any idea about what am I doing wrong? Thanks in advance!
Edit: And there would be multiple sub types to return from getA()
public class Test {
class A {
}
class B extends A {
}
class C extends A {
}
public static <T extends A> T getA(int type) {
if(type = 0) {
return new B();
} else {
return new C();
}
}
public static void main(String[] args) {
B b = getA(0);
C c = getA(1);
}
}
As you can see I am saying getA() will return T which is a child of the "A" class.
Yes, but you're allowing the caller to say which child class of A they want to have returned.
What if you wrote X x = getA();, where X is a subtype of A but not B?
The only thing you can safely return from that method is null.
If you want to say the method will return any subtype of A, make the return type A.
This question already has answers here:
Java: how do I get a class literal from a generic type?
(8 answers)
Closed 4 years ago.
I would like to get the class of Foo< T >.class (exactly Foo < T>, neither T.class nor Foo.class)
public class A extends B<C<D>>{
public A() {
super(C<D>.class); // not work
}
}
On StackOverflow has a instruction for obtaining generic class by injecting into constructor but it's not my case because C< D>.class (e.g List<
String>.class) is syntax error. At here it seems relate to syntax more than code structure.
To show more detail, higher level view, the original code is the following, its HATEOAS module in Spring framework:
public class CustomerGroupResourceAssembler extends ResourceAssemblerSupport<CustomerGroup, CustomerGroupResource>{
public CustomerGroupResourceAssembler() {
super(CustomerGroupController.class, CustomerGroupResource.class);
}
}
public class CustomerGroupResource extends ResourceSupport {
private CustomerGroup data;
}
But now I want to parameterize the CustomerGroupResource to
public class Resource<T> extends ResourceSupport {
private T data;
}
and then
public class CustomerGroupResourceAssembler extends ResourceAssemblerSupport<CustomerGroup, Resource<CustomerGroup>>{
public CustomerGroupResourceAssembler() {
super(CustomerGroupController.class, Resource<CustomerGroup>.class); // not work here, even Resource.class
}
}
Unfortunately what you are trying to do is impossible due to type erasure.
Information about generic types is only avalilable at compile time and not at run time. This is one of biggest limitations of using generics in Java. The reason why it was done like this is to preserve backwards compatibility.
See Java generics type erasure: when and what happens?
Due to type erasure, the generic only applies at compile time and doesn't mean anything at runtime. What you can do is
public class A extends B<C<D>>{
public A() {
super((Class<C<D>>) C.class);
}
}
However, you won't be able to determine the type of D at runtime. You can use reflection to get the super type however.
public class Main {
public static abstract class B<X> {
protected B() {
Type type = getClass().getGenericSuperclass();
System.out.println(type);
}
}
public static class A extends B<Supplier<String>> {
public A() {
}
}
public static void main(String[] args) {
new A();
}
}
prints
Main.Main$B<java.util.function.Supplier<java.lang.String>>
EDIT For your specific example you can do.
import java.lang.reflect.Type;
public interface Main {
class ResourceSupport {
}
class CustomerGroup {
}
public class Resource<T> extends ResourceSupport {
private T data;
}
abstract class ResourceAssemblerSupport<C, R> {
protected ResourceAssemblerSupport() {
Type type = getClass().getGenericSuperclass();
System.out.println(type);
ParameterizedType pt = (ParameterizedType) type;
Type[] actualTypeArguments = pt.getActualTypeArguments();
Class first = (Class) actualTypeArguments[0];
ParameterizedType second = (ParameterizedType) actualTypeArguments[1];
System.out.println(pt.getRawType() + " <" + first + ", " + second + ">");
}
}
public class CustomerGroupResourceAssembler extends ResourceAssemblerSupport<CustomerGroup, Resource<CustomerGroup>>{
public CustomerGroupResourceAssembler() {
}
}
public static void main(String[] args) {
new CustomerGroupResourceAssembler();
}
}
prints
Main.Main$ResourceAssemblerSupport<Main$CustomerGroup, Main.Main$Resource<Main$CustomerGroup>>
class Main$ResourceAssemblerSupport <class Main$CustomerGroup, Main.Main$Resource<Main$CustomerGroup>>
A generic way to do what you want is to use a helper function, however I think this isn't needed in your case.
public static void main(String[] args) {
System.out.println(new ClassType<List<String>>() {}.getType());
}
interface ClassType<T> {
default Type getType() {
ParameterizedType type = (ParameterizedType) getClass().getGenericInterfaces()[0];
return type.getActualTypeArguments()[0];
}
}
prints
java.util.List<java.lang.String>
This question already has answers here:
How do I get a class instance of generic type T?
(23 answers)
Closed 5 years ago.
Say I have these two methods:
<T extends MyClass> void method1(Class<T> a, ArrayList<T> b) {
//whatever
}
<T extends MyClass> void method2(T c) {
method1(c.getClass(), new ArrayList<T>()); //Here I get compile error: wrong argument type for the second parameter
}
While this other snippet returns no errors (only a warning for unchecked cast):
<T extends MyClass> void method1(Class<T> a, ArrayList<T> b) {
//whatever
}
<T extends MyClass> void method2(T c) {
method1((Class<T>)c.getClass(), new ArrayList<T>());
}
Can someone explain why I get the error in the first example, and what's the best way to deal with that?
public final native Class<?> getClass(); - this is code from Object class. Therfore you have warning, when do unsafe cast from Class<?> to Class<T>. You can give JVM more flexibility:
<T extends MyClass> void method1(Class<T> a, List<T> b) {
//whatever
}
<T extends MyClass> void method2(T c) {
method1(c.getClass(), new ArrayList<>());
}
There're no warning and compile error.
I asked a similiar question 10 minutes ago, but pasted the wrong code snippet. I'm really sorry about that.
I'm currently facing an issue with base and subclasses.
While having a single object as parameter (method single) the compiler doesn't complain.
But if it comes to lists the compiler forces me to declare the list as <? extends Base>
After that I'm no longer allowed to add objects of the base type to that list.
The error message: "The method list(List<Generics.Base>) in the type Generics.C is not applicable for the arguments (List<Generics.Sub>)"
public class Generics {
class Base { }
class Sub extends Base{ }
interface I {
public void list( List<Base> list );
public void single( Base list );
}
class C implements I {
public void list( List<Base> b) { }
public void single( Base p) { }
}
void test() {
C c = new C();
c.single( new Sub() );
List<Sub> b = new ArrayList<Sub>();
c.list( b ); // error message as above
}
public static void main( String[] args) {
Generics g = new Generics();
g.test();
}
}
Is there any other way but declaring the list-methods argument as type <? extends Base> ?
Below are the 2 ways to do it....
public void list(List<? extends Base> list){
}
Or
public <T extends Base> void list(List<T> list){
}
I'm trying to figure out why this code won't compile.
I have interface A extended by interface B.
Class C which implements interface B.
When I call a method that takes in a single object of type A, I can pass in an object of type C and it's fine.
When I call a method that takes in a java.util.List of type A, I cannot pass in a java.util.List of objects of type C. Eclipse generates the following error:
The method addAList(List) in the type Test1 is not applicable for the arguments (List)
Source code example is below.
import java.util.ArrayList;
import java.util.List;
public class Test1 {
public void addASingle(A a) {
return;
}
public void addAList(List<A> aList) {
return;
}
// **********************************
public static void main(String[] args) {
Test1 t = new Test1();
C c1 = new C();
List<C> cList = new ArrayList<C>();
cList.add(c1);
t.addASingle(c1); // allowed
t.addAList(cList); // The method addAList(List<Test1.A>)
// in the type Test1 is not applicable for the arguments (List<Test1.C>)
}
// **********************************
public static interface A {
}
public static interface B extends A {
}
public static class C implements B {
}
}
A List<Car> is not a List<Vehicle>. If it was, you could do the following:
List<Car> cars = new ArrayList<>();
List<Vehicle> vehicles = cars;
vehicles.add(new Bicycle());
and you would end up with a list of cars which contains a bicycle. It would ruin the type-safety of generic collections.
You probably should used a List<? extends A> instead of List<A>. List<? extends A> means: a List<some class which is A or which extends A>.
It expects List and you are passing List,
Change it to
public void addAList(List<? extends A> aList) {
return;
}
it expects List of type A....write it in your method signature.
public void addAList(List<? extends A> aList) {
return;
}
by writing this you declare that..your method expects any List which contains any subtype of A...This is called wildcard.