我在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方法只是为了测试)
答案 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
的实例或将其作为参数传递(参见其他答案)。