Java中的通用方法和类型推理

时间:2012-07-16 22:41:50

标签: java generics type-inference

鉴于以下不是非常有用的代码:

package com.something;

import java.util.ArrayList;
import java.util.Collection;

//Not a generic class!
public class Test {

  public <T> void plain(T param1, T param2) {}
  public <T> void fancy(T param1, Collection<T> param2) {}

  public void testMethod() {

    //No error
    fancy("", new ArrayList<String>());

    //Compiler error here!
    fancy("", new ArrayList<Integer>());

    //No error
    plain("", new ArrayList<Integer>());

  }

}

(请纠正我的理解,如果它错了!)

第二次调用fancy()是一个编译器错误,因为Java无法推断两个参数之间的任何常见类型(不能推断Object,因为第二个参数必须是Collection。)

plain()的调用是而不是编译器错误,因为Java在两个参数之间推断出Object的公共类型。

我最近遇到的代码的方法签名类似于plain()

我的问题是:

plain()的签名对任何内容都有用吗?

也许编写该代码的人认为plain()的签名会强制两个参数在编译时具有相同的类型,显然不是这种情况。

使用plain()这样的签名编写方法有什么不同或有益,而不是仅仅将这两个参数定义为Object

3 个答案:

答案 0 :(得分:4)

虽然编译器不会推断出一个人可能想要的泛型类型,但它强制执行明确指定的类型约束。以下调用会导致类型错误。

this.<String>plain("", new ArrayList<Integer>()); /* Compiler error. */
  

参数化方法&lt; String&gt;类型为Test的String(String,String)不适用于参数(String,ArrayList&lt; Integer&gt;)

答案 1 :(得分:3)

我猜你可以说它可以作为某种文档,因此用户知道你希望两个参数属于同一类型。当然,任何两个对象在某种程度上属于同一类型(它们都是Object),所以这是一个毫无意义的陈述。

长话短说,这是一个无用的签名。

当然,如果plain返回了T类型,那就是另一个故事。

答案 2 :(得分:1)

  

对fancy()的第二次调用是编译器错误,因为Java无法推断   两个参数之间的任何常见类型(不能从而推断出Object   第二个参数必须是Collection。)

好吧,我不确定这是什么原因,我会说原因是T中的泛型类型Collection<T>是一个不变量,其值决定了第一个参数{{1}的类型}}

例如,这是有效的:

T

因为所有fancy("", new ArrayList<CharSequence>()); //compiles Ok 都是String。从CharSequences推断出类型后,预计第一个参数为CharSequence

但是,这是无效的:

ArraysList<CharSequence>

因为预期第一个参数的类型为fancy((CharSequence)"", new ArrayList<String>()); //compiler error ,我们无法确保所有String实际上都是CharSequences类型,对吗?

因此,AFAIK,类型不兼容的原因是由于这种情况下泛型的性质,而不是第二种类型是String的事实。