编辑:这个问题确实应该围绕Lombok和Guice展开,而不是香草java继承。
我正在尝试通过Lombok和Guice注入实现Java继承链,它的工作原理如下:
1级
public abstract class Animal {
@NonNull protected String attr1;
protected abstract void method1();
void method0() {
// Some code that uses attr1
}
}
第2类
public abstract class Mammal extends Animal {
@NonNull protected String attr2;
protected abstract void method2();
@Override
void method1() {
// some logic that uses attr2
method2();
}
}
3级
public class Wolf extends Mammal {
@Inject @NonNull private String attr1;
@Inject @NonNull private String attr2;
@Inject @NonNull private String attr3;
@Override
void method2() {
// some logic
}
}
在main
程序中,我有调用wolf.method1()
的代码。这里的问题是只有wolf
具有所需的所有属性(由于Guice注入),而Animal
中的所有字段都是未定义的。我怀疑我可以在Vanilla Java中做到这一点,但是事情将变得一团糟(Animal
类中有6个属性,Mammal
中有5个属性)。有没有一种方法可以混合和匹配lombok的注释(@ NoArgsConstructor,@ AllArgsConstructor等)来使之工作?
谢谢。
答案 0 :(得分:1)
即使添加公共构造函数,您的抽象类也无法直接实例化,因为它们被声明为抽象的。如果愿意,可以使构造函数protected
表示它们仅可用于子类。
对抽象类不能真正实例化是正确的,但是Java编译器为什么没有抓住这个并停止抱怨没有构造函数?
您编写的没有显式构造函数的任何类都具有隐式的无参数构造函数。任何隐式的无参数构造函数都隐式调用其超类的无参数构造函数,即使该超类是抽象的。因此,如果链中某个类没有no-args构造函数(因为您显式地为其指定了另一个构造函数),则您的代码将无法编译。
在您提供的问题代码中,没有显式构造函数,因此每个确实类都有一个隐式的无参数构造函数。在您的实际代码中,大概是在某个地方写了一个构造函数,这就是为什么未添加隐式no-args构造函数的原因。
答案 1 :(得分:0)
我建议:
这将使您的设计更好,也可以解决问题。
i.e.
public interface Mammals {
}
public interface Animal extends Mammals {
}
public interface Dog extends Animal {
}
and
public class TakeADump {
public void dump() {
}
}
public class TakeAPee {
public void pee() {
}
}
然后
public class Sheperd implements Dog {
private TakeADump dumpService;
private TakeApee peeService;
}
现在你的狗可以...和......)
也添加
public class F... {
public void f...(<Animal> animal) {
// ... check it's an instance of the same or compatible animal or throw UnsupportedOperationException() if it's incompatible
}
}
:D
当然,创建抽象动物是有意义的。
即
public class AbstractAnimal {
private TakeADump dumpService;
private TakeApee peeService;
private F... f...Service;
}
然后
public abstract class AbstractDog extends AbstractAnimal implements Dog {
}
和
public class Sheperd extends AbstractDog {
public void lookAfterSheep() {
Sheep sheep = SheepLocator.findNearest();
// pee on a sheep
peeService.pee(sheep);
// dump on a sheep
dumpService.dump(sheep);
// f... a sheep
f...Service.mount(sheep);
}
}
因此,当您可以使用接口时,您的错误是使用了太多抽象。
答案 2 :(得分:0)
使用某些参数构造函数实现继承的概念时,最好在其中定义一个默认(无参数)构造函数。因为在创建子类的对象时,编译器会在内部调用父类的构造函数。 例如
class ABC {
}
class XYZ implements ABC{
}
public class Test{
XYZ obj= new XYZ() // this will internally call default constructor of XYZ and
//in that first statement will super()--> this will call default constructor of class ABC
}
无论如何,如果您已经在父类中实现了参数构造函数,那么编译器将不会隐式实现默认构造函数,我们需要显式定义它,以便从子构造函数调用超级构造函数。或从子构造函数中显式调用参数构造函数。