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

Erasure of method is the same as another method in type

以下是class

中的两种方法

class Developer 和 Student 不同,不共享任何 parent。

以下两个方法具有相同的代码,并且在两个对象上调用的方法具有相同的名称 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();
       .....
    }
}

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

我了解同一站点上其他 post 错误背后的原因。

如何重构它以便不存在错误并且代码干净?

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

为了解决你的问题,这里有一个解决方案概括了DeveloperStudent的共同特征,因此只需要一个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;
}

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

您的 StudentDeveloper class 似乎在某种程度上共享行为,因为它们都有一个相同名称的方法来做同样的事情:getStartDate().这表明您可以声明一个定义此常见行为的接口,例如"Startable"然后你只需要为接口定义一次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();
        // ...
    }
}

继续那个轨道,您可能会注意到您在 DeveloperStudent class 之间进行了一些复制粘贴,因为我猜他们不仅共享共同行为,还有共同结构(至少一个private LocalDate startDate;字段)。这始终表明您应该将共同的结构和行为提取到抽象中 class。例如:

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();
        // ...
    }
}

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

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

希望对您有所帮助,祝您好运!

通常,重构具有相同擦除的接口的正确方法是通过重命名一个或两个方法来删除重载:

class HierarchyValidator {
    private LocalDate[][] getArrayOfDeveloperTimespan(List<Developer> developers) {
       //here i have to call some method on developer from list
        LocalDate startDate = developer.getStartDate();
        ....
    }
    private LocalDate[][] getArrayOfStudentTimespan(List<Student> students) {
       //here i have to call some method on student from list
        LocalDate startDate = student.getStartDate();
       .....
    }
}

现在这两个方法不再相互重载,让您可以分别执行。

我尝试了 Mena 提供的解决方案,但它仍然对我不起作用,对我有用的是 subclasses 扩展父 class 并传递 List 此列表扩展到单个继承方法。