泛型无法适用重载的场景:both methods have same erasure

问题描述

针对集合对象,假设有一套根据其元素上相同名称的属性值进行排序的方法/算法。
由于集合的元素对象除Object外没有共同的基类,此时,首先想到的做法便是”重载“。
但方法重载时,参数数量和集合一样,但泛型的不一样,仍被编译器视为相同的方法,提示诸如:

‘specialSort(List)’ clashes with ‘specialSort(List)’;both methods have same erasure

问题分析

泛型,作为JDK5时代引入的”语法糖“,在编译的时候是会被抹除的,换言之,specialSort(List<Dog>)specialSort(List<Apple>)在编译时都会变成specialSort(List),因此不符合重载的原则(变量名相同、参数类型或数量不同)。

解决方案

方案一:针对集合对象,方法声明不同基类/实现类作为方法参数类型(不推荐)

既然List<Dog>List<Apple>在编译时都回变成List,如果我已知其中一个集合对象是ArrayList对象,以List<Apple>为例,那就可以将其对应的方法参数类型改成ArrayList<Apple>。再或者,直接将其中一个方法改成Collection

如此,因为参数类型不同,便满足重载的条件。

个人认为,这样的做法会大大影响代码的可读性,且会造成大量的冗余代码,虽然能解决问题,但真的不推荐。

此方案参考自:both methods have same erasure:如何无损扩展代码

方案二:设置共同基类/接口,抽象出方法所需要内容

如果两个是类型相近的类,如DogCat,那么可以考虑新建一个公共基类,随后在基类中暴露出为方法所需要的属性获取方法。

可重现问题代码中,方法目的是为了按特殊规则排序,那么也可以选择直接在基类中实现Comparable接口,重写比较的方法。

但对于类型不相近,或较难抽象出公共基类的类,那这个方案就显得不适用了。

方案三:在方法中,直接使用映射机制

在我看来,这是最暴力的方案了,方法中先可以直接通过映射机制获取到对象的属性值,随后便可以进行原来的逻辑代码操作了。

这个方案,不需要重载,省去了那些冗余的逻辑代码,只是反射机制需要格外的开销。

可重现问题代码

