Java 为什么会有额外的<;E>;在这种通用方法中?

Java 为什么会有额外的<;E>;在这种通用方法中?,java,generics,methods,Java,Generics,Methods,不久前我学习了java泛型,但现在我在学习集合,发现了一些我不懂的代码。代码如下: static <E> List<E> nCopies(int n, E value) 不仅如此 List<E> 列表 显然我遗漏了一些东西,有人能帮我澄清一下吗?List是方法的返回类型,而是传入的类型(这是由编译器根据作为E值传递的内容推断出来的) 静态列表方法(E myObject) { E objectOfMyType=myObject; List myList=n

不久前我学习了java泛型,但现在我在学习集合,发现了一些我不懂的代码。代码如下:

static <E> List<E> nCopies(int n, E value)
不仅如此

List<E>
列表
显然我遗漏了一些东西,有人能帮我澄清一下吗?

List
是方法的返回类型,而
是传入的类型(这是由编译器根据作为
E值
传递的内容推断出来的)

静态列表方法(E myObject)
{
E objectOfMyType=myObject;
List myList=new ArrayList();
...
返回myList;
}
这将被称为:

MyObject o = new MyObject();
List<MyObject> myList = SomeClass.someMethod(o);
MyObject o=newmyobject();
List myList=SomeClass.someMethod(o);
我觉得方法的语法有点愚蠢,但你已经有了。相关Oracle教程如下所示:

列表中,第一个
表示
E
是一个类型参数。如果您没有指定它,那么Java会认为
E值
中的
E
引用了一个名为
E
的实际类,并要求您导入它。请参阅。

需要
来告诉编译器您打算使用
E
作为类型参数,这与创建泛型类(例如
公共接口列表
时的方法相同

由于没有关于接口或类名超过一个字符的规则(仅约定),也没有关于类型参数名必须为一个字符的规则(仅约定),编译器不会知道您希望它是一个类型参数,而不是一个具体的类名

编辑 很多人都说这与静态方法直接相关。事实并非如此。您可以有一个实例方法,该方法对其自身的类型参数也是泛型的(尽管类型参数通常与类类型参数相关)

下面是一个示例,说明您可以在何处进行此操作:

public class MyList<E> {

    public <N super E> MyList<N> createCopy() {
        //...
    }
}
公共类MyList{
公共MyList createCopy(){
//...
}
}
此方法允许您创建列表的副本,但不限制您使用与列表相同的类型,而是允许您使用超类型。例如:

MyList<Integer> integers = createList(1, 2, 5);
MyList<Number> numbers = integers.createCopy();
MyList integers=createList(1,2,5);
MyList number=整数。createCopy();
您可以使用
来表示所定义的方法

泛型最常见的例子是有这样一个典型的类:

公共类SomeClass{
...
}
然后,当您创建该类的新对象时,您可以直接这样定义类型:

newsomeclass();
这样,对于该实例,该类中引用
的任何方法都将
视为字符串

现在考虑一个静态方法(它不绑定到一个类的任何特定实例),以便将使用另一种类型化的方法典型化,该方法适用于这样的方法:

静态列表nCopies(int n,E值)

在返回类型之前,使用<代码> <代码>来表示“该特定方法在执行时会考虑一些E”。调用该方法时,将决定

的内容:

nCopies(3,“a”);
在本例中,
将是一个字符串,因此返回类型将是一个
列表

最后,您甚至可以将两者混合使用:

公共类SomeClass{
公共无效剂量(E,F){
...
}
}

在这种情况下,如果您有某个类的实例,doSomething方法中的E将始终是String(对于该实例),但F可以是您想要的任何内容。

简单地说:表示
E
不是类<如果
E
是一个类(或接口),则code>List
将是一个有效的返回类型-尽管不推荐使用,但类可以用一个字母命名(因为类型变量也可以用更多字母命名,即使使用现有的类名,这会混淆任何人:
static List method(){…}
).

我不明白为什么会出现在列表前面。我知道这个值是E类型的,但前面的列表让我感到困惑。谢谢你的回答,这是类型参数的声明。这类似于在方法中声明普通参数的方式,如
String myStringArg
。例如,如果您有两个类型参数,它可能看起来像
,而不仅仅是
。同样,不是因为它是静态的,而是因为它是泛型的。@Mark,同意——goofy的想法是将泛型类型参数声明放在返回类型和方法名称之前,这在某种程度上违背了一些与生俱来的语法意识。@Kirk:也许吧。在我看来,在开始使用E之前,而不是之后,告诉编译器您将使用E作为类型参数是非常有意义的。为什么不能像这样编写:
static List nCopies(int n,value)
。Java编程语言的设计者这样做有什么问题吗?对我来说,这是一种更清晰的表示泛型变量的方法。一个原因可能是,如果您有多个类型为
的参数,它将变得重复;最好先把它放在前面,然后到处使用
public class MyList<E> {

    public <N super E> MyList<N> createCopy() {
        //...
    }
}
MyList<Integer> integers = createList(1, 2, 5);
MyList<Number> numbers = integers.createCopy();