Getting Clone of Superclass

Java cloning with super and sub classes

super.clone() return a object of Vehicle type, not Truck.
So you should call super(x) in constructor of Truck.

public class Truck extends Vehicle 
{
private int y;

public Truck(int x, int y) {
super(x);
this.y = y;
}

@Override public Object clone() {
Object result = new Truck(this.x, this.y);
return result;
}
}

Getting clone of superclass

You mean subclass. Box is the superclass, which is what you're returning.

This is very similar to the following:

  • Protocol func returning Self
  • Swift protocol and return types on global functions

It's not exactly the same question, though, since you're dealing with classes rather than protocols, so we can go through that example. First, the right tool is init, not a clone:

class Box {
let a: String
init(_ a: String) { self.a = a }
convenience init(copy: Box) { self.init(copy.a) }
}

class VBox:Box {}

let vb = VBox("test")
let cBox = VBox(copy: vb)

You see that this works fine since VBox adds no additional properties. But if VBox does add additional properties, then you'll get all the right errors that require you to implement an init.

class Box {
let a: String
init(_ a: String) { self.a = a }
convenience init(copy: Box) { self.init(copy.a) }
}

class VBox:Box {
let b: String
init(_ a: String, _ b: String) {
self.b = b
super.init(a)
}
convenience init(copy: VBox) {
self.init(copy.a, copy.b)
}
}

let vb = VBox("test", "this")
let cBox = VBox(copy: vb)

Note how this prevents you from trying to copy a Box into a VBox (since that would not initialize all the parameters). If you want that to work, you'd need to provide a copy(Box) initializer. This is the nice thing about using init. It keeps track of all the rules for you. NSCopying would let you make that mistake and would eventually crash.

Java: super.clone() method and inheritance

It sounds like there are at least two problems at work here:

  1. It sounds like you're confused about how clone() normally gets implemented.

  2. It sounds like you're thinking that cloning is a good idea (vs. using a copy constructor, factories or their equivalent).

Here is an example of an implementation of a clone method:

@Override 
public Object clone() throws CloneNotSupportedException {
//get initial bit-by-bit copy, which handles all immutable fields
Fruit result = (Fruit)super.clone();

//mutable fields need to be made independent of this object, for reasons
//similar to those for defensive copies - to prevent unwanted access to
//this object's internal state
result.fBestBeforeDate = new Date( this.fBestBeforeDate.getTime() );

return result;
}

Note that the result of super.clone() is immediately cast to a Fruit. That allows the inheriting method to then modify the Fruit-specific member data (fBestBeforeDate in this case).

Thus, the call to a child clone() method, while it will call the parents' clones, also adds its own specific modifications to the newly made copy. What comes out, in this case, will be a Fruit, not an Object.

Now, more importantly, cloning is a bad idea. Copy constructors and factories provide much more intuitive and easily maintained alternatives. Try reading the header on the Java Practices link that I attached to the example: that summarizes some of the problems. Josh Bloch also has a much longer discussion: cloning should definitely be avoided. Here is an excellent summary paragraph on why he thinks cloning is a problem:

Object's clone method is very tricky. It's based on field copies, and
it's "extra-linguistic." It creates an object without calling a
constructor. There are no guarantees that it preserves the invariants
established by the constructors. There have been lots of bugs over the
years, both in and outside Sun, stemming from the fact that if you
just call super.clone repeatedly up the chain until you have cloned an
object, you have a shallow copy of the object. The clone generally
shares state with the object being cloned. If that state is mutable,
you don't have two independent objects. If you modify one, the other
changes as well. And all of a sudden, you get random behavior.

Scala: How can I implement a clone method on a superclass, and use it in a subclass?

Assuming you want to minimize amount of ceremony in the subclasses, here is my suggestion:

class A extends Cloneable {
protected[this] def myCloneImpl[T] = {
val justLikeMe = this.clone
// copy values and such.
// Note that the Object.clone method already made a shallow copy, but you may want
// to deepen the copy or do other operations.
justLikeMe.asInstanceOf[T]
}
def myClone = myCloneImpl[A]
}

class B extends A {
override def myClone = myCloneImpl[B]
}

By extending java.lang.Cloneable and calling the Object.clone method, you ensure that your runtime type is the same as the object being cloned. The static type is coerced with a type-cast (asInstanceOf[T]). You will need to override the myClone method in each subclass and specify the type, but it should be a one-liner.

Overriding Clone() method in Java when superclass is not Clonable

If you have this structure:

class Y {}

class X extends Y implements Cloneable {
@Override
public X clone() {
try {
return (X) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
}

Then clone on instances of X will work fine.
It won't work on direct instances of Y, because they are not declared cloneable. But the Cloneable interface on X is an indicator to the mechanisms of the default clone() implementation that they should be made to work.

Alternatively

You could also have a non-Cloneable class with a working clone() method, as long as you didn't rely on the default implementation of clone().

For instance:

class Y {
@Override
public Y clone() {
// Don't call super.clone() because it will error
return new Y(...); // whatever parameters
}
}

However, with this mechanism, if you called super.clone() from a subclass of Y, you would get an instance of Y, which is probably not what you would want.

As others have pointed out, the Cloneable mechanism is awkward and confusing, and usually copying mechanisms using new are easier to work with.

Copying values from Superclass to Subclass

You can use SubOne as a wrapper instead as a child.

class SubOne {

private SuperOne superOne;

public SubOne(SuperOne) {
this.superOne = superOne;
}

public String getId() {
return this.superOne.getId();
}

public String getName() {
return this.superOne.getName();
}

public String setId(String id) {
return this.superOne.setId(id);
}

public String setName(String name) {
return this.superOne.setName(name);
}

///////////////

public SubOne getData(String id){
SuperOne data = someDao.getData(String id)
return new SubOne(data);
}

Addendum

If you insist on inherit SuperOne you can do it like this.

class SubOne extends SuperOne {

public SubOne(SuperOne superOne) {
super.setId(superOne.getId());
super.setName(superOne.getName());
}


Related Topics



Leave a reply



Submit