泛型对象参数的类型问题



我有一个抽象类,

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{
//...
}
}

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

现在我想做的是在构造函数中保存一个新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类兼容?

  2. 在第二种情况下,如何制作安全的铸件?我无法与manager instanceof F核对,那我该怎么办?

谢谢

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

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(它不是编译,因为你只知道F类型是扩展的WebserviceIntegration,但它可以是任何扩展WebserviceIntegration的类型

因此,如果您还有其他扩展Webservice集成的类,例如

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

你创造了另一个NewUserWindow<?, NoManager> noManagerWindow = new NewUserWindow<>(new OtherClass(), new NoManager())你不能做类似noManagerWindow.saveConnectedBean(new Manager())

2(你不应该做一个转换,因为你不能确定F是经理的类型。

我认为您要做的只是使用WebserviceIntegration类型,而不使用任何泛型。

也许是这样的事情。将抽象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中的方法实现,因为实际的子类型未知。

最新更新