具有超类参数的groovy中的TupleConstructor

时间:2017-09-26 09:18:18

标签: inheritance groovy constructor annotations

我的代码中有以下代码模式

class A {
    String x
    String y
    String z
    A() { }
    A(String a) { } 
}

@groovy.transform.InheritConstructors
class B extends A {
   B(String x, String y) {
      this.x = x
      this.y = y
      this.z = ""
   }
}

@groovy.transform.TupleConstructor(callSuper = true, includeSuperProperties = true)
class C extends B {
    String r
}

println new B("x1", "y1").x

println new C("x2", "y2", "r").r

我尝试实现的是能够像最后一行一样创建C对象。我得到的是一个错误。

Could not find matching constructor for: B(java.lang.String, java.lang.String, java.lang.String)

有没有办法通过注释实现这一点(避免在C中自己编写构造函数)? //您可以尝试使用https://groovy-playground.appspot.com/上的代码

1 个答案:

答案 0 :(得分:1)

您应该避免手动实现构造函数并同时使用AST转换生成的情况。您也不应将@TupleConstructor@InheritConstructor混在一起。最新的(Groovy 2.4.12)TupleConstructor类Javadoc非常神秘,它说:

  

(...)不要与InheritConstructors一起使用。

如果你检查InheritConstructors Javadoc,你会看到:

  

(...)不要与TupleConstructor一起使用。

用于Groovy的Javadoc 2.5.0-SNAPSHOT 在“已知限制”部分中说了更多内容:

  

已知限制:

     
      
  • 如果您定义自己的构造函数或与创建构造函数的其他AST变换(例如@InheritConstructors)组合,则此AST变换可能会变为无操作;在这种情况下,处理特定变换的顺序变得很重要。有关自定义此行为的详细信息,请参阅force属性。
  •   
  • 此AST转换通常使用默认参数值,这些值在封面下创建多个构造函数。如果要定义自己的构造函数或与创建构造函数的其他AST转换组合(例如@InheritConstructors),则应小心使用;在这种情况下,处理特定变换的顺序变得很重要。有关自定义此行为的详细信息,请参阅defaults属性。
  •   
  • 如果第一个属性(或字段)具有类型LinkedHashMap或者存在单个Map,AbstractMap或HashMap属性(或字段)
  • ,则Groovy的常规地图样式命名约定将不可用   
     

来源:http://docs.groovy-lang.org/next/html/gapi/groovy/transform/TupleConstructor.html

根据这些信息,您可以尝试实现预期行为的方法是摆脱手写的构造函数,并使用@TupleConstructor代替层次结构中的所有类,例如。

import groovy.transform.TupleConstructor

@TupleConstructor
class A {
    String x
    String y
    String z
}

@TupleConstructor(callSuper = true, includeSuperProperties = true)
class B extends A {
}

@TupleConstructor(callSuper = true, includeSuperProperties = true)
class C extends B {
    String r
}

println new B("x1", "y1").x

println new C("x2", "y2", "r").r

编辑:如果修改类A不是一个选项,那么您可以通过遵循类层次结构来实现此目的:

import groovy.transform.TupleConstructor

class A {
    String x
    String y
    String z
    A() { }
    A(String a) { }
}

@TupleConstructor(includeSuperProperties = true)
class B extends A {
}

@TupleConstructor(callSuper = true, includeSuperProperties = true)
class C extends B {
    String r
}

println new C("x2", "y2", "z2", "r2").dump()

运行以下脚本将返回输出:

<C@670002 r=r2 x=x2 y=y2 z=z2>

这里发生的是:

  • 班级A未更改。
  • B为从A
  • 继承的所有字段添加构造函数
  • C添加了缺少构造函数,以满足字段r的初始化。

我希望它有所帮助。