Java generic class constructor invocation - java

I have following code:
public class A {}
public class B extends A {}
public class C <T extends A> {
private final T data;
public C(final T data) {
this.data = data;
}
}
public class D<T extends B> extends C<T> {
public D(T data) {
super(data);
}
public D() {
this(new B());
}
public static D<B> create() {
return new D(new B());
}
}
There is a compile error in the class D:
error: no suitable constructor found for D(B)
this(new B());
constructor D.D() is not applicable
(actual and formal argument lists differ in length)
constructor D.D(T) is not applicable
(actual argument B cannot be converted to T by method invocation conversion)
where T is a type-variable:
T extends B declared in class D
What is confusing me is the fact, that the static method D.create() that does basically the same is compiled without any errors. Can anyone explain this error? And the difference between D() and D.create()?

The error is there because for class D it is not known that the type will be B, only that the generic type will extend B - you have assumed it's going to be B because there are no other classes (yet) in your class hierarchy (a fact that the compiler must consider may change in the future).
Note that in the factory method you are instantiating the raw type for D (one without a generic parameter). Instead, provide a type:
You should change:
public static D<B> create() {
return new D(new B());
}
to:
public static D<B> create() {
return new D<B>(new B()); // Note: Added generic parameter <B>
}

Because generic type T of class D is not bound
This will work
public class E extends D<B> {
public E() {
super(new B()); // call to D's constructor public D(T data)
}
}
normally you would call the constructor of D in this way:
new D<B>(new B());
but you CAN NOT do this
public D() {
this<B>(new B());
}
Another example.
Change the code a little bit and you will see the problem.
class BBB extends B {
}
class C<T extends A> {
protected final T data;
public C(final T data) {
this.data = data;
}
}
class D<T extends B> extends C<T> {
public D() {
this(new B());
}
public T getData(){
return data;
}
}
D<BBB> dOfBBB = new D<BBB>();
BBB data = dOfBBB.getData(); // So if this(new B()) would work
// how can the data then be returned?
// Because BBB is returned but it would be
// initialized with only a B instance

Related

Incompatible types: inferred type does not conform to upper bound(s)

I was implementing some architecture when I saw the following error:
Error:(33, 55) java: incompatible types: inferred type does not conform to upper bound(s)
inferred: java.io.Serializable
upper bound(s): sandbox.ExpirePolicy,java.io.Serializable
The whole simplified code is below:
interface Configuration<K,V>{}
interface ExpirePolicy{}
interface Factory<T>{}
class FactoryBuilder {
public static <T extends Serializable> Factory<T> of(T instance){
System.out.println(instance.getClass());
return new Factory<T>() {};
}
}
class BaseConfiguration<K,V> implements Configuration<K,V> {
public BaseConfiguration<K,V> setExpiryPolicyFactory(Factory<? extends ExpirePolicy> factory){
return this;
}
}
class C<K,V> extends BaseConfiguration<K,V> {
public C<K,V> setExpiration(){
super.setExpiryPolicyFactory(FactoryBuilder.of((Serializable) getExpirePolicy()));
return this;
}
private ExpirePolicy getExpirePolicy(){
return new ExpirePolicy() {};
}
}
The exception is in trying to call setExpiryPolicyFactory(Factory<? extends ExpirePolicy> factory) with instance of Factory<Serializable>
But if i delete generic in extends BaseConfiguration<K,V> the program will be successfully compiled.
So the next declaration of class C is correct:
class C<K,V> extends BaseConfiguration {
public C<K,V> setExpiration(){
super.setExpiryPolicyFactory(FactoryBuilder.of((Serializable) getExpirePolicy()));
return this;
}
private ExpirePolicy getExpirePolicy(){
return new ExpirePolicy() {};
}
}
The question is: why the second implementation(of class C) will be successfully compiled and the first not?
UPD:
Simpler example of question (delete <T> from extends Base<T>) and program compiles well :
class Base<T> {
public void test(ArrayList<? extends CharSequence> list) {}
}
class Derived<T> extends Base<T> {
public void callTest() {
super.test(new ArrayList<Integer>());
}
}
When you delete <T> from extends Base<T> statement, the Base class starts to be treated as a raw type.
According to Java spec:
The supertype of a class may be a raw type. Member accesses for the
class are treated as normal, and member accesses for the supertype are
treated as for raw types. In the constructor of the class, calls to
super are treated as method calls on a raw type.
This means that super.test(...) call is also treated as method call on a raw type as if it has been declared like:
public void test(ArrayList list) {}
Thus no compilation errors happens.
It seems like the factory builder should take in an ExpirePolicy instead of Serializable for creating the factory. Changing the signature to
class FactoryBuilder {
public static <T extends ExpirePolicy> Factory<T> of(T instance){
System.out.println(instance.getClass());
return new Factory<T>() {};
}
}
enables using
class C<K,V> extends BaseConfiguration<K,V> {
public C<K,V> setExpiration(){
super.setExpiryPolicyFactory(FactoryBuilder.of(getExpirePolicy()));
return this;
}
private ExpirePolicy getExpirePolicy(){
return new ExpirePolicy() {};
}
}
without extra casts.
The second implementation of C compiles, but with warnings, because it's using raw types.

