2

尝试使用泛型类型创建静态字段无法编译:

class MyClass {

    public static Function<Z, Z> blargh = new Function<Z, Z>() {
        public Z apply(Z a) {
            return a;
        }
    };
}

日食 说:

Multiple markers at this line
    - Z cannot be resolved to a type
    - Z cannot be resolved to a type
    - Z cannot be resolved to a type
    - Z cannot be resolved to a type
    - The type new Function<Z,Z>(){} must implement the inherited 
     abstract method Function<Z,Z>.apply(Z)

但是用具体类型替换所有Zs 就可以了:

static Function<Integer, Integer> blargh = new Function<Integer, Integer>() {
    public Integer apply(Integer a) {
        return a;
    }
};

这里发生了什么?


语境:

  1. 我最初是想弄清楚为什么这段代码使用方法而不是字段:

    public static <T extends Throwable> F<T, String> eMessage() {
      return new F<T, String>() {
        public String f(final Throwable t) {
          return t.getMessage();
        }
      };
    }
    

    也许是为了克服这个限制?

  2. Function类型来自谷歌的番石榴库。

4

3 回答 3

3

编辑:现在我更好地看到了这个问题。

我认为首先你必须将类型声明为类参数:

class MyClass<Z> {

获得可见性,但现在你不能这样使用它的原因是因为静态成员应该在类的所有实例之间共享。但是由于您可以创建具有不同类型参数的实例,因此依赖于特定类型的静态成员将没有意义。

于 2012-09-17T17:00:14.953 回答
3

您只能在成员字段上使用类级别的泛型。例如:

public class MyClass<Z> {
    private Function<Z, Z> function;
    // ...
}

是正确的。相反,声明它static会中断。为什么?

想想ArrayList。它的类声明类似于:

public class ArrayList<E> extends AbstractList<E> implements List<E>, ... {
    // ...
}

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>();

因此,因为可以从实例更改为实例,所以在级别上有一个变量E是没有意义的。Estatic

现在您可以使用泛型声明static方法,但方式完全不同。例如,Collections.sort可以有这样的声明:

public static <T> void sort(List<? extends T> list, Comparator<T> comparator)

请注意,T它在返回类型之前声明为方法的一部分。这是定义T方法内的上下文,并且T可能因调用而异。

编辑后备注:在您的情况下,您没有在Z任何地方声明,因此无论如何您都无法使用它。请参阅我上面的声明MyClass。注意我是如何<Z>直接在课堂上使用的?这意味着这Z将是某种任意类型。

在您试图弄清楚的情况下,您应该将Function其视为表示转换的通用方式。让我们剖析您发布的方法:

public static <T extends Throwable> F<T, String> eMessage() {
    return new F<T, String>() {
        public String f(final Throwable t) {
            return t.getMessage();
        }
    };
}

首先,请注意这是一种方法,而不是像您的 OP 这样的静态字段,因此在这里使用泛型是合法的。此外,它是static,因此任何泛型都需要在返回类型之前声明。在这里,他们声明<T extends Throwable>,因此T必须是某种扩展的错误或异常Throwable。返回类型是F<T, String>,它是一个接受T(a Throwable) 并返回 a的函数String。实际对象声明了一个f方法,该方法通过调用Throwable.getMessage. 由于项目是functionjava,一切都是基于F类的,所以泛型无处不在。

只要记住:

  1. 在类级别声明的泛型只能由非静态成员和方法使用。
  2. 在方法级别声明的泛型是允许的,但不要引用类级别的类型,而是引用在返回类型之前声明的类型。
  3. 根本不允许在静态字段级别声明的泛型,因为它们永远不会为其具体类型提供上下文。
于 2012-09-17T17:28:15.393 回答
1

我认为最简单的答案可能是:尽管 JDK 编译器在解释泛型方面很灵活,但鉴于代码的语义,不可能修改或指定“Z”类。

在所有泛型的使用中,您必须定义一种语法,该语法指定正在操作的泛型类的标识。例如(如上例所示)。

1) 使用通用的、参数化的效用函数。在这种情况下,它对编译器来说是显而易见的,因为指定的类是作为函数的输入发送的。

2) 将类本身定义为通用且非静态的。这将要求该类的用户使用正确指定的类参数来声明它。

具体来说,对于 Function 类,您明确定义了一个受约束的类:一个将“Z”作为输入,并返回“Z”作为输出的类。如果你想生成它,你可以创建一个 FunctionFactory 类,例如,它接受 Z 的单个实例,并返回一个类型指定的函数 type :

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;
                        }
                    };
            }
于 2012-09-18T16:17:19.420 回答