我有一个家长班
public class Parent
{
Database m_d;
Parent(Database d){
m_d = d;
}
}
还有一个儿童班
public class Child extends Parent implements java.lang.AutoCloseable
{
ChildDatabase m_d
Child()
{
// Error on the next statement:
// "Cannot reference m_database before supertype constructor
// has been called"
super(m_d = CreateDatabase());
}
}
请注意,ChildDatabase
实现了java.lang.AutoCloseable
,这就是为什么我需要在ChildDatabase
类中保留Child
引用的原因。请注意,ChildDatabase
扩展了Database
。
问题在于super(m_d = CreateDatabase());
无效,因为您无法在对super
的调用中引用子类成员。
是否缺少我可以使用的语法?一种替代方法是在getDatabase()
中实现Parent
方法,并将结果转换为ChildDatabase
并存储为m_d;
,但这对我来说似乎是一种气味。 >
请注意,CreateDatabase
可以是static
。
答案 0 :(得分:2)
怎么样
public abstract class Parent<DB extends Database>
{
DB m_d;
Parent()
{
m_d = getDatabase();
}
abstract DB getDatabase();
}
和
public class Child extends Parent<ChildDatabase> implements java.lang.AutoCloseable
{
Child()
{
// do something with this.m_d here
}
@Override
ChildDatabase getDatabase()
{
return createChildDatabase();
}
}
然后,你甚至可以使用AutoCloseable功能,直接在this.m_d(如试...用等)。
答案 1 :(得分:0)
通过在父类中引入对象的吸气剂,您可以编写它:
public class Child extends Parent implements java.lang.AutoCloseable
{
ChildDatabase m_d;
Child()
{
// Error on the next statement:
// "Cannot reference m_database before supertype constructor
// has been called"
super(CreateDatabase());
this.m_d = (ChildDatabase)getMd();
}
}
但是向下转换是不可取的,它可能会在运行时失败并且看起来很hack。
如果子类需要将字段引用为ChildDataBase
,则它应该在构造函数本身中是显式的,例如:
ChildDatabase m_d;
Child(ChildDatabase childDb)
{
super(childDb);
m_d = childDb;
}
通常,如果不是实现细节,则应明确依赖项,因为它有利于可测试性和转换为其他实现。
请注意,我对此解决方案也不满意。
这仍然会复制层次结构中的字段。
这里的问题是,您想为父构造函数和子构造函数赋值不同的已声明类型的同一对象。
你不应该。人们阅读您的代码时容易出错。
使用通用类可能更好,并且允许子类为数据库字段指定子类。
仍然需要在父类中提供getter。
public class Parent<T ? extends DataBase>
{
private T m_d;
Parent(T d){
m_d = d;
}
public T getMd(){
return m_d;
}
}
具有隐藏依赖性:
public class Child extends Parent<ChildDataBase> implements AutoCloseable
{
Child(){
super(CreateDatabase());
}
void foo(){
ChildDataBase md = getMd(); // return the generic type
}
}
具有公开的依赖性:
public class Child extends Parent<ChildDataBase> implements AutoCloseable
{
Child(ChildDataBase md){
super(md);
}
void foo(){
ChildDataBase md = getMd(); // return the generic type
}
}
答案 2 :(得分:0)
您要实现的目标只是不可行。
在Java language specification之后,在完成对super
(构造函数)的调用之前,无法初始化任何类字段成员。
当您在Child
类中实现特定行为时,一种解决方法可能是忽略本地m_d
字段,该字段在与工厂混合的工厂中传递所需的Database
实例引用。子类型Database
的通用形式类型。
下面是Parent
类类型:
public class Parent<D extends Database> {
D m_d;
Parent(D m_d) {
m_d = m_d;
}
protected D getDatabase() {
return this.m_d;
}
}
Child
如下:
public class Child extends Parent<ChildDatabase> {
private Child(ChildDatabase m_d) {
super(m_d);
}
private static ChildDatabase createDatabase() {
return null;
}
public static class ChildFactory {
public static Child createChild() {
return new Child(createDatabase());
}
}
}
答案 3 :(得分:0)
为什么要在m_d
和Parent
中都包含字段Child
?仅在Parent
中使用它是否足够?只需将super(createDatabase());
的{{1}}放在Child
的构造函数中,如以下代码所示:
public class Parent
{
Database m_d;
Parent(Database d)
{
m_d = d;
}
}
class Child extends Parent implements java.lang.AutoCloseable
{
Child()
{
super(createDatabase());
}
private static ChildDatabase createDatabase()
{
return new ChildDatabase();
}
@Override
public void close() throws Exception
{
}
}
class Database
{
}
class ChildDatabase extends Database implements java.lang.AutoCloseable
{
@Override
public void close() throws Exception
{
}
}