添加自定义构造函数而不会丢失默认的地图构造函数

Dón*_*nal 11 groovy constructor

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

class Foo {
  def a
  def b
}

// this works
new Foo(a: '1', b: '2')
Run Code Online (Sandbox Code Playgroud)

但是,似乎只要添加自己的构造函数,此默认构造函数就不可用

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')
Run Code Online (Sandbox Code Playgroud)

是否可以添加自己的构造函数而不会丢失默认的地图构造函数?我尝试用类注释,@TupleConstructor但它没有任何区别.我意识到我可以自己添加地图构造函数,例如

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

虽然上面的构造函数与默认的映射构造函数不同,因为映射中没有类中相应属性的键将导致异常.

bdk*_*her 20

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

@groovy.transform.MapConstructor
class Foo {
    def a, b
    Foo(Integer x) {
        println 'my constructor was called'
    }
}

// this works
new Foo(1)

// the map constructor is present, too
def mappedFoo = new Foo(a: '1', b: '1')
assert mappedFoo.a == '1'
assert mappedFoo.b == '1'
Run Code Online (Sandbox Code Playgroud)

如果您使用的是旧版本的Groovy,那么@InheritConstructors 注释可以用作替代@MapConstructor,但正如Arie指出的那样,如果您的类扩展了一些基类,请避免使用此方法; 如果基类缺少无参数构造函数,则无效.


Wil*_*ill 10

在编译时,Groovy的地图构造函数使用空构造函数和一堆setter(以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"
Run Code Online (Sandbox Code Playgroud)


Dav*_*ton 5

添加一个无参数的ctor并调用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
Run Code Online (Sandbox Code Playgroud)