2013-06-25 37 views
13

Điều này có thể đã được hỏi một triệu lần trước, nhưng tôi đang gặp rắc rối khi gói đầu của tôi xung quanh viết một constructor sao chép vào một lớp trừu tượng với một tham số kiểu bounded. Tôi có một số mã mà trông như thế này:Java Copy constructors với generics

public abstract class Superclass<T> { 
    Set<? extends Variable<T>> vars; 

    public abstract Superclass<? extends T> copy(); 

    class Variable<T> { 
     T value; 
    } 
} 

class Foo extends Superclass<Integer> { 
    public Foo copy() { 
     Foo _newFoo = Foo(); 
     Set<FooVariable> _newVars = new HashSet<FooVariable>(); 
     _newVars.addAll(this.vars); 
     _newFoo.vars = _newVars; 
    } 

    class FooVariable extends Variable<Integer> { /* ... */ } 
} 

class Bar extends Superclass<String> { 
    public Bar copy() { 
     Bar _newBar = Bar(); 
     Set<BarVariable> _newVars = new HashSet<BarVariable>(); 
     _newVars.addAll(this.vars); 
     _newBar.vars = _newVars; 
    } 

    class BarVariable extends Variable<String> { /* ... */ } 
} 

Kể từ khi phương pháp copy cho cả FooBar là như nhau, ngoại trừ cho các loại biến, tôi muốn để có thể di chuyển mã đó vào một phương pháp cụ thể trong siêu lớp. Nhưng tôi không thể tìm ra (a) làm thế nào để có bê tông public Superclass<? extends T> copy phương pháp trở về một trường hợp Foo nếu kêu gọi một Foo và một trường hợp Bar nếu kêu gọi một Bar và (b) cư tập vars với FooVariable s hoặc BarVariable s như thích hợp.

Ai có thể vui lòng giúp đỡ và cho tôi biết những gì tôi đang bỏ lỡ không? Cảm ơn.

+2

Một hàm tạo bản sao là một hàm tạo thực tế chấp nhận một cá thể của lớp làm đối số. Đây là một phương pháp sao chép. –

+0

wont này cung cấp cho biên dịch lỗi trên các 'Foo _newFoo = Foo();' và những gì về các loại trả về mất tích? Hoặc tôi hoàn toàn hiểu sai một số khái niệm – exexzian

Trả lời

0

Giới thiệu thông số loại chung thứ hai để đại diện cho Variable<T>, U.

Sau đó, Foo.FooVariable<T>Bar.BarVariable<T> thỏa mãn các giới hạn của U và có thể được trả về từ phương pháp copy.

EDIT

Tôi đã thay đổi mã để di chuyển thi hành copy vào lớp cha. Nó dựa trên phương thức newInstance (được giới thiệu bởi @OndrejBozek).

public abstract class Superclass<T, U extends Variable<T>> { 
    Set<U> vars; 

    class Variable<T> { 
     T value; 
    } 

    public Superclass<T, U> copy() { 
     Superclass<T, U> _newSuperclass = newInstance(); 
     Set<U> _newVars = new HashSet<U>(); 
     _newVars.addAll(vars); 
     _newSuperclass.vars = _newVars; 
     return _newSuperclass; 
    } 

    public abstract Superclass<T, U> newInstance(); 
} 

class Foo extends Superclass<Integer, Foo.FooVariable> { 
    public Foo newInstance() { return new Foo(); } 

    class FooVariable extends Variable<Integer> { /* ... */ } 
} 

class Bar extends Superclass<String, Bar.BarVariable> { 
    public Bar newInstance() { return new Bar(); } 

    class BarVariable extends Variable<String> { /* ... */ } 
} 
+0

Cảm ơn sự giúp đỡ của bạn. Mặc dù giải pháp này không gây ra sự an toàn kiểu mà tôi quan tâm, nhưng tôi vẫn sao chép khá nhiều mã trong các phương thức 'Foo.copy' và' Bar.copy'. Bạn có thể nghĩ ra một cách để di chuyển tất cả mã đó vào trong siêu lớp không? – jay

+0

@ jay, tôi đã sửa đổi câu trả lời của tôi trong một nỗ lực để di chuyển 'copy' vào lớp cha. – rgettman

2

Còn loại Superclass thì sao?

public abstract class Superclass<T> { 

    Set<? extends Variable<T>> vars; 

    public Superclass<? extends T> copy() { 
     Superclass<T> _newSuperclass = this.getNewInstance(); 
     Set<Variable<T>> _newVars = new HashSet<Variable<T>>(); 
     _newVars.addAll(this.vars); 
     _newSuperclass.vars = _newVars; 
     return _newSuperclass; 
    } 

    public abstract Superclass<T> getNewInstance(); 

    class Variable<T> { 

     T value; 
    } 
} 

Vấn đề là bạn chỉ cần thực hiện getNewInstance() trong lớp con thay vì constructor.

Vì vậy Foo sẽ trông giống như:

class Foo extends Superclass<Integer> { 

    @Override 
    public Superclass<Integer> getNewInstance() { 
     return new Foo(); 
    } 

    class FooVariable extends Variable<Integer> { /* ... */ } 
} 
+0

Có nó biên dịch. Chỉ cần biên dịch nó với Java 1.7. Điều gì nên sai về mã đó? –

+1

Xin lỗi, tôi đã suy nghĩ sai ... – jlordo

+0

Tôi nghĩ rằng bạn đang thiếu '_newSuperClass.vars = _newVars;' – Alex

0

Tested mã này, nó có một vài cảnh báo, nhưng nó làm những gì bạn muốn:

public <C extends Superclass<? extends T>> C copy() throws InstantiationException, IllegalAccessException { 
    C result= (C) this.getClass().newInstance(); 
    HashSet newVars= new HashSet(); 
    newVars.addAll(this.vars); 
    result.vars= newVars; 
    return result; 
} 

Một nhận xét: đây không phải là một copy constructor. Đây chỉ là một phương pháp sao chép. Constructor không có kiểu trả về và tên của nó tương đương với tên lớp.