方法的擦除与类型中的另一种方法相同

sil*_*ons 3 java generics refactoring

以下是一个类中的两种方法

class Developer和Student是不同的,不共享任何父级.

以下两种方法都使用相同的代码和方法调用两个对象具有相同的名称ex.getStartDate.

class hierarchyValidator {
    private LocalDate[][] getArrayOfTimespan(List<Developer> developers)
    {
       //here i have to call some method on developer from list
        LocalDate startDate = developer.getStartDate();
        ....
    }

    private LocalDate[][] getArrayOfTimespan(List<Student> students)
    {
       //here i have to call some method on student from list
        LocalDate startDate = student.getStartDate();
       .....
    }
}
Run Code Online (Sandbox Code Playgroud)

它显示错误方法的擦除与类型中的另一种方法相同

我理解同一网站上其他帖子的错误原因.

如何重新考虑它,以便错误不会存在,代码将是干净的?

Men*_*ena 5

您的问题是由于类型擦除:您的Lists中的参数化类型信息在运行时被擦除,因此这些方法具有几乎相同的签名,您的代码无法编译.

为了解决您的问题,这里有一个解决方案,它概括了Developer和的共同特征Student,因此对于给定的参数化类型只需要一种 getArrayOfTimespan方法:

// common interface to Student and Developer classes
interface Datable {
    LocalDate getStartDate();
}
// dev class implementing "datable"
class Developer implements Datable {
    @Override
    public LocalDate getStartDate() {
        // TODO Auto-generated method stub
        return null;
    }
}
// student class implementing "datable"
class Student implements Datable {
    @Override
    public LocalDate getStartDate() {
        // TODO Auto-generated method stub
        return null;
    }
}
// parameter interpreted as list of super type to both dev and student
private LocalDate[][] getArrayOfTimespan(List<Datable> args)
{
    for (Datable d: args) {
        // TODO something
        LocalDate foo = d.getStartDate();
    }
    // TODO return something
    return null;
}
Run Code Online (Sandbox Code Playgroud)


Kap*_*aar 5

这是 Java 泛型的固有问题。因为泛型类型在运行时被删除,所以 jvm 无法决定getArrayOfTimespan()调用哪个版本的方法,因为两者将具有完全相同的签名:即getArrayOfTimespan(List<Object> arg1)。因此你的错误。然而,如果我们超越 Java 泛型的表面及其局限性,就会发现 Java 编译器实际上是在告诉您存在更深层次的问题。

看来您StudentDeveloper类在某种程度上共享行为,因为两者都有一个名称相同的方法来执行相同的操作:getStartDate()。这表明您可以声明一个定义此常见行为的接口,例如“可启动”,然后您只需getArrayOfTimespan()为该接口定义一次方法。

interface Startable {
   LocalDate getStartDate();
}

class Developer implements Startable { /* ... */ }

class Student implements Startable { /* ... */ }

class hierarchyValidator {
    private LocalDate[][] getArrayOfTimespan(List<Startable> startables)
    {
        // ...
        LocalDate startDate = startable.getStartDate();
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

Developer继续沿着这条路线,您可能会注意到您正在您的类之间进行一些复制粘贴Student,因为我猜测它们不仅共享共同的行为,而且还共享共同的结构(至少是一个private LocalDate startDate;字段)。这始终表明您应该将公共结构和行为提取到抽象类中。例如:

abstract class Person {
    private LocalDate startDate;

    public LocalDate getStartDate() {
        return this.startDate;
    }
    // ... etc ...
}

class Student extends Person{}

class Developer extends Person{}

class hierarchyValidator {
    private LocalDate[][] getArrayOfTimespan(List<Person> people)
    {
        // ...
        LocalDate startDate = person.getStartDate();
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这不仅可以为您节省大量的复制粘贴,而且还可以使您的代码对其他人来说更清晰,并帮助您避免在您在一处更改内容而忘记副本时出现错误。

简而言之:如果您意识到自己正忙于复制粘贴,或者遇到泛型问题,则几乎总是意味着您需要继承。如果您的类共享共同的行为(即具有相同的方法)--> 使用接口。如果你的类共享共同的结构(即具有相同的字段)-->使用抽象类。

希望这有帮助,祝你好运!