Java -- 如何处理构造函数中的类型擦除?

2022-09-02 10:49:47

假设我的类中有两个构造函数:

public User (List<Source1> source){
...
}

public User (List<Source2> source) {
...
}

假设这两个构造函数都提供有关用户的相同信息,并且是为不同用例构造用户的同样有效的方式。

在Java中,由于类型擦除,您无法执行此操作 - Java不会接受两个参数为参数的构造函数List< ?>.

那么,有什么办法可以解决这个问题呢?什么是不过度但仍然尊重基本OO的解决方案?仅仅因为Java没有强大的泛型支持,就必须围绕这一点构建一个工厂方法或其他接口,这似乎是错误的。

以下是我能想到的可能性:

1) 接受 a 作为构造函数的参数,并在构造函数中分析您需要哪种逻辑,或者如果它不是任何可接受的类型,则引发异常。List<?>

2) 创建一个接受 List 的类,构造相应的 User 对象,然后返回它。

3) 创建包装器,可以改为传递给 User 构造函数。List<Source1>List<Source2>

4)用两个类来子类这个家伙,其中除了构造函数之外,所有功能都是继承的。一个构造函数接受 Source1,另一个接受 Source2。

5)用构建器包装这个家伙,其中有两种不同的构建器方法,用于两个不同的实例化数据源。

我的问题是这些:

1)需要这样做是Java的缺陷,还是有意的设计决策?什么是直觉?

2)在维护良好代码而不引入不必要的复杂性方面,哪种解决方案最强大?为什么?

这个问题是类似的:在Java中围绕类型擦除设计构造函数,但没有涉及细节,它只是建议各种解决方法。


答案 1

通常的方法是使用工厂方法

public static User createFromSource1(List<Source1> source) {
    User user = new User();
    // build your User object knowing you have Source1 data
    return user;
}

public static User createFromSource2(List<Source2> source) {
    User user = new User();
    // build your User object knowing you have Source2 data
    return user;
}

如果你只想使用 或 (即你没有默认构造函数)进行构造,你只需隐藏你的构造函数,强制客户端使用你的工厂方法:Source1Source2

private User () {
    // Hide the constructor
}

出现此问题的原因是,您无法以不同的方式命名构造函数,如果这些是正常方法,那么这就是您克服此问题的方法。由于构造函数名称固定为类名,因此此代码模式只是区分然后给出相同类型擦除的方法。


答案 2

1:保持与擦除的向后兼容性。

2: 你的类可以使用泛型吗?像这样:

public class User<T> {
    private List<T> whatever;
    public User(List<T> source){
       ....
    }
}

我不确定这是否是你的意思(2)


推荐