How to subclass generics properly? - java

I have searched other questions/answers, an I'm still confused about this JAVA ISSUE.
If I want to subclass a type that takes generic parameters, how would I do so while using generic parameters for the subclass too without it getting shadowed?
For example:
public class A <T> extends ArrayList<T> {}
So if i instantiate my custom class, with say, Integers as the parameter, does it take that value as parameter for <T> for the ArrayList part of it too? If not, then how would I specify the type for the ArrayList?
And I know sub classing containers may not be the best idea in many situations, but in this case I have decided it would be appropriate.

yes that would be how one goes about it.
public static void main(String[] args) {
B<Integer> b = new B<Integer>();
b.a = 1;
b.b = "one";
b.add(1);
b.add(2);
}
public static class A<T> extends ArrayList<T> {
public T a;
}
public static class B<T> extends A<T> {
public T b;
}
if you like you could even have them have different types, as long as you supply the super-class with it's type as well:
public static void main(String[] args) {
B<Integer, String> b = new B<Integer, String>();
b.a = 1;
b.b = "one";
b.add(1);
b.add(2);
}
public static class A<T> extends ArrayList<T> {
public T a;
}
public static class B<U, T> extends A<U> {
public T b;
}

Related

Create dynamic Type Java

explain my problem:
I have a super abstract class called First and then I have a lot of class that inherit from it.
I want to build a method that I "say" to it "create a ArrayList of one of the types that inherit from First class", but I'm not to able to find solution.
For example:
public abstract class First{
public First(){
}
}
public class FirstOne extends First{
...........
}
//It's a pseudo-code
public class MyProgramClass{
public creatingMethod(TypeThatInheritFromFirstClass x ){
return ArrayList<TypeThatInheritFromFirstClass>;
}
}
I insert creatingMethod in program class,but it can be anywhere(I prefer in First class like static method, but it's an example)
Thank for your time
You could use a type token:
public class SomeGenerics {
public static void main(String[] args) {
List<SubFirst1> list1 = creatingMethod(SubFirst1.class);
List<SubFirst2> list2 = creatingMethod(SubFirst2.class);
}
public static <T extends First> List<T> creatingMethod(Class<T> type) {
return new ArrayList<>();
}
}
class First {}
class SubFirst1 extends First {}
class SubFirst2 extends First {}
EDIT as per the comment:
As you already have the type token, you can use it for creating instances of that type. A little restriction is, that you must know what constructor to use. If they - for example - all have a parameterless constructor, you can create instances like that:
public static <T extends First> List<T> creatingMethod(Class<T> type) throws ReflectiveOperationException {
List<T> result = new ArrayList<>();
result.add(type.newInstance());
return result;
}
If you have a constructor with parameters (again: all sub classes must have the same parameterized constructor), you must go a more difficult way. Example with a string parameter:
public static <T extends First> List<T> creatingMethod(Class<T> type, String param) throws ReflectiveOperationException {
List<T> result = new ArrayList<>();
Constructor<T> constructor = type.getDeclaredConstructor(String.class);
result.add(constructor.newInstance(param));
return result;
}

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 can I have instances of Base and Sub-Classes in one List?

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.
How can I use both types (Base and Subclass) in one list?
public class Generics {
class Base { }
class Sub extends Base{ }
interface I {
public void list( List<Sub> list );
public void single( Sub p);
}
class C implements I {
public void list( List<Sub> list) { }
public void single( Sub p) { }
}
void test() {
C c = new C();
c.single( new Sub() );
c.list( new ArrayList<Base>() ); // The method list(List<Generics.Sub>) in the type Generics.C is not applicable for the arguments (ArrayList<Generics.Base>)
}
public static void main( String[] args) {
Generics g = new Generics();
g.test();
}
}
Change:
public void list(List<Sub> list);
to:
public void list(List<? extends Base> list);
Using just List<Base> will give you compiler errors like this one:
public static void main(String[] args) {
List<Sub> subs = new ArrayList<Sub>();
doSomethingWith(subs); // The method doSomethingWith(List<Base>) in the type Main is not applicable for the arguments (List<Sub>)
}
private static void doSomethingWith(List<Base> bases) {
// Do something with bases
}
If all you're going to pass is List<Base> to doSomethingWith, then this point is moot, since this won't give you a compiler error. If you want to pass lists that are of a specific type (such as List<Sub> above), then you need to change doSomethingWith to:
private static void doSomethingWith(List<? extends Base> bases) {
This fixes the problem. You could also do it at the caller lever (but it's a bit messier):
List<Sub> subs = new ArrayList<Sub>();
doSomethingWith(new ArrayList<Base>(subs));
One issue with the wildcard (?) approach is that you can't add new items to the list. To do that, you need something like:
private static <B extends Base> void doSomethingWith(List<B> bases) {
And then add only B instances to bases.
Just declare all your lists as
List<Base> list;
Then you can add both Base objects and objects of any subclass.
Below are the 2 ways to do it....
public void inTake(List<? extends Base> list){
}
Or
public T extends Base void inTake(List<T> list){
}

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