EDIT: This question really should be around Lombok and Guice instead of vanilla java inheritance.
I'm trying to implement a Java inheritance chain with Lombok and Guice injections, it works something like this:
Class 1
public abstract class Animal {
@NonNull protected String attr1;
protected abstract void method1();
void method0() {
// Some code that uses attr1
}
}
Class 2
public abstract class Mammal extends Animal {
@NonNull protected String attr2;
protected abstract void method2();
@Override
void method1() {
// some logic that uses attr2
method2();
}
}
Class 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
}
}
Out there in the main
program I have code that calls wolf.method1()
. The problem here is that only wolf
has all the attributes needed (due to Guice injections), whereas all the fields in Animal
are undefined. I suspect I can probably do it in Vanilla Java, but things are going to get super messy (I have 6 attributes in Animal
class and 5 more in Mammal
). Is there a way to mix-and-match lombok's annotations (@NoArgsConstructor, @AllArgsConstructor, etc) to make this work?
Thanks.
Your abstract classes cannot be directly instantiated even if you add public constructors, because they are declared abstract. If you prefer, you can make the constructors protected
to indicate they are only available to subclasses.
right that abstract classes can't really be instantiated, but why didn't the Java compiler catch this and stop complaining about not having a constructor?
Any class you write without an explicit constructor has an implicit no-args constructor. Any implicit no-args constructor implicitly calls its superclass's no-args constructor, even if that superclass is abstract. So if some class up the chain doesn't have a no-args constructor (because you explicitly gave it another constructor), then you code won't compile.
In the code you gave in your question, there are no explicit constructors, so every class does have an implicit no-args constructor. In your actual code, presumably you have written a constructor somewhere, which is why the implicit no-args constructor has not been added.
I propose:
It will make your design better and solve the problem as well.
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() {
}
}
and then
public class Sheperd implements Dog {
private TakeADump dumpService;
private TakeApee peeService;
}
And now your dog can s... and p... :)
Also add
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
Of course it will make sense to create an abstract Animal.
ie
public class AbstractAnimal {
private TakeADump dumpService;
private TakeApee peeService;
private F... f...Service;
}
then
public abstract class AbstractDog extends AbstractAnimal implements Dog {
}
and
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);
}
}
So your mistake is using too much abstract when you can use interfaces.
When you are implementing concept of inheritance with some argument constructor it is good practice to have one default (no argument) constructor defined there. Because while creating object of child class compiler internally will call constructor of parent class. eg
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
}
if anyhow you have implemented argument constructor in parent class then compiler will not implement default constructor implicitly we need to define it explicit to make call to super constructor from child constructor. Or do a explicit call to argument constructor from child constructor.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.