Java克隆抽象对象
我想知道是否有任何方法可以做到以下几点。 我有一个抽象类, Shape
,以及它的所有不同的子类,我想重写克隆方法。 我想在方法中做的就是从当前的toString()
创建一个新的Shape
。 显然我不能做以下因为Shape
是抽象的。 还有另一种方法可以做到这一点,因为在每个子类中重写克隆只是为了简单的名称更改似乎没用。
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() } }
您可以尝试使用reflection:
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; }
}
在clone()方法中,您调用getClass()。 因为ACloneble是抽象的,所以调用将总是进入具体类。
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 }
}
最后
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()); }
输出:
ClonebaleOne One ClonebaleTwo Two
但它更像是一个黑客而不是一个解决方案
[编辑]我的两个克隆比…更快
[编辑]完成。 clone()的另一个实现可以是
@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; }
当您的抽象类实现Serialazable时。 在那里,您将对象写入光盘并使用光盘中的值创建副本。
您无法创建abstract
类的深层克隆 ,因为它们无法实例化 。 您可以通过使用Object.clone()
或返回this
来进行浅层克隆
@Override public Object clone() throws CloneNotSupportedException { return super.clone(); }
要么
@Override public Object clone() throws CloneNotSupportedException { return this; }
抽象类可以作为引用,它不能有一个实例,所以在这种情况下浅克隆工作
要么
作为一种更好的方法,您可以将clone()
声明为abstract
并让子类定义它,就像这样
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"); } }
虽然我怀疑它是个好主意,但你可以使用reflection:
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); } } }
你可以用reflection来解决:
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); }
但是 – IMO – 实施效果差,容易出错,有很多坑; Cloneable
和Object.clone()
的最佳用法是不使用它们! 你有很多方法可以做同样的事情(如深度克隆的序列化)和浅克隆,可以更好地控制流量。
- Java FileHandler禁用日志轮换
- Object.isArray()很慢,有没有快速的方法呢?
- 将二进制字符串转换为hex字符串JAVA
- 获取对Java的默认http(s)URLStreamHandler的引用
- java.sql.SQLException:侦听器拒绝连接时出现以下错误:ORA-12519,TNS:找不到合适的服务处理程序
- 为什么hibernate强制在session.get方法中进行序列化
- Javaexception处理 – 样式
- Java MongoDB:com.mongodb.DB和com.mongodb.client之间有什么区别
- 请求调度程序转发和servlet链接之间的区别