有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

泛型Java在匿名类定义中引用枚举类型

我试图定义以下匿名Google Guava函数实例:

Function<E extends Enum<E>, String> ENUM_TO_STRING = new Function<E extends Enum<E>, String>() {
    @Override
    public String apply(E enumValue) {
        String result = null;
        if (enumValue != null) {
            result = enumValue.toString();
        }
        return result;
    }
};

这个想法是一个简单的转换函数实例,它有一个apply方法,如果不为null,则对任何枚举值调用toString,如果值为null,则返回null

不幸的是,编译器抱怨泛型引用E扩展了Enum。我知道这个表达式可以在非匿名的上下文中使用,例如:

public static <E extends Enum<E>> String enumToString(E enumValue) {
    String result = null;
    if (enumValue != null) {
        result = enumValue.toString();
    }
    return result;      
}

第一,匿名类定义是不正确的。第二个非匿名方法定义没有问题

是否仍然可以使用枚举定义匿名类

谢谢


共 (3) 个答案

  1. # 1 楼答案

    不能在任何地方只使用泛型类型变量。您必须处于一个可以声明和访问它们的上下文中

    在第二个示例中,它们在方法签名中声明

    在第一个示例中,似乎没有在任何地方声明E。换句话说,不能将类型变量声明为变量声明的一部分。如果代码片段出现在声明的类型变量E中的方法或类本身,则可以执行您正在尝试的操作

  2. # 2 楼答案

    这里可能根本不需要泛型,因为实际上不使用类型信息,而且在运行时也会丢失。首先从老函数apply(枚举值)开始。如果您真的不想抑制警告,并且需要进行类型检查,那么您可以从那里进一步调查

  3. # 3 楼答案

    作为Sotirios points out,泛型类型参数只能为类或方法声明,不能为字段声明。事实上,声明E可能是不必要的——一个Function<Enum<?>, String>就可以了:

    Function<Enum<?>, String> ENUM_TO_STRING = new Function<Enum<?>, String>() {
        @Override
        public String apply(Enum<?> enumValue) {
            if (enumValue != null) {
                return enumValue.toString();
            }
            return null;
        }
    };
    

    按照这一思路,toString是由Object而不是Enum声明的,因此一般的Function<Object, String>更有意义:

    Function<Object, String> NULLABLE_TO_STRING = new Function<Object, String>() {
        @Override
        public String apply(Object obj) {
            if (obj != null) {
                return obj.toString();
            }
            return null;
        }
    };
    

    一般来说,最好将实现细节隐藏在工厂方法后面,以便于将来的更改,例如:

    private static final Function<Object, String> NULLABLE_TO_STRING = ...
    
    public static Function<Object, String> nullableToString() {
        return NULLABLE_TO_STRING;
    }
    

    请注意,Function<Object, String>仍在返回。只要您的API使用PECS(例如接受^{),这应该没问题,但我们也可以更进一步,通过使方法通用来提供特定的输入类型:

    private static final Function<Object, String> NULLABLE_TO_STRING = ...
    
    public static <T> Function<T, String> nullableToString() {
        @SuppressWarnings("unchecked") // safe contravariant cast
        final Function<T, String> withNarrowedType =
                (Function<T, String>)(Function<?, String>)NULLABLE_TO_STRING;
        return withNarrowedType;
    }
    

    请注意,这使用了相同的Function实例,并使用未经检查的强制转换来缩小其输入类型。强制转换是安全的,因为NULLABLE_TO_STRING接受任何对象,并且是无状态的。约书亚·布洛赫(Joshua Bloch)在有效的Java项目27“偏爱泛型方法”中展示了这种模式