首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java类泛型和方法泛型冲突

Java类泛型和方法泛型冲突
EN

Stack Overflow用户
提问于 2011-04-21 01:29:04
回答 4查看 1.1K关注 0票数 2

我有一个泛型Class Factory类,它有两个方法,一个利用class泛型T值,另一个只使用它自己的方法泛型定义。

代码语言:javascript
复制
public class GenericClassFactory<T extends ClassMatchable> {
    public <E, K> E newObject(ClassMatcher<E, K> matcher, K key, String packageName){...}
    public <K> T newObject(K key, String packageName){...}
}

利用T泛型的方法工作得很好,但是当我想使用另一个不关心T泛型是什么的方法时,它不会使用泛型E,它只会返回一个对象,然后我不得不对它进行类型转换。

代码语言:javascript
复制
Data data = new GenericClassFactory().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

这有编译错误,因为它希望我将其类型转换为(Data)。如果我向GenericClassFactory传递一个有效的类泛型,它将会工作。这就像如果你定义了一个类泛型但没有使用,它就不能识别方法泛型。

代码语言:javascript
复制
Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

这很好用。但是,当我的目的不需要它时,我不得不定义一个类泛型,这是愚蠢的。我可以这样做:

代码语言:javascript
复制
public class GenericClassFactory {
    public <E, K> E newObject(ClassMatcher<E, K> matcher, K key, String packageName){...}
    public <T extends ClassMatchable, K> T newObject(K key, String packageName){...}
}

但是现在我的第二个方法似乎太宽了,或者something...maybe不是。我的意思是,如果你赋值给返回类型的对象没有实现ClassMatchable,它仍然会给出编译错误。那是我应该走的路吗?这样我就不用打字了?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-04-21 01:37:29

没错,如果不输入类引用,那么即使是只使用方法类型参数的泛型方法也不会被泛化。这是Java泛型中比较奇怪的细微差别之一。正如您所说,您可以为T添加一些任意类型

代码语言:javascript
复制
Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

但更有可能的是,这甚至不应该是一个实例方法。它不能是一个静态方法吗?如果是这样,您可以像这样调用它:

代码语言:javascript
复制
Data data =  GenericClassFactory.newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

编辑

请注意,这将扩展到所有实例成员,而不仅仅是泛型实例方法。因此,有一些更简单的案例可以证明这种奇怪的细微差别。此代码编译时仅显示警告:

代码语言:javascript
复制
public class Scratchpad<T> {
   List<String> list;
   public static void main(String[] args) {
      Scratchpad sp = new Scratchpad();
      List<Integer> list = sp.list;
   }
}

这是因为sp.list被解析为List,而不是List<String>,即使Scratchpad.listT无关。

JLS, Section 4.8中详细记录了这一点

未从其超类或超接口继承的原始类型C的构造函数(§8.8)、实例方法 (§8.8、§9.4)或非静态字段(§8.3)的类型在与C对应的泛型声明中擦除其类型。原始类型C的静态成员的类型与其在与C对应的泛型声明中的类型相同。

票数 6
EN

Stack Overflow用户

发布于 2011-04-21 01:45:19

在调用该方法时,应告知E和K的实际类型:

代码语言:javascript
复制
  new GenericClassFactory<ClassMatchable>().<TypeforE, TypeforK>newObject(...)

看起来Java不能从参数中推断出它。

当然,还有:

如果你定义了一个类泛型但没有使用,它就像

不能识别方法泛型一样。

是完全正确的。

票数 1
EN

Stack Overflow用户

发布于 2011-04-21 02:19:13

如果你定义了一个类泛型但没有使用,它就像

不能识别方法泛型一样。

完全正确。如果您在一个类上定义了一个泛型约束,然后在没有提供任何泛型约束的情况下实例化该类(也就是说,您完全放弃了<> ),那么您就进入了的领域,在这个领域中,一切都不再相同。

原始类型的存在只是为了向后兼容。根据Angelika Langer的优秀Java Generics FAQ

在将泛型引入

编程语言之后,不鼓励在编写的代码中使用原始类型。根据Java语言规范,Java编程语言的未来版本可能不允许使用原始类型。

它也是states

原始类型的

方法或构造函数具有类型擦除后的签名。如果擦除操作更改了参数类型,则对原始类型的方法或构造函数调用会生成未检查的警告。

如果newObject()方法没有使用它所属类的类型参数T,那么您的设计就有问题:newObject()很可能应该成为一个静态方法。

但是,如果由于某种原因,它确实必须是实例方法,则可以使用wildcard type GenericClassFactory<?>使其正常工作

代码语言:javascript
复制
GenericClassFactory<?> gcf = new GenericClassFactory();
Data data = gcf.newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl"); 
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5734248

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档