2014-10-14 22 views
10

Theo mặc định, mỗi lớp Groovy có một hàm tạo Bản đồ, ví dụ:thêm một hàm tạo tùy chỉnh mà không làm mất hàm tạo bản đồ mặc định

class Foo { 
    def a 
    def b 
} 

// this works 
new Foo(a: '1', b: '2') 

Tuy nhiên, có vẻ như rằng ngay sau khi bạn thêm một constructor của riêng bạn, constructor mặc định này không có sẵn

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') 

Có thể thêm constructor của riêng bạn mà không làm mất bản đồ mặc định constructor? Tôi đã thử chú thích lớp học với @TupleConstructor nhưng nó không có sự khác biệt. Tôi nhận ra rằng tôi có thể tự thêm bản dựng của bản đồ, ví dụ:

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

Mặc dù hàm khởi tạo ở trên không giống với hàm tạo bản đồ mặc định vì một khóa trong bản đồ không có thuộc tính tương ứng trong lớp sẽ gây ra ngoại lệ.

Trả lời

18

Bạn có thể sử dụng chú thích @InheritConstructors.

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

// this works 
new Foo(1) 

def mappedFoo = new Foo(a: '1', b: '1') 
assert mappedFoo.a == '1' 
assert mappedFoo.b == '1' 
+0

Đây là khả năng tùy chọn sạch hơn. –

+0

Điều này xảy ra để làm việc bởi vì 'Foo' thừa hưởng constructor no-arg mặc định từ lớp' Object' cơ bản. Nó sẽ phá vỡ nếu lớp cơ sở không có hàm tạo không có arg, và nó sẽ gây ô nhiễm không gian của hàm tạo nếu lớp cơ sở có nhiều hàm khởi tạo bị quá tải. @ Will của câu trả lời là đúng cách để đi. –

7

Khi biên dịch, bản đồ của Groovy được dịch sang object creation using an empty constructor plus a bunch of setters (theo kiểu javabean). Có một constructor rỗng giải quyết vấn đề này:

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" 
4

Thêm một không-arg ctor và gọi super, ví dụ,

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 
Các vấn đề liên quan