Groovy 在不丢失默认映射构造函数的情况下添加自定义构造函数

Groovy 在不丢失默认映射构造函数的情况下添加自定义构造函数,groovy,constructor,Groovy,Constructor,默认情况下,每个Groovy类都有一个映射构造函数,例如 class Foo { def a def b } // this works new Foo(a: '1', b: '2') 但是,似乎只要添加自己的构造函数,这个默认构造函数就不可用 class Foo { Foo(Integer x) { println 'my constructor was called' } def a def b } // this works new Foo(1

默认情况下,每个Groovy类都有一个映射构造函数,例如

class Foo {
  def a
  def b
}

// this works
new Foo(a: '1', b: '2')
但是,似乎只要添加自己的构造函数,这个默认构造函数就不可用

class Foo {

  Foo(Integer x) {
    println 'my constructor was called'  
  }

  def a
  def b
}

// this works
new Foo(1)

// now this doesn't work, I get the error: groovy.lang.GroovyRuntimeException: 
// failed to invoke constructor
new Foo(a: '1', b: '2')
是否可以在不丢失默认映射构造函数的情况下添加自己的构造函数?我尝试使用
@TupleConstructor
注释该类,但没有任何区别。我意识到我可以自己添加地图构造器,例如

public Foo(Map map) {    
  map?.each { k, v -> this[k] = v }  
}

尽管上面的构造函数与默认的map构造函数不同,因为map中的键在类中没有相应的属性将导致异常。

如果您使用的是Groovy 2.5或更高版本,则可以应用
@MapConstructor


如果您使用的是较旧版本的Groovy,
@inheritarconstructor
可以用作
@MapConstructor
的替代品,但正如Arie所指出的,如果您的类扩展了一些基类,请避免使用这种方法;如果基类缺少no-arg构造函数,这将不起作用。

编译后,Groovy的映射构造函数将被转换为(javabean样式的)。使用空构造函数可以解决此问题:

class Foo {

  Foo(Integer x) {
    println 'my constructor was called'  
  }

  Foo() {}

  def a
  def b
}

new Foo(1)

foo = new Foo(a: '1', b: '2')

assert foo.a == "1"

添加一个无参数选择器并调用
super
,例如

class Foo {
  Foo(Integer x) {
    println 'my constructor was called'  
  }

  Foo() { super() } // Or just Foo() {}

  def a
  def b
}

f = new Foo(a: '1', b: '2')
println f.a
=> 1

这很可能是一个更干净的选项。这是因为
Foo
从基
对象
类继承了默认的无参数构造函数。如果基类没有arg构造函数,它将崩溃;如果基类有多个重载构造函数,它将污染构造函数空间@威尔的答案是正确的。
class Foo {
  Foo(Integer x) {
    println 'my constructor was called'  
  }

  Foo() { super() } // Or just Foo() {}

  def a
  def b
}

f = new Foo(a: '1', b: '2')
println f.a
=> 1