【问题标题】:How does java determine, which overloaded method will call, when one method with generic type parameter and other with non generic parameter?当一个方法具有泛型类型参数而另一个具有非泛型参数时,java如何确定将调用哪个重载方法?
【发布时间】:2021-02-19 06:00:29
【问题描述】:

Java 类不能有两个在类型擦除后具有相同签名的重载方法。 Java 将针对以下情况生成编译时错误:

public class Example {
    public void print(Set<String> strSet) { }
    public void print(Set<Integer> intSet) { }
}

但我的问题不是那个。有两种情况1和2。我想知道,为什么他们的行为不一样?

Scenario 1:

import java.util.ArrayList;
import java.util.List;

public class MethodOverload {

    public static void main(String[] args) {
        
        MethodOverload methodOverload = new MethodOverload();

        //Point 1 - List here
        List<Integer> mangoList = new ArrayList<Integer>();
        mangoList.add(1);
        mangoList.add(2);
        
        System.out.println("Size List<Integer>:"+methodOverload.count(mangoList));
        
        //Point 2 - ArrayList here
        ArrayList<String> nameList = new ArrayList<String>();
        nameList.add("Anex");
        nameList.add("Alia");
        nameList.add("Maxim");
        
        System.out.println("Size List<String>:"+methodOverload.count(nameList));
    }
    
    public <T> int count(List<T> list) {
        System.out.print("Ïn side generic; ");
        return list.size();
    }
}

场景 1 的输出:

Inside generic block; Size List<Integer> : 2
Inside generic block; Size List<String>  : 3

Scenario 2:

import java.util.ArrayList;
import java.util.List;

public class MethodOverload {

    public static void main(String[] args) {
        
        MethodOverload methodOverload = new MethodOverload();

        //Point 3 - List here
        List<Integer> mangoList = new ArrayList<Integer>();
        mangoList.add(1);
        mangoList.add(2);
        
        System.out.println("Size List<Integer>:"+methodOverload.count(mangoList));
        
        //Point 4 - ArrayList here
        ArrayList<String> nameList = new ArrayList<String>();
        nameList.add("Anex");
        nameList.add("Alia");
        nameList.add("Maxim");
        
        System.out.println("Size List<String>:"+methodOverload.count(nameList));
    }
    
    public <T> int count(List<T> list) {
        System.out.print("Inside generic block; ");
        return list.size();
    }
    
    //Point 5
    public int count(ArrayList<String> list) {
        System.out.print("Inside non-generic block; ");
        return list.size();
    }

}

场景 2 的输出:

Inside generic block;     Size List<Integer> : 2
Inside non-generic block; Size List<String>  : 3

现在,我的问题是,在scenario 2 的情况下,java 如何决定调用哪个方法? 在scenario 1 中,java 调用单个计数方法没有任何问题,那么为什么 java 没有为scenario 2 显示类似的行为?

【问题讨论】:

    标签: java generics overloading


    【解决方案1】:

    因为类型擦除仅适用于泛型类型。 Java 不会“擦除”继承。

    在场景 1 中,count() 方法签名在运行时实际上变成了这样:

    public int count(List<Object> list) {...}
    

    所以 mangoList(声明为 List)和 nameList(声明为 ArrayList)都符合这个签名。

    在场景 2 中,方法签名在运行时实际上变成了这样:

    public int count(List<Object> list) {...}
    
    public int count(ArrayList<Object> list) {...}
    
    • 由于 mangoList 被声明为 List,Java 将它与第一个 count() 方法相匹配,将 List 作为参数。
    • 由于 nameList 被声明为 ArrayList,Java 将它用于第二个 count() 方法,将 ArrayList 作为参数。

    早在泛型出现之前,Java 就知道如何进行这种(基于继承的)重载。它不能做的是基于未绑定泛型类型的重载,因为运行时类型擦除,这就是编译器阻止你这样做的原因。

    【讨论】:

    • 感谢您的详尽解释。
    【解决方案2】:

    在 Java 中,方法参数类型是方法签名的一部分

    因此,该方法将在编译时根据参数类型进行绑定。 (这不应该被误解为调用方法的引用变量的多态行为,比如methodOverload

    在上面的代码中,

    1. 引用类型为List 的第一个调用将绑定到以List 作为参数类型的方法
    2. 让我们假设,不存在以List 作为参数类型的方法,并假设存在以ArrayList 作为参数的方法。编译器如何保证 List 在运行时实际上是 ArrayList 以维护类型安全承诺。既然不能,就禁止这种绑定。
    3. 类型为ArrayList 的第二个调用将绑定到具有精确类型ArrayList 的方法(如果存在)。如果该方法不存在,则映射到List方法(如果考虑泛型,则使用相关泛型类型)

    基本上,

    1. 其方法将被调用的对象由调用该方法的引用变量的多态性决定(编译器确保只有引用变量类型的类在编译时具有相关方法,但不控制子类方法被调用在运行时)
    2. 一旦对象被运行时识别,要在该对象上调用的方法由编译时绑定基于参数控制。

    最后的想法

    1. 覆盖是一种运行时行为,由调用该方法的引用的对象类型决定
    2. 重载是一种编译时确定性行为,用于根据参数类型由 time time 选择的对象。

    【讨论】:

    • 感谢您的精彩解释。
    猜你喜欢
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 2011-12-25
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多