Java泛型,将T方法称为T而不是其超类

时间:2016-03-18 22:32:51

标签: java generics

我在java中有以下伪代码:

class MyClassSuper{
    public static final String VALUE = "e";
}

class MyClassSub extends MyClassSuper{
    public static final String VALUE = "f";
}

class MyGenericClass<T extends MyClassSuper> {
    public void print(){
        System.out.println(T.VALUE);
    }
}

当我使用MyClassSub作为其类型创建MyGenericClass的新实例时,我期望print方法打印“f”,但它会打印“e”。是否有可能让MyGenericClass将T视为实际类型,同时保留T当前扩展的超类?

修改

实际代码(缩写):

public class Bean implements Serializable {

    public static final String FILE_EXT = "";
    private static final long serialVersionUID = 1L;

}

public class UserBean extends Bean{

    public static final String FILE_EXT = "u";
    private static final long serialVersionUID = 1L;

    private String name;

    public UserBean(String name){
        this.name = name;
    }
}

public class BeanPersistence<T extends Bean> implements IBeanPersistence<T> {

    public void printExtension(){
        System.out.println(T.FILE_EXT);
    }

}

这是我正在尝试编写的代码。基本上我希望BeanPersistence类根据它初始化的Bean的类型知道它正在编写的文件使用什么扩展。从我收集的评论来看,这是错误的做法,这将是什么方式? (显然printExtension方法只是为了测试)

3 个答案:

答案 0 :(得分:2)

正确的方法是使用多态:在MyClassSuper中添加一个非静态方法,可以在子类中重写,并为MyGenericClass提供实例:

class MyClassSuper{
    public String getValue() { return "e"; }
}

class MyClassSub extends MyClassSuper{
    public String getValue() { return "f"; }
}

class MyGenericClass<T extends MyClassSuper> {
    private final T instance;

    MyGenericClass(T instance) { this.instance = instance; }

    public void print(){
        System.out.println(instance.getValue());
    }
}

答案 1 :(得分:2)

这可能是合适的,具体取决于您的情况。

public class BeanPersistence<T extends Bean> {

    public void printExtension(Bean bean) {
        System.out.println(bean.getExtension());
    }

    public static void main(String[] args) {

        BeanPersistence<Bean> persistence = new BeanPersistence<>();
        UserBean userBean = new UserBean();
        AdminBean adminBean = new AdminBean();
        persistence.printExtension(userBean); // prints u
        persistence.printExtension(adminBean); // prints a
    }
}

abstract class Bean {

    abstract String getExtension();
}

class UserBean extends Bean {

    private static final String FILE_EXT = "u";

    @Override
    String getExtension() {
        return FILE_EXT;
    }
}

class AdminBean extends Bean {

    private static final String FILE_EXT = "a";

    @Override
    String getExtension() {
        return FILE_EXT;
    }
}

通常,您应该通过方法访问对象属性,而不是直接访问。当我们调用方法时,面向对象的行为(多态,动态调度)将调用正确的方法。

另见

答案 2 :(得分:1)

我今天之前没有意识到这甚至会编译。发生的事情是因为T extends MyClassSuper,当类被编译成字节码时,T被视为MyClassSuper,所以T.VALUE实际上只是MyClassSuper.VALUE,这就是它打印"e"的原因。 (我很惊讶你可以在类型参数上访问静态字段和方法 - 我完全没有理由看到它。)

接下来,请记住,覆盖仅适用于实例方法,而不适用于字段或静态内容。

您尝试执行的操作的另一个问题是,由于类型擦除,类型T在运行时甚至不知道,因此您无法根据其值选择String

您的问题的一个解决方案是使用扩展的实例方法,可以在子类中重写。这需要持有T的实例或将其作为参数传递(参见其他答案)。