通用对象参数的类型问题

时间:2018-09-21 07:58:54

标签: java generics

我有一个抽象类

public abstract class WebserviceIntegration {
    //...
}

许多类中都使用了

public class Manager extends WebserviceIntegration {
    //...
}

现在,我已经建立了一个类,该类将通用类的抽象类作为F自变量,并且在其内部具有方法:

public class NewUserWindow<T, F extends WebserviceIntegration> extends Window {

    public NewUserWindow(T objOne, F objTwo) {
        //...
        saveConnectedBean(objTwo); //no problems here
    }

    public void saveConnectedBean(F bean) throws MyException{
        //...
    }
}

如果我创建一个新窗口NewUserWindow<?, Manager> window = new NewUserWindow<>(new OtherClass(), new Manager());并保存传递给该窗口的bean,Ofc一切都很好。

现在我想做的是在构造函数中保存一个 Manager

public NewUserWindow(T objOne, F objTwo) {
        //...

        Manager manager = new Manager();
        //... setting manager stuff

        saveConnectedBean(manager); //does not compile
 }

编译器现在阻止我说saveConnectedBean(F) in NewUserWindow cannot be applied to (my.package.path.Manager)。 如果我用

进行更改
saveConnectedBean((F)manager);

它可以编译,但警告我演员表未选中。

  1. 在第一种情况下,为什么编译器不知道我的Manager类正在扩展WebserviceIntegration,从而使其与F类兼容?

    < / li>
  2. 在第二种情况下,如何进行安全投射?我无法与manager instanceof F核对,该怎么办?

谢谢

2 个答案:

答案 0 :(得分:3)

这不是很清楚,但是根据您的问题,我认为失败的代码位于通用类的构造函数中。

1)编译器认为您对F声明的调用是因为在通用类内部,编译器不知道F的确切类型。不要忘记泛型只是编译工件。
因此,如果在构造函数中实例化Manager变量,例如:

Manager manager = new Manager();

但是您声明了通用类型,例如NewUserWindow<?, OtherSubClass> window = ... 它将破坏类型安全性。

2)避免在通用类中使用instanceof。它在某种程度上破坏了通用目的。

作为替代方案,您应该从通用实例的客户端传递Manager,例如:

Manager manager = new Manager();
NewUserWindow<?, Manager> newUserWindow = new NewUserWindow<>(new ..., manager);
newUserWindow.saveConnectedBean(manager);

根据您的评论:

  

假设我无法跨解决方案2运行,是否还有其他方法可以解决   安全铸造?

您可以通过创建一个NewUserWindow抽象类来实现,该抽象类将返回F的方法声明为抽象。

public abstract class NewUserWindow<T, F extends WebserviceIntegration> extends Window {

    public NewUserWindow(T objOne, F objTwo) {

        F f = createF();
        saveConnectedBean(f);
    }

    public abstract F createF();

    public void saveConnectedBean(F bean) throws MyException{
        //...
    }
}

并实现它,例如:

public ManagerUserWindow extends NewUserWindow<T, Manager> extends Window {

    public Manager createF(){
       return new Manager();
    }

}

答案 1 :(得分:1)

也许是这样。将抽象save方法添加到WebserviceIntegration

public static abstract class WebserviceIntegration {
    public abstract void save();
}

WebserviceIntegration的每个子类中实现此方法

public static class Manager extends WebserviceIntegration {
    @Override
    public void save() { // saving Manager here }
}

因此saveConnectedBean现在可以接受WebserviceIntegration

public void saveConnectedBean(WebserviceIntegration bean) { }

这应该是安全的,因为WebserviceIntegration的每个子类型都必须实现save功能。


或者,您可以引入新的方法类型参数

public <B extends WebserviceIntegration> void saveConnectedBean(B bean) { }

在这种情况下,saveConnectedBean仅限于使用WebserviceIntegration中的方法来实现,因为实际的子类型是未知的。