Java 为什么可以';我不能声明一个参数化的静态类变量吗?
尝试使用泛型类型创建静态字段不会编译:Java 为什么可以';我不能声明一个参数化的静态类变量吗?,java,generics,static,Java,Generics,Static,尝试使用泛型类型创建静态字段不会编译: class MyClass { public static Function<Z, Z> blargh = new Function<Z, Z>() { public Z apply(Z a) { return a; } }; } 这是怎么回事 背景: 我最初试图弄清楚为什么使用方法而不是字段: public static <T extends Th
class MyClass {
public static Function<Z, Z> blargh = new Function<Z, Z>() {
public Z apply(Z a) {
return a;
}
};
}
这是怎么回事
背景:
public static <T extends Throwable> F<T, String> eMessage() {
return new F<T, String>() {
public String f(final Throwable t) {
return t.getMessage();
}
};
}
公共静态F消息(){
返回新的F(){
公共字符串f(最终可丢弃的t){
返回t.getMessage();
}
};
}
也许是为了克服这个限制函数
类型来自Google的guava库编辑:现在我更清楚地看到了这个问题 我认为首先必须将类型声明为类参数:
class MyClass<Z> {
class-MyClass{
为了获得可见性,现在您不能这样使用它的原因是,静态成员应该在类的所有实例之间共享。但是,由于您可以使用不同的类型参数创建实例,因此依赖于特定类型的静态成员没有意义。您只能在成员fie上使用类级别的泛型lds。例如:
public class MyClass<Z> {
private Function<Z, Z> function;
// ...
}
E
没有静态意义上的上下文,因为静态变量属于ArrayList
的所有实例,但是E
对于每个ArrayList
实例可能不同:
// Here's one ArrayList with E as String
List<String> strs = new ArrayList<String>();
// And another with E as Boolean
List<Boolean> bools = new ArrayList<Boolean>();
请注意,T
在返回类型之前声明为方法的一部分。这是在方法中定义T
的上下文,并且T
可以因调用而异
编辑后备注:在您的情况下,您没有在任何地方声明Z
,因此您无论如何都不能使用它。请参阅我上面的声明,了解MyClass
。注意我是如何直接在类上使用
的?这意味着Z
将是任意类型
在您试图弄清楚的情况下,您应该将函数
视为表示转换的一种通用方式。让我们分析一下您发布的方法:
public static <T extends Throwable> F<T, String> eMessage() {
return new F<T, String>() {
public String f(final Throwable t) {
return t.getMessage();
}
};
}
公共静态F消息(){
返回新的F(){
公共字符串f(最终可丢弃的t){
返回t.getMessage();
}
};
}
首先,请注意,这是一个方法,而不是像OP那样的静态字段,因此在这里使用泛型是合法的。此外,它是静态的
,因此任何泛型都需要在返回类型之前声明。在这里,它们声明
,因此T
必须是某种扩展了可丢弃性的错误或异常。返回类型是F
,这是一个采用T
(aThrowable
)的函数并返回一个字符串
。实际对象声明了一个f
方法,该方法通过调用Throwable.getMessage
来实现。由于项目是functionaljava,所有内容都基于f
类,因此泛型无处不在
记住:
在类级别声明的泛型只能由非静态成员和方法使用
允许在方法级别声明泛型,但不引用类级别的类型,而是引用在返回类型之前声明的类型
不允许在静态字段级别声明泛型,因为它们的具体类型永远不会有上下文
我认为最简单的答案可能是:尽管JDK编译器在解释泛型方面很灵活,但在给定代码语义的情况下,不可能修改或指定“Z”类
在所有泛型的使用中,您必须定义一个语法来指定正在操作的泛型类的标识。例如(如上面的示例所示)
1) 使用一个通用的、参数化的实用程序函数。在这种情况下,它对编译器来说是显而易见的,因为指定的类是作为函数的输入发送的
2) 将类本身定义为泛型和非静态。这将要求类的用户使用正确的指定类参数声明它
具体地说,对于函数类,您明确定义了一个受约束的类:一个以“Z”作为输入,并返回“Z”作为输出的类。如果您想将其泛化,您可以创建一个FunctionFactory类,该类接收Z的单个实例,并返回一个类型为的指定函数:
public static <Z> Function<Z,Z> functionFactory(final Z default){
return new Function<Z,Z>(){
@Override
public Z apply(Z input) {
// TODO Auto-generated method stub
if(input==null)
return default;
else
return input;
}
};
}
公共静态函数functionFactory(最终Z默认值){
返回新函数(){
@凌驾
公共Z应用(Z输入){
//TODO自动生成的方法存根
如果(输入==null)
返回默认值;
其他的
返回输入;
}
};
}
@Matt Fenwick:你能展示静态成员周围的代码吗?特别是你声明它的类吗?值得注意的是,尽管在Java中,GenericType
和GenericType
实际上是相同的类型,但并非所有面向对象的框架都是这样工作的。在.net中(可能还有其他一些框架),在程序执行过程中使用的每一个泛型类型参数组合都将生成一个不同的泛型类型,并有自己的一组静态变量。任何希望从一个框架切换到另一个框架的人都应该意识到这些区别。@supercat Good point.Java的擦除是该警告的最终原因。很好指出,由于缺少擦除,其他语言可能(并且通常确实)具有不同的语义。谢谢:)
// Here's one ArrayList with E as String
List<String> strs = new ArrayList<String>();
// And another with E as Boolean
List<Boolean> bools = new ArrayList<Boolean>();
public static <T> void sort(List<? extends T> list, Comparator<T> comparator)
public static <T extends Throwable> F<T, String> eMessage() {
return new F<T, String>() {
public String f(final Throwable t) {
return t.getMessage();
}
};
}
public static <Z> Function<Z,Z> functionFactory(final Z default){
return new Function<Z,Z>(){
@Override
public Z apply(Z input) {
// TODO Auto-generated method stub
if(input==null)
return default;
else
return input;
}
};
}