2013-08-09 46 views
10

Tôi tự hỏi nếu có bất kỳ cách nào để làm như sau. Tôi có một lớp trừu tượng, Shape, và tất cả các lớp con khác nhau của nó và tôi muốn ghi đè lên phương thức sao chép. Tất cả những gì tôi muốn làm trong phương thức này là tạo một Shape mới từ toString() của hiện tại. Rõ ràng tôi không thể làm như sau bởi vì Shape là trừu tượng. Có cách nào khác để làm điều này bởi vì bản sao ghi đè trong mọi phân lớp chỉ để thay đổi tên đơn giản có vẻ vô ích.Java nhân bản đối tượng trừu tượng

public abstract class Shape { 

    public Shape(String str) { 
     // Create object from string representation 
    } 

    public Shape clone() { 
     // Need new way to do this 
     return new Shape(this.toString()); 
    } 

    public String toString() { 
     // Correctly overriden toString() 
    } 
} 
+1

Sử dụng phản ánh? – johnchen902

Trả lời

5

Bạn có thể cố gắng sử dụng phản ánh:

public abstract class AClonable implements Cloneable{ 

private String val; 

public AClonable(){ 

} 

public AClonable(String s){ 
    val=s; 
} 

public String toString(){ 
    return val; 
} 

@Override 
public AClonable clone(){ 
    try { 
     System.out.println(getClass().getCanonicalName()); 
     AClonable b= getClass().getDeclaredConstructor(String.class).newInstance(val); 

     return b; 
    } catch (InstantiationException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IllegalArgumentException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (SecurityException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchMethodException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return null; 
} 

}

trong phương pháp clone() bạn gọi getClass(). Bởi vì các ACloneble ist trừu tượng, có cuộc gọi sẽ allways đi đến lớp bê tông.

public class ClonebaleOne extends AClonable{ 

public ClonebaleOne(){ 
    super(); 
} 

public ClonebaleOne(String s) { 
    super(s); 
    // TODO Auto-generated constructor stub 
} 

}

public class ClonebaleTwo extends AClonable{ 

public ClonebaleTwo(){ 
    super(); 
} 

public ClonebaleTwo(String s) { 
    super(s); 
    // TODO Auto-generated constructor stub 
} 

}

và cuối cùng

public static void main(String[] args){ 
    AClonable one = new ClonebaleOne("One"); 
    AClonable tow= new ClonebaleTwo("Two"); 
    AClonable clone = one.clone(); 
    System.out.println(clone.toString()); 
    clone = tow.clone(); 
    System.out.println(clone.toString()); 

} 

Output:

ClonebaleOne 
    One 
    ClonebaleTwo 
    Two 

Nhưng nó nhiều hơn một hack hơn là một giải pháp

[EDIT] hai máy nhái của tôi đã nhanh hơn;)

[EDIT] Để được hoàn tất. Một hàm ý khác của bản sao() có thể là

@Override 
public AClonable clone(){ 
    try { 
     ByteArrayOutputStream outByte = new ByteArrayOutputStream(); 
     ObjectOutputStream outObj = new ObjectOutputStream(outByte); 
     ByteArrayInputStream inByte; 
     ObjectInputStream inObject; 
     outObj.writeObject(this); 
     outObj.close(); 
     byte[] buffer = outByte.toByteArray(); 
     inByte = new ByteArrayInputStream(buffer); 
     inObject = new ObjectInputStream(inByte); 
     @SuppressWarnings("unchecked") 
     Object deepcopy = inObject.readObject(); 
     inObject.close(); 
     return (AClonable) deepcopy; 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

khi lớp trừu tượng của bạn triển khai Serialazable. Ở đó bạn viết đối tượng của bạn vào đĩa và tạo một bản sao với giá trị từ đĩa.

+0

Tôi thích ý tưởng của bạn và có lẽ nó sẽ có ích cho tôi trong tương lai, nhưng tôi nghĩ rằng tôi tốt hơn hết chỉ cần xác định bản sao cho mỗi phân lớp. Quá tệ không có cách nào đơn giản hơn để đạt được điều này. – negoose

+0

Để xác định chúng trong mỗi phân lớp là giải pháp tốt nhất trong cách định hướng đối tượng. Tôi đồng ý với sanbhat. Tôi lo sợ giải pháp Serialazable là giải pháp chậm nhất và nó cũng là một hack. –

2

Bạn không thể tạo bản sao sâu của abstract lớp vì họ không thể khởi tạo. Tất cả các bạn có thể làm là cạn nhân bản bằng cách sử dụng Object.clone() hoặc trở this

@Override 
public Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
} 

hoặc

@Override 
public Object clone() throws CloneNotSupportedException { 
    return this; 
} 

Một lớp trừu tượng có thể hoạt động như một tài liệu tham khảo, và nó không thể có một thể hiện nhân bản rất cạn làm việc tại trường hợp này

HOẶC

Cách tiếp cận tốt hơn, bạn có thể tuyên bố clone() như abstract và yêu cầu lớp trẻ để xác định nó, một cái gì đó như thế này

abstract class Shape { 

    private String str; 

    public Shape(String str) { 
     this.str = str; 
    } 

    public abstract Shape clone(); 

    public String toString() { 
     return str; 
    } 
} 

class Circle extends Shape { 

    public Circle(String str) { 
     super(str); 
    } 

    @Override 
    public Shape clone() { 
     return new Circle("circle"); 
    } 

} 
1

Mặc dù tôi nghi ngờ nó là một ý tưởng tốt, bạn có thể sử dụng phản ánh:

import java.lang.reflect.Constructor; 
import java.lang.reflect.InvocationTargetException; 

public class Test { 

    public static void main(String[] args) {   
     Square s1 = new Square("test"); 
     Square s2 = (Square) s1.clone(); 

     // show that s2 contains the same data 
     System.out.println(s2); 
     // show that s1 and s2 are really different objects 
     System.out.println(s1 == s2); 
    } 

    public static abstract class Shape { 
     private String str; 

     public Shape(String str) { 
      this.str = str; 
     } 

     public Shape clone() {   
      try { 
       Class<?> cl = this.getClass(); 
       Constructor<?> cons = cl.getConstructor(String.class); 
       return (Shape) cons.newInstance(this.toString());   
      } catch (NoSuchMethodException | SecurityException | 
        InstantiationException | IllegalAccessException | 
        IllegalArgumentException | InvocationTargetException e) { 
       e.printStackTrace(); 
      }   

      return null; 
     } 

     @Override 
     public String toString() { 
      return str; 
     } 
    } 

    public static class Square extends Shape { 
     public Square(String str) { 
      super(str); 
     } 
    } 
} 
1

Bạn có thể giải quyết với sự phản ánh:

public abstract class Shape { 

    private String str; 

    public Shape() { 

    } 

    protected Shape(String str) { 
     this.str = str; 
    } 

    public Shape clone() throws CloneNotSupportedException 
    { 
     try { 
      return (Shape)getClass().getDeclaredConstructor(String.class).newInstance(this.toString()); 
     } catch (Exception e) { 
      throw new CloneNotSupportedException(); 
     } 
    } 

    public String toString() { 
     return "shape"; 
    } 

public class Round extends Shape 
{ 
    public Round() 
    { 
     super(); 
    } 
    protected Round(String str) { 
     super(str); 
    } 

    @Override 
    public String toString() { 
     return "round"; 
    } 
} 

main(){ 
    Shape round = new Round();   
    Shape clone = round.clone(); 
    System.out.println(round); 
    System.out.println(clone); 
} 

nhưng - IMO - thực hiện kém và dễ bị lỗi với nhiều hố; việc sử dụng tốt nhất CloneableObject.clone() là không sử dụng chúng! Bạn có rất nhiều cách để làm điều tương tự (như serialization cho bản sao sâu) và bản sao nông cho phép bạn kiểm soát tốt hơn của dòng chảy.

Các vấn đề liên quan