How can I use generics with exclusive binding using "extends"?

Suppose I have a code snippet with JDK 1.7. Using Generics, I am embarrassed of how to get a generic parameterized type with exclusive , not included borders using extends . For instance:

 abstract class BaseAbstract { } class ChildWhichExtendsBaseAbstract extends BaseAbstract { } class SomeOtherClassWhichUseGenerics<T extends BaseAbstract> { } public class Test { public static void main(String[] args) { /** * I just don't want JVM to compile below line, because I want to use * generic type with {@link SomeOtherClassWhichUseGenerics} which must * not be {@link BaseAbstract} */ SomeOtherClassWhichUseGenerics<BaseAbstract> obj1 = new SomeOtherClassWhichUseGenerics<BaseAbstract>(); /** * I just want JVM to compile below line, because I want to use generic * type with {@link SomeOtherClassWhichUseGenerics} which must be only * subclasses of BaseAbstract */ SomeOtherClassWhichUseGenerics<ChildWhichExtendsBaseAbstract> obj2 = new SomeOtherClassWhichUseGenerics<ChildWhichExtendsBaseAbstract>(); } } 

I think this should be one of the known problems / problems / requirements. Is work possible?

+4
source share
2 answers

extends means an inclusive upper bound.

What is this, the end of the discussion. It is impossible to say extends T , but not T From JLS ยง4.5.1 :

An argument of type T1 is said to contain another argument of type T2 written by T2 <= T1 if the set of types denoted by T2 is supposedly a subset of the set of types denoted by T1 with reflexive and transitive closure following rules (where <: denotes subtyping ( ยง4.10 ) ):

// snip

  • T <=? extends T

What is it. T contained in ? extends T ? extends T

In addition, even if you could tie it that way, in fact it didnโ€™t make a big difference. Let me tell you what you could; this would be illegal:

 public List<? exclusive-extends MyClass> list = new ArrayList<>(); list.add(new MyClass()); 

But this anonymous class will not:

 public List<? exclusive-extends MyClass> list = new ArrayList<>(); list.add(new MyClass(){}); 

However, there may be a problem with your real problem.

It seems to me that the real problem is that you do not want anyone to put BaseAbstract instances in your generic type; you only need subclasses.

Well, doing that is easy enough to achieve; BaseAbstract cannot be created at all because it is an abstract class. As long as the parameterized type is an abstract class, you're fine.

If you have a real class, not an abstract class, you can simply put a dummy abstract class between them, for example.

 class Foo { } abstract class AbstractFoo extends Foo { } // Newly added class Bar extends AbstractFoo { } // previously extended Foo class Baz extends AbstractFoo { } // previously extended Foo 
+4
source

I see the only option: make BaseAbstract package-private and put all the children in the same package. This BaseAbstract method BaseAbstract not be accessible externally. For example, consider the following code.

 // a/BaseAbstract.java package a; abstract class BaseAbstract { } // a/ChildWhichExtendsBaseAbstract.java package a; public class ChildWhichExtendsBaseAbstract extends BaseAbstract { } // a/SomeOtherClassWhichUseGenerics.java package a; public class SomeOtherClassWhichUseGenerics<T extends BaseAbstract> { } // b/Test.java package b; import a.ChildWhichExtendsBaseAbstract; import a.SomeOtherClassWhichUseGenerics; public class Test { public static void main(String[] args) { /** * Compile error as BaseAbstract is invisible */ SomeOtherClassWhichUseGenerics<BaseAbstract> obj1 = new SomeOtherClassWhichUseGenerics<BaseAbstract>(); /** * Compiles correctly */ SomeOtherClassWhichUseGenerics<ChildWhichExtendsBaseAbstract> obj2 = new SomeOtherClassWhichUseGenerics<ChildWhichExtendsBaseAbstract>(); } } 

The limitation of this approach is that you must define all possible child classes in one package a .

+2
source

All Articles