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

时间:2015-12-14 13:29:18

标签: java generics refactoring

以下是类

中的两种方法

类开发人员和学生不同,不共享任何父母。

以下两种方法都使用相同的代码和方法调用两个对象具有相同的名称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();
       .....
    }
}

显示错误方法的删除与类型中的其他方法相同

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

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

4 个答案:

答案 0 :(得分:5)

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

为了解决您的问题,这里有一个解决方案,可以概括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;
}

答案 1 :(得分:2)

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

似乎你的StudentDeveloper类在某种程度上共享行为,因为它们都有一个同名的方法,它做同样的事情:getStartDate()。这表明您可以声明一个定义此常见行为的接口,例如&#34;可启动&#34;然后你只需要为接口定义一次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类之间的一些复制粘贴,因为我猜测,他们不仅份额的共同行为,还有公共结构(至少是一个private LocalDate startDate;字段)。这始终是一个指示器,您应该将您的常见结构和行为提取到抽象类中。 E.g:

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

这不仅会为您节省大量的复制粘贴的,但它也会使你的代码更清晰给其他人,并帮助您避免错误,当你改变的东西在一个地方,忘记拷贝。

简而言之:如果你意识到你正在忙于复制粘贴,或者如果你遇到了泛型问题,那么它几乎总是意味着你需要继承。如果你的类有共同的行为(即有相同的方法) - &gt;使用界面。如果您的类共享共同的结构(即具有相同的字段) - &gt;使用抽象类。

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

答案 2 :(得分:1)

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

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

现在这两种方法不再相互超载,让你继续单独实现。

答案 3 :(得分:0)

我尝试了Mena提供的解决方案,但它仍然对我不起作用,对我有用的是子类扩展了父类并传递了List <?将BaseClass>扩展到单个继承的方法。