Class that implements an interface with a method returning List of interfaces generates compilation error

Let's say I have these four classes:
public interface A {}
public interface B {
public A getA();
}
public class C implements A {}
public class D implements B {
public C getA() {
return new C();
}
}
This compiles well. However if I have this code I get a compilation error:
public interface A {}
public interface B {
public List<A> getA();
}
public class C implements A {}
public class D implements B {
public List<C> getA() {
return new ArrayList<C>();
}
}
public class E implements B {
public List<A> getA() {
return new ArrayList<C>();
}
}
What is the reason that allows to return a C in the method getA, in the first example, but generates an error in the second example when I return a List?
It looks to me that both examples should compile or throw an error.
Thanks.
EDIT
I read the post using Dog/Animal, however my doubt is different. I have added the class E. If you call getA in class E you get a List as defined in the interface. Then why it fails compiling for class E?
This is relate to java generics.
You have defined the return type of method in interface as List<A> but you are trying to return a List<C> from the actual implementation.
If you actually wanna return a List<C> from the method then you have to change your interface method as follows
public List<? extends A> getA();
Explanation why can't return new ArrayList<C>();
Let say it is valid to return as u mentioned. Then
List<A> listA = getA(); // This will compile if allowed
listA.add(new A()); // this will also valid since reference type is A.
So you can see that it is no point of allowing the way you mentioned

Generic Class and passing derived data type

I do have a problem in the last line of execution though I pass derived data type. Not able to figure out. Thanks.
public class ExtendedDHvalue extends DHvalue {}
public class DerivedHolderUnique<T> {
private Class<? extends T> a;
public DerivedHolderUnique(Class<? extends T> a){
this.a = a;
}
public Class<? extends T> getA() {
return a;
}
public void setA(Class<? extends T> a) {
this.a = a;
}
public static void main(String[] args){
ExtendedDHvalue eDV = new ExtendedDHvalue();
DerivedHolderUnique<DHvalue> dhu = new DerivedHolderUnique<DHvalue>(eDV);
}
}
Your constructor takes parameter of type Class<? extends T> and you're passing an argument that extends T to it. You should change those two lines to:
Class<ExtendedDHvalue> eDV = ExtendedDHvalue.class;
DerivedHolderUnique<DHvalue> dhu = new DerivedHolderUnique<DHvalue>(eDV);
Your DerivedHolderUnique constructor requires a Class instance, not
an ExtendedDHvalue instance. This is what causes the compile-time error.
You should think if you actually want
private Class<? extends T> a;
or
private T a;
and then rework your DerivedHolderUnique class accordingly.
I tend to think you want the latter but you should know better.

How does Subclassing for Lists work?

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){
}

inheritance & collections related compile error

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.

Categories

Resources