Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Selective Generics

class A <T> {

    private T field;
}

I know I can force the type parameter to be of some bounded type using < ... extends ... >, but how can I force type parameter T to be ONLY either a String, Integer, SomeClassB, SomeEnumC and not be able to parametrise it with anything else?

A<SomeClassB> a = new A<SomeClassB>();

Would be legal.

A<SomeClassX> a = new A<SomeClassX>();

Would be illegal.

I have already tried to test for these types using

T instanceof SomeEnumC

in the constructor for class A, but it is very messy.

like image 569
oskarm Avatar asked Jul 01 '26 21:07

oskarm


2 Answers

Note: I agree with @Jeffrey's comment above, that this doesn't seem to make a lot of sense, since it doesn't seem like you could gain any useful type information by doing this kind of restriction. I'd really be curious to know what your use case is here.


You can't restrict the generic types acceptable for T to a list of unrelated classes like in your example. You can only restrict generic types using super or extends, meaning they have to be super- or sub-types of some given type.

However, since you seem to have a limited number of classes you want to allow for T, you should just be able to enumerate all of them. Here's what I'm thinking:

public class A<T> {

  /**
   * Private constructor means only nested classes
   * can extend this class. We use this to limit the
   * types that can be used for T.
   */
  private A() { }

  /** Integer version of A */
  public static class IntA extends A<Integer> { }

  /** String version of A */
  public static class StringA extends A<String> { }

}

Now you can use a static import to import whichever nested version of A<T> that you want, or all of them like this: import static A.*;

like image 180
DaoWen Avatar answered Jul 04 '26 10:07

DaoWen


I am assuming that you want to export Class A as part of your API and this is why you want to restrict the types that can be passed as generic type parameters.

If the list of types that you want to restrict Class A to is known (and reasonably small in number) then a workaround is to define a package-private interface instead (this will prevent classes that are outside your package from implementing the interface):

interface A <T> {
    T field;
}

You can then simply write concrete classes for the types you wish to allow. Because nobody else can implement your interface, there is no possibility of someone writing a class based on a type that you did not intend to permit.

like image 32
scottb Avatar answered Jul 04 '26 11:07

scottb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!