假设我有一个泛型类 Foo
,它可以容纳一个类型为 T
的对象。此外,假设我只希望能够使用两种类型之一的对象来实例化类。最后,假设这两种类型的最低公共(public)上限是一种类型,其子类比我想要允许的这两种类型多得多,所以我不能简单地为类型参数指定上限(如 class Foo<T extends Something>
), 因为这样我就可以用我期望的两种类型之外的其他类型来实例化类。
为了说明,假设我希望 Foo
保存 仅 String
或 Integer
。最低的公共(public)上限是 Object
,因此指定上限不会奏效。
当然,我可以按照以下方式做一些事情
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;
}
}
但是,在这种情况下,我仍然可以使用任何 对象调用构造函数;如果我尝试用既不是 String
也不是 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;
}
}
这行得通,但看起来真的很奇怪。编译器警告(可以理解)关于未经检查的强制转换。当然我可以抑制这些警告,但我觉得这不是要走的路。此外,看起来编译器实际上无法推断类型 T
。我惊讶地发现,使用类 Foo
的后一个定义,我可以这样做,例如:
Foo<Character> foo = new Foo<>("hello");
当然这里的类型参数应该是String
,而不是Character
。但是编译器让我摆脱了上述分配。
- 有没有办法实现我想要的,如果有,怎么做?
- 附带问题:为什么编译器允许我对上面类型为
Foo<Character>
的对象进行赋值,甚至连 警告 都没有(在使用类Foo
的后一个定义时)? :)
最佳答案
尝试使用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;
}
}
现在您使用以下方式创建实例:
Foo<String> foos = Foo.of("hello");
Foo<Integer> fooi = Foo.of(42);
Foo<Character> fooc = Foo.of('a'); // Compile error
但是以下内容仍然有效,因为您可以声明任何类型 T 的 Foo,但不能实例化它:
Foo<Character> fooc2;
Foo<Character> fooc3 = null;
Foo<Object> fooob1;
Foo<Object> fooob2 = null;
关于java - 使用一组固定类型中的一个来参数化一个类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48993454/