Java类泛型和方法泛型冲突 [英] Java Class Generics and Method Generics conflicts

查看:223
本文介绍了Java类泛型和方法泛型冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  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它将只返回一个对象,然后我必须输入它。 / p>

  Data data = new GenericClassFactory()。newObject(new ClassMatcher< Data,String>(){...},key1 ,my.package.name.impl); 

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

 数据数据=新的GenericClassFactory< ClassMatchable>()。newObject(new ClassMatcher< Data,String>(){...},key1,my.package.name.impl); 

这很好。但是,当我不需要为了我的目的而定义一个通用的类时,这是愚蠢的。我可以这样做:

  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){...}
}

但现在我的第二种方法看起来太宽泛了,或者不是。我的意思是,如果分配给返回类型的对象没有实现ClassMatchable,它仍然会出现编译错误。那是我应该去的方式吗?所以,我不必强制类型转换?

解决方案

没错,如果你不输入类的引用,那么甚至仅使用方法类型参数的泛型方法不会被聚合。这是Java Generics的更为细微的变化之一。正如你所说,你可以为 T 设置一些任意类型:

  Data Class = new GenericClassFactory< ClassMatchable>()。newObject(new ClassMatcher< Data,String>(){...},key1,my.package.name.impl); 

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

  Data data = GenericClassFactory.newObject(new ClassMatcher< Data,String> {...},key1,my.package.name.impl); 



编辑



请注意, 所有实例成员,而不仅仅是泛型实例方法。因此,有更简单的例子证明了这种奇怪的细微差别。此代码仅编译警告:

  public class Scratchpad< T> {
列表< String>列表;
public static void main(String [] args){
Scratchpad sp = new Scratchpad();
列表<整数> list = sp.list;


code
$ b $ p $这是因为 sp。 list 解析为 List ,而不是 List< String> 即使 Scratchpad.list T 无关。



详细记录在 JLS第4.8节


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



I have a Generic Class Factory class that has two methods one utilizes the Class generic T value and the other only uses its own method generic definitions.

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){...}
}

The method that utilizes the T generic works fine but when I want to use the other method that doesn't care what the T generic is it won't use the Generic E it will just return an Object and then I have to type cast it.

Data data = new GenericClassFactory().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

This has compile errors because it wants me to typecast it to (Data). If I pass the GenericClassFactory a valid Class Generic it will work. Its like it doesn't recognize method generics if you have a Class Generic defined but not used.

Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

That works fine. But it's dumb that I would have to define a class generic like that when it isn't needed for my purposes. I could do this:

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){...}
}

But now my second method seems like its too broad or something...maybe not. I mean it will still give a compile error if the object you are assigning to the return type doesn't implement ClassMatchable. Is that the way I should go? So that I don't have to typecast?

解决方案

That's right, if you don't type a class reference, then even generic methods that only use method type parameters will not be generified. It's one of the weirder nuances of Java Generics. As you say, you can put in some arbitrary type for T:

Data data = new GenericClassFactory<ClassMatchable>().newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

But more likely this shouldn't even be an instance method. Can't it be a static method? If so you could just invoke it like this:

Data data =  GenericClassFactory.newObject(new ClassMatcher<Data, String>(){...}, "key1", "my.package.name.impl");

Edit

Note that this extends to all instance members, not just generic instance methods. Thus, there are simpler cases that demonstrate this odd nuance. This code compiles with only warnings:

public class Scratchpad<T> {
   List<String> list;
   public static void main(String[] args) {
      Scratchpad sp = new Scratchpad();
      List<Integer> list = sp.list;
   }
}

And that's because sp.list is resolved as a List, not a List<String>, even though Scratchpad.list has nothing to do with T.

This is verbosely documented in the JLS, Section 4.8:

The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.

这篇关于Java类泛型和方法泛型冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