针对集合对象,假设有一套根据其元素上相同名称的属性值进行排序的方法/算法。
由于集合的元素对象除Object
外没有共同的基类,此时,首先想到的做法便是”重载“。
但方法重载时,参数数量和集合一样,但泛型的不一样,仍被编译器视为相同的方法,提示诸如:
‘specialSort(List)’ clashes with ‘specialSort(List)’;both methods have same erasure
泛型,作为JDK5时代引入的”语法糖“,在编译的时候是会被抹除的,换言之,specialSort(List
和specialSort(List
在编译时都会变成specialSort(List)
,因此不符合重载的原则(变量名相同、参数类型或数量不同)。
既然List
和List
在编译时都回变成List
,如果我已知其中一个集合对象是ArrayList
对象,以List
为例,那就可以将其对应的方法参数类型改成ArrayList
。再或者,直接将其中一个方法改成Collection
。
如此,因为参数类型不同,便满足重载的条件。
个人认为,这样的做法会大大影响代码的可读性,且会造成大量的冗余代码,虽然能解决问题,但真的不推荐。
此方案参考自:both methods have same erasure:如何无损扩展代码
如果两个是类型相近的类,如Dog
和Cat
,那么可以考虑新建一个公共基类,随后在基类中暴露出为方法所需要的属性获取方法。
在可重现问题代码
中,方法目的是为了按特殊规则排序,那么也可以选择直接在基类中实现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;
});
}