开发者

Any way to make a generic List where I can add a type AND a subtype?

开发者 https://www.devze.com 2023-02-02 10:49 出处:网络
I understand why I cannot do the following: private class Parent { }; private class Child extends Parent {

I understand why I cannot do the following:

private class Parent {
};

private class Child extends Parent {
};

private class Grand开发者_StackOverflow中文版Child extends Child {
};

public void wontCompile(List<? extends Parent> genericList, Child itemToAdd) {
    genericList.add(itemToAdd);
}

My question is there ANY practical way to have a typesafe List where you can call add(E) where E is known to be only a Parent or a Child?

I vaguely remember some use of the "|" operator as used for wildcard bounds, but I cannot find it in the spec...

Thanks!


There is not.

In add(E), the determination of the exact type of E could be made only at runtime. Any variable declared to be of type Parent can hold a reference to a GrandChild object, due to the subtype relationship; there's no way to create a list where you can't add objects of a subtype of the element type (at least, where such an operation will be prohibited by the compiler).

The real question is: why do you even want that? Perhaps your inheritance hierarchy is upside down.


Why not? All you need is a matching generic type for both the List and item arguments that satisfies both the calling parameters, you can achieve that pretty simply:

import java.util.ArrayList;
import java.util.List;

public class TestClass {

  private class Parent {
  };

  private class Child extends Parent {
  };

  private class GrandChild extends Child {
  };

  public <T extends Parent> void compilesNow(final List<T> genericList, final T itemToAdd) {
    genericList.add(itemToAdd);
  }

  public void addSomeDescendents() {
    final List<Parent> list = new ArrayList<Parent>();
    compilesNow(list, new Parent());
    compilesNow(list, new Child());
    compilesNow(list, new GrandChild());
  }
}

EDIT: Sorry I missed the bit about excluding GrandChild... however, my example is a step further into how Generics can be utilized to make this scenario at least compile


Your class hierarchy

public class Parent {

}

public class Child extends Parent {

}

public class GrandChild extends Child {

}

How to add a type and its subtypes to a generic List

public class Runner {

    //List that contains anything that has a super class Parent
    private static List<? super Parent> genericList = new ArrayList<>(); 

    public static void main(String[] args) {
        Parent parent = new Parent();
        Child child = new Child();
        GrandChild grandChild = new GrandChild();

        genericList.add(parent);
        genericList.add(child);
        genericList.add(grandChild);

        genericList.forEach(System.out::println);
    }
}

The output

com.abd.test.generics.Parent@1218025c 
com.abd.test.generics.Child@816f27d 
com.abd.test.generics.GrandChild@87aac27


You could create a facade and do your own instanceof checking before delegating to an encapsulated List.

It would be ugly and is most likely a horrible idea.

0

精彩评论

暂无评论...
验证码 换一张
取 消