我使用Java泛型实现了一个简单的付款处理系统。它可以在运行时进行编译和运行,但是我对“未经检查的转换”警告感到困惑。

enum PaymentType {
    CARD, SAVED_CARD
}

interface PayData {
}

class CardPayData implements PayData {
    private String cardNumber;
    private String cvc;
}

class SavedCardPayData implements PayData {
    private String cardId;
}

interface PayService<T extends PayData> {
    void pay(T payData);
}

class CardPayService implements PayService<CardPayData> {
    @Override
    public void pay(CardPayData cardPayData) {
        // i need concrete class CardPayData here
    }
}

class SavedCardPayService implements PayService<SavedCardPayData> {
    @Override
    public void pay(SavedCardPayData payData) {
        // i need concrete class SavedCardPayData here
    }
}

class PayServiceFactory {
    private CardPayService cardPayService = new CardPayService();
    private SavedCardPayService savedCardPayService = new SavedCardPayService();

    public PayService getService(PaymentType paymentType) {
        if (paymentType.equals(PaymentType.CARD))
            return cardPayService;
        else
            return savedCardPayService;
    }
}

class PaymentProcessor {
    PayServiceFactory payServiceFactory = new PayServiceFactory();

    public void serveRequest(PayData payData, PaymentType paymentType) {
//        here i have 'unchecked cast' warning
        PayService<PayData> payService = (PayService<PayData>) payServiceFactory.getService(paymentType);
        payService.pay(payData);
    }
}


试图摆脱这种警告的任何尝试都会导致我出现编译错误。例如,我尝试从我的工厂方法返回泛型类型,但只收到编译错误:

// return generic
public PayService<? extends PayData> getService(PaymentType paymentType) { ... }


 public void serveRequest(PayData payData, PaymentType paymentType) {
        PayService<? extends PayData> payService =  payServiceFactory.getService(paymentType);
// error here:
// pay (capture <? extends PayData>) in PayService cannot be applied to (PayData)
        payService.pay(payData);
    }

最佳答案

类的设计本质上是不安全的类型。具体来说,serveRequest方法:

public void serveRequest(PayData payData, PaymentType paymentType) {
    PayService<PayData> payService = (PayService<PayData>) payServiceFactory.getService(paymentType);
    payService.pay(payData);
}


无法强制payData的运行时类型与payService.pay期望的兼容。根据paymentTypegetService可能在运行时返回PayService<Anything>,因此payService.pay可能会在运行时期望任何类型。因为payData应该是的类型只能在运行时知道,所以不能在编译时强制执行。

最好的办法是放入SuppressWarnings并使payData通用:

@SuppressWarnings("unchecked")
public <T extends PayData> void serveRequest(T payData, PaymentType paymentType) {
    PayService<T> payService = (PayService<T>) payServiceFactory.getService(paymentType);
    payService.pay(payData);
}

09-15 23:44