From: Lethal Possum on 16 Feb 2010 06:34 Hello everyone, Let's say I have a class B that extends a class A. Now I have an instance of B and I need to "clone" it but only as an instance of A, not B. I can't just cast my instance of B into A, I need a new instance of A, and only A. I need that the new object's getClass() method to return A.class. Is there an easy way to do this? I'd prefer not to copy each field one by one as there is many of them and maintenance would be difficult (i.e. how do I make sure someone adding a field to class A will update my method accordingly). I know I could probably achieve this by reflection, iterating on every field of class A, but some fields of A need to be copied in a specific way. This is already done properly by the clone() method of A so I would really like to leverage that code. I am not sure my problem is very clear so I wrote a short piece of code to demonstrate it. I also included all the solution that I already know not to work: == Start of code == public class A implements Cloneable { private boolean _copy = false; public boolean isCopy() { return _copy; } public Object clone() throws CloneNotSupportedException { A a = (A)super.clone(); a._cloned = true; return a; } } public class B extends A { public A test1() throws Exception { A a = (A)this; return (A)a.clone(); } public A test2() throws Exception { A a = (A)clone(); return a; } public A test3() throws Exception { A a = (A)super.clone(); return a; } public A test4() throws Exception { A a = (A)clone(); return (A)a.clone(); } } public class test { public static void main (String[] args) throws Exception { B b = new B(); A a1 = b.test1(); System.out.println(a1.getClass().toString() + " copy=" + a1.isCopy()); A a2 = b.test2(); System.out.println(a2.getClass().toString() + " copy=" + a2.isCopy()); A a3 = b.test3(); System.out.println(a3.getClass().toString() + " copy=" + a3.isCopy()); A a4 = b.test4(); System.out.println(a4.getClass().toString() + " copy=" + a4.isCopy()); } } == End of code == All that I get is: class B copy=true When I would like to get: class A copy=true Any idea? Thanks, Tom
From: Lethal Possum on 16 Feb 2010 06:36 On 16 fév, 12:34, Lethal Possum <lethal.pos...(a)gmail.com> wrote: > Hello everyone, > > Let's say I have a class B that extends a class A. Now I have an > instance of B and I need to "clone" it but only as an instance of A, > not B. I can't just cast my instance of B into A, I need a new > instance of A, and only A. I need that the new object's getClass() > method to return A.class. > > Is there an easy way to do this? I'd prefer not to copy each field one > by one as there is many of them and maintenance would be difficult > (i.e. how do I make sure someone adding a field to class A will update > my method accordingly). > > I know I could probably achieve this by reflection, iterating on every > field of class A, but some fields of A need to be copied in a specific > way. This is already done properly by the clone() method of A so I > would really like to leverage that code. > > I am not sure my problem is very clear so I wrote a short piece of > code to demonstrate it. I also included all the solution that I > already know not to work: > > == Start of code == > > public class A implements Cloneable { > > private boolean _copy = false; > > public boolean isCopy() { > return _copy; > } > > public Object clone() throws CloneNotSupportedException { > A a = (A)super.clone(); > a._cloned = true; > return a; > } > > } > > public class B extends A { > > public A test1() throws Exception { > A a = (A)this; > return (A)a.clone(); > } > > public A test2() throws Exception { > A a = (A)clone(); > return a; > } > > public A test3() throws Exception { > A a = (A)super.clone(); > return a; > } > > public A test4() throws Exception { > A a = (A)clone(); > return (A)a.clone(); > } > > } > > public class test { > > public static void main (String[] args) throws Exception { > B b = new B(); > A a1 = b.test1(); > System.out.println(a1.getClass().toString() + " copy=" + > a1.isCopy()); > A a2 = b.test2(); > System.out.println(a2.getClass().toString() + " copy=" + > a2.isCopy()); > A a3 = b.test3(); > System.out.println(a3.getClass().toString() + " copy=" + > a3.isCopy()); > A a4 = b.test4(); > System.out.println(a4.getClass().toString() + " copy=" + > a4.isCopy()); > } > > } > > == End of code == > > All that I get is: > > class B copy=true > > When I would like to get: > > class A copy=true > > Any idea? > > Thanks, > > Tom I just noticed a typo in my code, "a._cloned = true;" should be "a._copy = true;". Sorry, Tom
From: Lew on 16 Feb 2010 11:26 Lethal Possum wrote: >> Let's say I have a class B that extends a class A. Now I have an >> instance of B and I need to "clone" it but only as an instance of A, >> not B. I can't just cast my instance of B into A, I need a new >> instance of A, and only A. I need that the new object's getClass() >> method to return A.class. >> >> Is there an easy way to do this? I'd prefer not to copy each field one >> by one as there is many of them and maintenance would be difficult >> (i.e. how do I make sure someone adding a field to class A will update >> my method accordingly). >> >> I know I could probably achieve this by reflection, iterating on every >> field of class A, but some fields of A need to be copied in a specific >> way. This is already done properly by the clone() method of A so I >> would really like to leverage that code. >> >> I am not sure my problem is very clear so I wrote a short piece of >> code to demonstrate it. I also included all the solution that I >> already know not to work: >> >> == Start of code == >> >> public class A implements Cloneable { >> >> private boolean _copy = false; The Java naming conventions call for no underscore in this variable name. It initializes to 'false', then you set it to 'false'. This is redundant but some consider it useful for internal documentation and don't mind the extra assignment of 'false'. >> public boolean isCopy() { >> return _copy; >> } >> >> public Object clone() throws CloneNotSupportedException { >> A a = (A)super.clone(); >> a._cloned = true; >> return a; >> } >> >> } >> >> I just noticed a typo in my code, "a._cloned = true;" should be >> "a._copy = true;". >> >> public class B extends A { >> >> public A test1() throws Exception { >> A a = (A)this; Upcasts are superfluous. 'this' already /is-an/ 'A', and doesn't lose its 'B'-ness by having an 'A' pointer reference it. >> return (A)a.clone(); >> } >> >> public A test2() throws Exception { >> A a = (A)clone(); Same remark - upcasts are superfluous. >> return a; >> } >> >> public A test3() throws Exception { >> A a = (A)super.clone(); Once again the cast is superfluous. It does nothing to upcast an instance to a type that it already is. This fails for the same reason that the call to 'super.clone()' in 'A' succeeds. From the Javadocs for 'clone()' (which surely you have read while researching this question - right?): > this method creates a new instance of the class of this object Since the class of this object is 'B', the cloned instance is a 'B'. You can't very well rely on this behavior in 'A' and simultaneously wish it wouldn't work that way in 'B'. >> return a; >> } >> >> public A test4() throws Exception { >> A a = (A)clone(); >> return (A)a.clone(); Not only is the upcast superfluous, and not only does 'a' continue to point to a 'B' instance (casts don't change the runtime type of an object), but now you've created two instances of 'B' and thrown one away. >> } >> >> } >> >> public class test { >> >> public static void main (String[] args) throws Exception { >> B b = new B(); >> A a1 = b.test1(); >> System.out.println(a1.getClass().toString() + " copy=" + >> a1.isCopy()); >> A a2 = b.test2(); >> System.out.println(a2.getClass().toString() + " copy=" + >> a2.isCopy()); >> A a3 = b.test3(); >> System.out.println(a3.getClass().toString() + " copy=" + >> a3.isCopy()); >> A a4 = b.test4(); >> System.out.println(a4.getClass().toString() + " copy=" + >> a4.isCopy()); >> } >> >> } >> >> == End of code == >> >> All that I get is: >> >> class B copy=true Not possible. You have four 'println()' calls. You must have gotten four lines of output. >> When I would like to get: >> >> class A copy=true The presence of the '_copy' variable (whose name violates the naming conventions, btw) is against the spirit of 'clone()', but never mind. As the Javadocs say, for the clone to be value-equal "is not an absolute requirement." 'clone()' is the wrong method for what you are asking. It is designed to return an instance of the cloned object's class. You are trying to violate that contract. Create your own method in 'A' to make a copy that instantiates its own 'A' instance and copies over the desired state without using 'clone()'. -- Lew
From: markspace on 16 Feb 2010 13:16 Lethal Possum wrote: > Hello everyone, > > Let's say I have a class B that extends a class A. Now I have an > instance of B and I need to "clone" it but only as an instance of A, > not B. I can't just cast my instance of B into A, I need a new > instance of A, and only A. I need that the new object's getClass() > method to return A.class. I'm not sure what you're trying to do. Is there a way you can be more specific with your actual example? This one is pretty hypothetical. Here's my hypothetical thought: package test; public class CloneTest implements Cloneable { public static void main( String[] args ) { CloneChild b = new CloneChild(); CloneTest a = b.clone(); System.out.println( a ); } @Override public final CloneTest clone() { try { return (CloneTest) super.clone(); }catch( CloneNotSupportedException ex ) { // Cannot get here throw new AssertionError( ex ); } } } class CloneChild extends CloneTest { }
From: Thomas Pornin on 16 Feb 2010 14:09 According to Lethal Possum <lethal.possum(a)gmail.com>: > Is there an easy way to do this? Generally speaking, no. In Java, the implementation of a class is the guardian of what can be part of an instance of that class. To get an instance of A you have to go through a constructor of A. If A does not override clone(), then calling super.clone() from an instance of B will fallback on Object.clone(), which will build a new instance of B, not a new instance of A. Basically, to get what you want, you will need a bit of cooperation from class A. If class A cooperates (i.e. you are developing the source code of A as well), then the simplest way seems to add a A.dup() method which returns a new instance of A (created with an explicit 'new A()') and manually filled with the proper data. Otherwise, you could probably try to abuse serialisation (serialise your instance of B into some bytes, and cut&glue it into a proper serialisation for A) but this is hardly "easy" and I guess that there are a huge number of pesky details to take into account. --Thomas Pornin
|
Next
|
Last
Pages: 1 2 Prev: Capture image from webcam in java Next: Oracle insert current date and time |