泛型无法适用重载的场景: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;});}

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

  1. both methods have same erasure, yet neither overrides the other

    文章目录 both methods have same erasure, yet neither overrides the other 1.编译报错 both methods have same e ...

  2. 泛型与操作符重载杂谈

    泛型基础 1.为什么要用泛型类,我们先来看一段代码: 以交换两个数为例,可能需要定义多个重载方法 public static void swap(ref int x,ref int y) { int ...

  3. C#笔记09 结构、枚举、异常、泛型、操作符重载、dll、垃圾回收与资源清理、XML注释

    文章目录 结构体struct 枚举enum 异常Exception 执行try最近的最贴切的catch 继承Exception以定义异常 泛型 泛型的约束where 操作符重载 类型转换操作符重载 d ...

  4. Java筑基——泛型的点点滴滴

    目录 1. 泛型的作用 2. 泛型类 3. 泛型接口 4. 泛型方法 5. 泛型擦除 5.1 擦除是什么? 5.2 擦除时使用边界替换类型参数 5.3 擦除会插入类型转换来保持类型安全 5.4 擦除会 ...

  5. 深入理解 Java 泛型

    首先提个问题: Java 泛型的作用是什么?泛型擦除是什么?泛型一般用在什么场景? 如果这个问题你答不上来,那这篇文章可能就对你有些价值. 读完本文你将了解到: 什么是泛型 为什么引入泛型 泛型的使用 ...

  6. java 泛型全解 - 绝对最详细

    背景 对于java的泛型我一直属于一知半解的,平常真心用的不多.直到阅读<Effect Java>,看到很多平常不了解的用法,才下定决心,需要系统的学习,并且记录下来. 1.泛型的概述: ...

  7. Java泛型的定义和使用详解

    目录 一,为什么我们需要泛型 二,什么是泛型,泛型的定义 三,如何定义和使用泛型 四.限定类型变量 五.泛型中的约束和局限性 六.泛型类型的继承规则 七.通配符类型 八.虚拟机是如何实现泛型的? 一, ...

  8. 3万字死磕Java泛型所有细节知识点,看这一篇就够了

    1 泛型 1.0 前言--为什么要死磕Java泛型 不知道阅读这篇文章的你是否曾跟我一样,在没有阅读<Java核心技术>前查阅了大量的Java泛型文章,但是在实际使用泛型的过程中,总是觉得 ...

  9. 泛型爪哇(Generic Java)

    泛型爪哇(Generic Java) Java 可能即将有一场大变革 译者:陈崴 侯捷注:本文系北京<程序员>杂志 2001/05 的文章.译笔顺畅,技术饱满. 承译者陈崴先生与<程 ...

最新文章

  1. 详解linux系统的启动过程及系统初始化
  2. kali linux提示安装系统失败,kali“安装系统”失败分析及解决
  3. 基于单目视觉的智能车辆视觉导航系统设计
  4. luncene 查询字符串的解析—QueryParser类
  5. VTK修炼之道24:图像基本操作_单颜色通道图像合成彩色
  6. GPS服务端解析程序编写日记之--vs2010中多种语言开发及调试的若干注意事项
  7. python中的栈结构_python中有栈吗
  8. [转载]DB2数据库移植罕见成绩片面理睬(4)
  9. outlook的插件管理(Web界面)
  10. 我又踩坑了!如何为HttpClient请求设置Content-Type标头?
  11. caffe(CPU版本)配置 及MNIST调用
  12. 93.复原IP地址(力扣leetcode) 博主可答疑该问题
  13. cr全称是什么意思_魔兽世界CR是团灭的意思 他的全称是什么呢?
  14. 打卡项目php,Thinkphp框架早起打卡项目(深蓝引擎Z)趣步模式+完整数据+全开源源码...
  15. 卡方检验结果表格中出现非常多个卡方值和P值的原理和实现步骤
  16. 五个拿来就能用的炫酷登录页面
  17. win10服务器只显示4g内存,64位win10识别到了4G内存,却只用了3.1G,为什么?
  18. 阿里巴巴与山东省人民政府签署战略合作协议
  19. Fabric CA的基础知识
  20. 应用统计学与R语言实现学习笔记(三)——描述性统计

热门文章

  1. 越老越吃香的计算机专业,大四学长:最有前途的4个理工专业,毕业工作不愁,还越老越吃香...
  2. 大话水声通信技术---(BFSK仿真)
  3. 如何在ubuntu中安装无线网卡驱动(迅捷FW150UH)
  4. driver failed programming external connectivity on endpoint rabbitmq (204c074dd525374b10eec763a068ec
  5. 2020美团面试真题解析
  6. 检验c语言程序是否正确的程序,c语言实习心得体会范文
  7. excel多表格数据汇总如何实现
  8. 百度云盘搜索引擎【升级版】
  9. 融资破局 |中英美三国多层次资本市场和STO融资的比较及借鉴
  10. 计算机辅助测试题,2017计算机辅助设计练习题