gpt4 book ai didi

Java方法重载 - 同一继承树中的通用参数和参数

转载 作者:搜寻专家 更新时间:2023-11-01 01:50:25 25 4
gpt4 key购买 nike

假设我有以下代码:

// Method acception generic parameter
public static <T> T foo(T para) {
return para;
}

// Method accepting Integer parameter
public static Integer foo(Integer para) {
return para + 1;
}

// Method accepting Number parameter
public static Number foo(Number para) {
return para.intValue() + 2;
}

public static void main(String[] args) {
Float f = new Float(1.0f);
Integer i = new Integer(1);
Number n = new Integer(1);
String s = "Test";

Number fooedFloat = foo(f); // Uses foo(Number para)
Number fooedInteger = foo(i); // Uses foo(Integer para)
Number fooedNumber = foo(n); // Uses foo(Number para)
String fooedString = foo(s); // Uses foo(T para)

System.out.println("foo(f): " + fooedFloat);
System.out.println("foo(i): " + fooedInteger);
System.out.println("foo(n): " + fooedNumber);
System.out.println("foo(s): " + fooedString);
}

输出如下所示:

foo(f): 3
foo(i): 2
foo(n): 3
foo(s): Test

现在问题:

  1. foo(n) 调用 foo(Number para),很可能是因为 n 被定义为 Number ,即使它有一个 Integer 分配给它。那么我是否正确地假设决定采用哪些重载方法是在编译时发生的,没有动态绑定(bind)? (关于静态动态绑定(bind)的问题)
  2. foo(f) 使用 foo(Number para),而 foo(i) 使用 foo(Integer para)。只有 foo(s) 使用通用版本。因此,编译器总是会查看给定类型是否存在非泛型实现,只有在没有的情况下才会回退到泛型版本吗? (关于泛型的问题)
  3. 同样,foo(f) 使用 foo(Number para),而 foo(i) 使用 foo(Integer para )。然而,Integer i 也将是一个Number。那么总是采用继承树中“最外层”类型的方法吗? (关于继承的问题)

我知道这些问题很多,而且示例并非来自生产代码,但我只是想知道“背后发生的事情”以及事情发生的原因。

非常感谢任何指向 Java 文档或 Java 规范的链接,我自己找不到它们。

最佳答案

language specification 中解释了确定在编译时调用哪个方法签名的规则。 .特别重要的是关于选择 the most specific method 的部分.以下是与您的问题相关的部分:

If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.

...

One applicable method m<sub>1</sub> is more specific than another applicable method m<sub>2</sub>, for an invocation with argument expressions e<sub>1</sub>, ..., e<sub>k</sub>, if any of the following are true:

  • m<sub>2</sub> is generic, and m<sub>1</sub> is inferred to be more specific than m<sub>2</sub> for argument expressions e<sub>1</sub>, ..., e<sub>k</sub> by §18.5.4.

  • m<sub>2</sub> is not generic, and m<sub>1</sub> and m<sub>2</sub> are applicable by strict or loose invocation, and where m<sub>1</sub> has formal parameter types S1, ..., Sn and m<sub>2</sub> has formal parameter types T1, ..., Tn, the type Si is more specific than Ti for argument e<sub>i</sub> for all i (1 ≤ in, n = k).

...

A type S is more specific than a type T for any expression if S <: T (§4.10).

在这种情况下,IntegerNumber 更具体因为Integer延伸Number ,因此每当编译器检测到对 foo 的调用时接受类型为 Integer 的变量已声明 , 它将添加对 foo(Integer) 的调用.

更多关于第一个条件与第二个方法是通用的在 this section 中解释。 .这有点冗长,但我认为重要的部分是:

When testing that one applicable method is more specific than another (§15.12.2.5), where the second method is generic, it is necessary to test whether some instantiation of the second method's type parameters can be inferred to make the first method more specific than the second.

...

Let m<sub>1</sub> be the first method and m<sub>2</sub> be the second method. Where m<sub>2</sub> has type parameters P1, ..., Pp, let α1, ..., αp be inference variables, and let θ be the substitution [P1:=α1, ..., Pp:=αp].

...

The process to determine if m<sub>1</sub> is more specific than m<sub>2</sub> is as follows:

...

If Ti is a proper type, the result is true if Si is more specific than Ti for ei (§15.12.2.5), and false otherwise. (Note that Si is always a proper type.)

这基本上意味着 foo(Number)foo(Integer)都比 foo(T) 更具体因为编译器可以为生成 Number 的泛型方法(例如 foo(Number) 本身)推断至少一种类型和 foo(Integer)更具体(这是因为 Integer <: NumberNumber <: Number )。

这也意味着在您的代码中 foo(T)仅适用于传递 String 的调用(并且本质上是最具体的方法,因为它是唯一适用的方法) .

关于Java方法重载 - 同一继承树中的通用参数和参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35924313/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com