class Dog {
    private String name;
    private int age;
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

class Apple {
    private String name;
    private int age;
    public Apple(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

@Test
void test() {
    List<Dog> dogList = Lists.newArrayList();
    dogList.add(new Dog("Dog B", 2));
    dogList.add(new Dog("Dog A", 2));
    dogList.add(new Dog("Dog A", 1));
    specialSort(dogList);
    System.out.println(JSON.toJSONString(dogList));
    List<Apple> appleList = Lists.newArrayList();
    appleList.add(new Apple("Apple B", 2));
    appleList.add(new Apple("Apple A", 2));
    appleList.add(new Apple("Apple A", 1));
    specialSort(appleList);
    System.out.println(JSON.toJSONString(appleList));
}

public static void specialSort(List<Dog> dogList) {
    dogList.sort((o1, o2) -> {
        int result = 0;
        if (o1.getAge() != o2.getAge()) {
            result = o1.getAge() - o2.getAge();
        } else {
            Objects.requireNonNull(o1.getName());
            Objects.requireNonNull(o2.getName());
            result = ObjectUtils.compare(o1.getName(), o2.getName());
        }
        return result;
    });
}

public static void specialSort(List<Apple> appleList) {
    appleList.sort((o1, o2) -> {
        int result = 0;
        if (o1.getAge() != o2.getAge()) {
            result = o1.getAge() - o2.getAge();
        } else {
            Objects.requireNonNull(o1.getName());
            Objects.requireNonNull(o2.getName());
            result = ObjectUtils.compare(o1.getName(), o2.getName());
        }
        return result;
    });
}

方案一:代码实现(不推荐)

// Class Dog 和 Class Apple 的定义不变
@Test
void test() {
    ArrayList<Dog> dogList = Lists.newArrayList();
    dogList.add(new Dog("Dog B", 2));
    dogList.add(new Dog("Dog A", 2));
    dogList.add(new Dog("Dog A", 1));
    specialSort(dogList);
    System.out.println(JSON.toJSONString(dogList));
    ArrayList<Apple> appleList = Lists.newArrayList();
    appleList.add(new Apple("Apple B", 2));
    appleList.add(new Apple("Apple A", 2));
    appleList.add(new Apple("Apple A", 1));
    specialSort(appleList);
    System.out.println(JSON.toJSONString(appleList));
}
public static void specialSort(List<Dog> dogList) {
    dogList.sort((o1, o2) -> {
        int result = 0;
        if (o1.getAge() != o2.getAge()) {
            result = o1.getAge() - o2.getAge();
        } else {
            Objects.requireNonNull(o1.getName());
            Objects.requireNonNull(o2.getName());
            result = ObjectUtils.compare(o1.getName(), o2.getName());
        }
        return result;
    });
}
public static void specialSort(ArrayList<Apple> appleList) {
    appleList.sort((o1, o2) -> {
        int result = 0;
        if (o1.getAge() != o2.getAge()) {
            result = o1.getAge() - o2.getAge();
        } else {
            Objects.requireNonNull(o1.getName());
            Objects.requireNonNull(o2.getName());
            result = ObjectUtils.compare(o1.getName(), o2.getName());
        }
        return result;
    });
}

方案二:代码实现

abstract class ParentClass {
    public abstract String getName();
    public abstract int getAge();
}

class Dog extends ParentClass{
    private String name;
    private int age;
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

class Apple extends ParentClass{
    private String name;
    private int age;
    public Apple(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
@Test
void test() {
    List<Dog> dogList = Lists.newArrayList();
    dogList.add(new Dog("Dog B", 2));
    dogList.add(new Dog("Dog A", 2));
    dogList.add(new Dog("Dog A", 1));
    specialSort(dogList);
    System.out.println(JSON.toJSONString(dogList));
    List<Apple> appleList = Lists.newArrayList();
    appleList.add(new Apple("Apple B", 2));
    appleList.add(new Apple("Apple A", 2));
    appleList.add(new Apple("Apple A", 1));
    specialSort(appleList);
    System.out.println(JSON.toJSONString(appleList));
}

public static <T extends ParentClass> void specialSort(List<T> list) {
    list.sort((o1, o2) -> {
        int result = 0;
        if (o1.getAge() != o2.getAge()) {
            result = o1.getAge() - o2.getAge();
        } else {
            Objects.requireNonNull(o1.getName());
            Objects.requireNonNull(o2.getName());
            result = ObjectUtils.compare(o1.getName(), o2.getName());
        }
        return result;
    });
}

方案三:代码实现

// Class Dog 和 Class Apple 的定义不变
@Test
void test() {
    List<Dog> dogList = Lists.newArrayList();
    dogList.add(new Dog("Dog B", 2));
    dogList.add(new Dog("Dog A", 2));
    dogList.add(new Dog("Dog A", 1));
    specialSort(dogList);
    System.out.println(JSON.toJSONString(dogList));
    List<Apple> appleList = Lists.newArrayList();
    appleList.add(new Apple("Apple B", 2));
    appleList.add(new Apple("Apple A", 2));
    appleList.add(new Apple("Apple A", 1));
    specialSort(appleList);
    System.out.println(JSON.toJSONString(appleList));
}
public static void specialSort(List list){
        list.sort((o1, o2) -> {
            int result = 0;
            // 暂不考虑特殊异常处理
            try {
                String method = "getAge";
                int age1 = (int) o1.getClass().getMethod(method).invoke(o1),
                        age2 = (int) o2.getClass().getMethod(method).invoke(o2);
                if (age1 != age2) {
                    result = age1 - age2;
                } else {
                    method = "getName";
                    String name1 = (String) o1.getClass().getMethod(method).invoke(o1),
                            name2 = (String) o2.getClass().getMethod(method).invoke(o2);
                    Objects.requireNonNull(name1);
                    Objects.requireNonNull(name2);
                    result = ObjectUtils.compare(name1, name2);
                }
            } catch (Exception e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
            return result;
        });
    }
  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值