使用一组固定类型对类进行参数化

Mal*_*ppa 3 java generics class java-8

假设我有一个Foo可以容纳类型对象的泛型类T.此外,假设我希望能够使用两种类型之一的对象来实例化类.最后,假设这两种类型的最低公共上限是一个类型,它比我想要允许的那两种类型有更多的子类,所以我不能简单地指定类型参数的上限(如class Foo<T extends Something>) ,因为那时我会允许用除我期望的两种类型之外的其他类型来实例化该类.

为了说明,假设我想Foo持有一个或一个.最低公共上限是,因此指定上限不会起作用.StringIntegerObject

当然,我可以做一些事情

class Foo<T> {

    private T obj;

    public Foo(T obj) throws IllegalArgumentException {
        if (!(obj instanceof String || obj instanceof Integer)) {
            throw new IllegalArgumentException("...");
        }
        this.obj = obj;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,在这种情况下,我仍然可以使用任何对象调用构造函数; 如果我尝试使用既不是a String也不是a的东西来实例化它Integer,我将在运行时获得异常.

我想做得更好.我希望编译器静态地(即,在编译时)推断我只能使用String或者对象来实例化这个类Integer.

我在想这些方面的东西可能会成功:

class Foo<T> {

    private T obj;

    public Foo(String s) {
        this((T) s);
    }

    public Foo(Integer i) {
        this((T) i);
    }

    private Foo(T obj) {
        this.obj = obj;
    }
}
Run Code Online (Sandbox Code Playgroud)

这有效,但看起来真的很奇怪.编译器警告(可以理解)未经检查的强制转换.当然我可以压制这些警告,但我觉得这不是要走的路.另外,看起来编译器实际上无法推断出类型T.我很惊讶地发现,对于后一种类的定义Foo,我可以做到这一点,例如:

Foo<Character> foo = new Foo<>("hello");
Run Code Online (Sandbox Code Playgroud)

当然,类型参数应该在String这里,而不是Character.但编译器让我逃脱了上述任务.

  1. 有没有办法实现我想要的,如果有,怎么样?
  2. 旁边的问题:为什么编译器让我逃避对Foo<Character>上面类型的对象的赋值,甚至没有警告(当使用后面的类定义时Foo)?:)

And*_*eas 8

尝试使用static工厂方法来防止编译器警告.

class Foo<T> {

    private T obj;

    public static Foo<String> of(String s) {
        return new Foo<>(s);
    }

    public static Foo<Integer> of(Integer i) {
        return new Foo<>(i);
    }

    private Foo(T obj) {
        this.obj = obj;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在使用以下方法创建实例

Foo<String> foos = Foo.of("hello");

Foo<Integer> fooi = Foo.of(42);

Foo<Character> fooc = Foo.of('a'); // Compile error
Run Code Online (Sandbox Code Playgroud)

但是以下内容仍然有效,因为您可以声明任何类型T的Foo,但不能实例化它:

Foo<Character> fooc2;

Foo<Character> fooc3 = null;

Foo<Object> fooob1;

Foo<Object> fooob2 = null;
Run Code Online (Sandbox Code Playgroud)