有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

具有泛型对象参数的java类型问题

我有一个抽象类

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,那么一切都很好

现在我想做的是在构造函数中保存一个新的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检查,那我该怎么办

谢谢


共 (2) 个答案

  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的方法实现,因为实际的子类型未知

  2. # 2 楼答案

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

    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);
    

    根据您的评论:

    Let's say I can't run across solution 2, is there any other way for safe casting?

    可以通过执行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();
        }
    
    }