在 Java 中使用泛型类型的静态函数

static functions using generic types in Java

提问人:SoullessWarrior 提问时间:9/8/2023 最后编辑:HolgerSoullessWarrior 更新时间:9/8/2023 访问量:61

问:

当我遇到以下函数时,我正在查看 java.util.function 中 Predicate 的源代码(对于上下文来说,它是一个函数接口,它返回一个布尔值,采用了 T 类型的一些通用输入):

    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }

    @SuppressWarnings("unchecked")
    static <T> Predicate<T> not(Predicate<? super T> target) {
        Objects.requireNonNull(target);
        return (Predicate<T>)target.negate();
    }

我对静态函数如何与所有这些泛型类型一起使用感到困惑。这是怎么回事?

我期待某种类型推理使这种情况发生。在第一种方法中,返回函数是一个可以隐式输入的函数,但是由于参数是类型,我希望这只能变成一个类型的类,在我看来,这完全违背了在函数中使用的意义。Predicate<T>targetRefObjectPredicate<Object>T

第二个函数,我甚至想不出一个合理的推理模式,看起来很荒谬。返回类型被转换为 ,但会返回 ,这使得接受超级参数本身很奇怪,而且,由于 return 语句中的类型转换,以及参数中的模糊性,不可能从中知道一个明智的。这两种方法是如何工作的,为什么这样定义它们?Predicate<T>target.negatePredicate<? super T>T

Java 泛型 接口 转换

评论

1赞 Holger 9/8/2023
泛型方法是声明至少一个类型参数的方法。调用方决定要用于类型参数的实际类型参数 () 。你的短语“这只能变成谓词类型的类”是不可理解的。您应该使用反引号标记代码片段,以便类型参数不会与 HTML 标记混淆。如前所述,调用方决定什么是,因此,返回 a 允许调用方决定谓词将具有什么实际参数化。这有效,因为每个对象都有一个方法。TPredicate<T>equals

答:

2赞 knittl 9/8/2023 #1

我们总是可以显式指定类型:

static <T> Predicate<T> isEqual(Object targetRef) {
    return (null == targetRef)
            ? Objects::isNull
            : (T object) -> targetRef.equals(object);
}

所以 while 是类型 ,是类型 。targetRefObjectobjectT

T取决于调用上下文,例如:

Predicate.isEqual(something); // T == Object
Predicate.<String>isEqual(something); // T == String
Predicate<Double> p = Predicate.isEqual(something); // T == Double
Stream.of(1,2,3).filter(Predicate.isEqual(2)); // T == Integer

评论

0赞 SoullessWarrior 9/8/2023
是的,但由于它是一个静态方法,它将像 Predicate.isEqual(myobject) 一样被调用,为了参数,myobject 是一个 Integer。在这种情况下,什么是T?
1赞 knittl 9/8/2023
@SoullessWarrior这取决于调用上下文。Predicate<String> p = Predicate.isEqual(myInteger);
0赞 SoullessWarrior 9/8/2023
啊,谢谢!这澄清了一切。剩下的唯一问题是:为什么第二种方法采用超类,然后将否定转换为 T?
0赞 Andy Turner 9/8/2023
@SoullessWarrior调用泛型方法的结果是 polyexpression:相同的代码可以具有不同的类型,具体取决于它的使用方式(例如,分配给它的变量类型)。
1赞 Andy Turner 9/8/2023
@SoullessWarrior演员正在将允许的参数类型从“某事,我们不知道具体是什么,但可以接受”缩小到“只有可接受”。如果您使用的 API 适当地使用了泛型,它应该能够接受比需要的更通用的谓词;但有时,它们不接受通用参数,例如,您需要一个实际参数而不是 A,您只会将 s 传递给它。TTPredicate<String>Predicate<Object>String
0赞 Jorn 9/8/2023 #2

对于第一个函数,该方法始终采用 .您可能希望只采用其自身类型的参数,但这不是它的作用。这样一来,参数就只能由调用者的需求来推断:您可以轻松地传递给期望 的东西,这将正常工作(并且始终返回)。equalsObjectObject::equals<T>isEqual("")Predicate<Integer>false

第二个函数以大致相同的方式从调用方推断。just的意思是“任何可以消费的东西”。强制转换是必需的,因为编译器无法知道返回的 by 作为 .<T>superPredicateTPredicatenegatePredicate<T>