【问题标题】:Java Chain Inheritance with Lombok and Guice Injections带有 Lombok 和 Guice 注入的 Java 链继承
【发布时间】:2019-03-04 05:08:50
【问题描述】:

编辑:这个问题真的应该围绕 Lombok 和 Guice 而不是 vanilla java 继承。

我正在尝试使用 Lombok 和 Guice 注入实现 Java 继承链,它的工作原理如下:

第一类

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 等)来完成这项工作?

谢谢。

【问题讨论】:

  • 您的抽象类即使有公共构造函数也不能直接实例化,因为它们被声明为抽象的。如果您愿意,可以将构造函数设为 protected 以表明它们仅可用于子类。
  • 显示的代码不会产生你提到的错误,因为它有一个默认的构造函数。
  • 感谢@khelwood,对abstract 类无法真正实例化,但为什么Java 编译器没有捕捉到这一点并停止抱怨没有构造函数?
  • 这是您的完整代码吗?正如马克已经说过,您发布的内容不应导致错误(可能是警告),因为如果不存在其他构造函数,编译器将添加一个空构造函数。
  • 抽象类无法实例化,但由于子类构造函数中隐式调用super(),它们仍然需要构造函数。

标签: java inheritance dependency-injection guice lombok


【解决方案1】:

当您使用某些参数构造函数实现继承概念时,最好在其中定义一个默认(无参数)构造函数。因为在内部创建子类编译器的对象时,会调用父类的构造函数。 例如

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
 }

如果您在父类中实现了参数构造函数,那么编译器将不会隐式实现默认构造函数,我们需要显式定义它以便从子构造函数调用超级构造函数。或者从子构造函数显式调用参数构造函数。

【讨论】:

    【解决方案2】:

    我建议:

    1. 仅对整个层次结构使用接口。
    2. 解耦行为并将它们封装在单独的类中。
    3. 使用组合而不是继承,即私有 SomeBehavior someBehavior;适合每一种需要它的特定动物。

    它会让你的设计更好,也能解决问题。

    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;
    }
    

    现在你的狗可以...和p... :)

    同时添加

    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

    当然,创建一个抽象的 Animal 是有意义的。

    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);
        }
    }
    

    所以你的错误是当你可以使用接口时使用了太多抽象。

    【讨论】:

      【解决方案3】:

      即使您添加公共构造函数,您的抽象类也不能直接实例化,因为它们被声明为抽象类。如果您愿意,可以将构造函数设为 protected 以指示它们仅可用于子类。

      没错,抽象类不能真正实例化,但为什么 Java 编译器没有捕捉到这一点并停止抱怨没有构造函数?

      您编写的任何没有显式构造函数的类都有一个隐式的无参数构造函数。任何隐式无参数构造函数都会隐式调用其超类的无参数构造函数,即使该超类是抽象的。因此,如果链上的某个类没有无参数构造函数(因为您明确地给了它另一个构造函数),那么您的代码将无法编译。

      在您在问题中提供的代码中,没有显式构造函数,因此每个类 确实 都有一个隐式的无参数构造函数。在你的实际代码中,大概你在某处写了一个构造函数,这就是为什么没有添加隐式无参数构造函数的原因。

      【讨论】:

      • “void 构造函数”是官方术语吗?我认为它被称为“无参数构造函数”。对构造函数使用“void”可能会导致混淆,认为 void 是一种返回类型,而构造函数没有返回类型。
      • @DodgyCodeException 你说得对,没有参数更清楚。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-26
      • 2019-01-12
      • 2020-08-23
      • 2011-12-24
      • 2016-05-04
      • 2021-11-05
      • 2015-09-03
      相关资源
      最近更新 更多