Java 方法重载并选择最特定的类型

Java 方法重载并选择最特定的类型,java,static-methods,overloading,Java,Static Methods,Overloading,示例代码是: public class OverloadingTest { public static void test(Object obj){ System.out.println("Object called"); } public static void test(String obj){ System.out.println("String called"); }

示例代码是:

    public class OverloadingTest {

       public static void test(Object obj){
           System.out.println("Object called");
       }

       public static void test(String obj){
           System.out.println("String called");
       }

       public static void main(String[] args){
           test(null);
           System.out.println("10%2==0 is "+(10%2==0));
           test((10%2==0)?null:new Object());
           test((10%2==0)?null:null);
   }
输出为:

调用的字符串
10%2==0为真
被调用的对象
调用的字符串

test(null)
的第一次调用调用带有
String
参数的方法,根据
Java语言规范
这是可以理解的

1) 有人能解释一下在前面的调用中调用
test()
的依据是什么吗

2) 同样,当我们放置时,说一个
if
条件:

    if(10%2==0){
        test(null);
    }
    else
    {
        test(new Object());
    }
它总是使用
String
参数调用方法


编译器会在编译时计算表达式
(10%2)
?我想知道表达式是在编译时还是在运行时计算的。谢谢。

我认为你的问题在于你做出了错误的假设,你的表达方式:

test((10%2==0)?null:new Object());
(10%2==0)? null : new Object(); // A
(10%2==0)? null : null; // B

将始终调用test(null),这就是它们将通过test(Object)的原因

同:

Object o;

if(10%2==0)
    o=null;
else
    o=new Object();

test(o);

由于
o
的类型是
Object
(就像
(10%2==0)的类型一样),因此将始终调用null:newobject()
测试(Object)
o
的值无关紧要。

您的答案是:运行时,因为在运行时指定参数是否为字符串的实例,所以在编译时无法找到它。

正如@Banthar提到的结束
?:
操作符首先为变量赋值,然后计算条件。 另一方面,您提到的
if
条件总是返回true,因此编译器将仅用
if
1)if1)的
test()
方法由编译时的参数类型决定:

test((Object) null);
test((Object)"String");
输出:

Object called
Object called
2) 编译器更加智能,编译后的代码相当于:

test(null);
您可以使用
javap-c
检查字节码:

   0: aconst_null   
   1: invokestatic  #6                  // Method test:(Ljava/lang/String;)V
   4: return  
这就是我们对这个问题的看法

如果有多个方法声明可访问且适用 对于方法调用,必须选择一个来提供 运行时方法分派的描述符。Java编程 语言使用的规则是选择最具体的方法

这是您案例中的测试(字符串)方法

正因为如此,如果你加上

public static void test(Integer obj){
           System.out.println("Ingeter called");
       }
它将显示编译错误-类型重载测试的方法测试(字符串)不明确

正如JLS所说:

可能没有最具体的方法,因为有 两个或多个最大特定方法。在这种情况下:

如果所有最大特定方法具有相同的签名,则: 如果其中一个最大特定的方法未声明为抽象,则 这是最具体的方法。否则,所有的 方法必须声明为抽象的。最具体的方法是 在最大特定的方法中任意选择。但是, 大多数特定的方法被认为是在以下情况下引发选中的异常: 仅当在每个 最大特定方法。否则,我们说该方法 调用不明确,会发生编译时错误


Java使用早期绑定。最具体的方法是在编译时选择的。根据参数数量和参数类型选择最具体的方法。在这种情况下,参数的数量不相关。这就给我们留下了参数的类型

参数有什么类型?这两个参数都是表达式,使用三元条件运算符。问题归结为:条件三元运算符返回什么类型?类型是在编译时计算的

给出了两个表达式:

test((10%2==0)?null:new Object());
(10%2==0)? null : new Object(); // A
(10%2==0)? null : null; // B
列出了类型评估的规则。在
B
中很容易,两个术语完全相同:
null
将被返回()(JLS:“如果第二个和第三个操作数具有相同的类型(可能是null类型),那么这就是条件表达式的类型。”)。在
A
中,第二个术语来自特定类别。由于这更为具体,并且
null
可以替代类
object
的对象,因此整个表达式的类型为
object
(JLS:“如果第二个和第三个操作数中的一个为null类型,另一个为引用类型,则条件表达式的类型为该引用类型。”)

表达式的类型求值后,方法选择与预期一样

使用
if
给出的示例是不同的:使用两种不同类型的对象调用方法。三元条件运算符在编译时总是计算为一种类型,适合这两个术语。

JLS 15.25:

条件表达式的类型确定如下:

[……]

  • 如果第二个和第三个操作数中的一个为null类型,而另一个为null类型 是引用类型,则条件表达式的类型就是该引用 类型
[……]

那么

10 % 2 == 0 ? null : new Object();

这是一个很好的问题

让我试着澄清一下你上面写的代码

  • 在第一个方法调用中
测试(空)

在这种情况下,
null
将转换为字符串类型,因此根据JLS调用
测试(字符串obj)

  • 在第二个方法调用中
测试((10%2==0)?null:新对象()

它将返回布尔值“true”。所以第一个布尔“true”值将自动转换到布尔包装类对象中。布尔包装器对象正在三元运算符中找到与
新对象()
选项的最佳匹配。该方法以对象作为参数调用,因此它调用followin