4

I read Effective Java by J.Bloch and here was wrote:

If you design a class for inheritance, be aware that if you choose not to provide a well-behaved protected clone method, it will be impossible for subclasses to implement Cloneable.

I have Class A:

public class A{}

And class B which extends class A:

public class B extends A implements Cloneable {

}

So in this case I can't to override clone() method? If yes, than please explain why.

Vladyslav Sheruda
  • 1,856
  • 18
  • 26
  • Use copy constructor. – Everv0id May 06 '15 at 13:56
  • Yes, I understand that copy constructor is a better way to copy object ..thanks :) – Vladyslav Sheruda May 06 '15 at 14:00
  • For others: An alternative to the copy constructor is the [static newInstance()](http://www.javapractices.com/topic/TopicAction.do?Id=12) idiom. But I find this curious. Why not simply make your class its own factory and have a non-static `newInstance()` method? Seems cleaner than passing in an existing object as a parameter; just as the object for a copy of itself (without using the broken `clone()`). –  May 06 '15 at 14:14
  • In the past, I've had a customer who required both `shallowClone()` and `deepClone()` customized methods, as an avoidance to the java `clone()` nonsense. They wanted it entirely under their own control. Makes sense to me. –  May 06 '15 at 14:16
  • @tgm1024 so, in real life using clone() method in all cases is a bad idea? – Vladyslav Sheruda May 07 '15 at 07:52
  • @JamesSchermann, while some would say that, I'll just say it's a weird paradigm, and most consider it broken. I've used it before in the past, but it's considered problematic and I prefer the control gained from implementing my own copy. You may appreciate this [interesting interview on the subject with Josh Bloch, the author of *Effective Java*, the book you read](http://www.artima.com/intv/bloch13.html). But in my customer's case, they required both deep and shallow duplication functionality with specific requirements. –  May 07 '15 at 12:22
  • The statement by Bloch is manifestly incorrect. Possibly he is talking about deep-copying elsewhere in the context, but the sentence as quoted is simply false. – user207421 Nov 13 '17 at 23:39

3 Answers3

2

In your case yes you can override clone():

public class A {
}

public class B extends A implements Cloneable {

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

and still have an effective clone mechanism - you are therefore telling the truth when you state implements Cloneable.

However, all that is needed to break that promise is to give A a private variable.

public class A {
    private int a;
}

and now your promise is broken - unless A implements clone, in which case you can use super.clone():

public class A {

    private int a;

    @Override
    public A clone() throws CloneNotSupportedException {
        A newA = (A) super.clone();
        newA.a = a;
        return newA;
    }
}

public class B extends A implements Cloneable {

    private int b;

    @Override
    public B clone() throws CloneNotSupportedException {
        B newB = (B) super.clone();
        newB.b = b;
        return newB;
    }
}

Essentially - as Joshua Bloch states - if you don't implement clone your sub-classes also cannot (generally).

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
1

Cloneable and clone() are pretty much deprecated, so it doesn't matter anyway. However, since clone() is always supposed to call super.clone(), if a superclass implements it wrong, the subclass won't be able to fix it either.

It has nothing to do with not being able to override clone(), it just won't result in a correct implementation.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • 1
    Where exactly does your first statement (`Cloneable` is deprecated) come from? – Dominik Sandjaja May 06 '15 at 13:52
  • 1
    Plenty of discussion about it, [here's](http://stackoverflow.com/questions/709380/java-rationale-of-the-cloneable-interface) one place. Actually `Cloneable` isn't **deprecated**, it's **broken**. – Kayaman May 06 '15 at 14:00
  • 1
    Well, I totally agree about the "broken" part. I just thought that I had missed the deprecation part. – Dominik Sandjaja May 07 '15 at 05:33
  • @EJP I think the idea I was going for here was that if `A` doesn't call `super.clone()` (i.e. `Object.clone()`), then as `B` won't be able to call it either it will result in an incorrect implementation. However it seems the doc states that `By convention, the returned object should be obtained by calling super.clone()`, so I suppose it would just result in an *unconventional* implementation. – Kayaman Nov 14 '17 at 05:01
  • It seems to me that the sentence quoted from Bloch is just simply wrong as stated. Maybe there is some surroundings context that qualifies it. I don't have a copy, and the extracts I've seen from it frankly don't impress me. – user207421 Nov 14 '17 at 20:34
  • I looked into this. The quoted sentence is the final sentence in the entire section, and is completely unsupported by either argument or example, unless the entire section is intended to prove it, which it doesn't. – user207421 Nov 16 '17 at 03:12
0

Of course you can implement B.clone().

The problem which J. Bloch refers to is (IIRC), that without a good A.clone() method, the private fields within A can not be cloned properly in B. Simple example:

public class A {
  private String myText;
  public A (String myText) {
    this.myText = myText;
  }
  public String getExtendedText() {
    return "Hello something " + myText;
  }
}

public class B extends A implements Cloneable {
    private int someValue;
    // getter/setter

    public clone() {
        // how can you now provide a good clone with A.myText being cloned?
    }    
}
assylias
  • 321,522
  • 82
  • 660
  • 783
Dominik Sandjaja
  • 6,326
  • 6
  • 52
  • 77
  • `A.myText` and `B.someValue` will be cloned automatically by `Object.clone()`. `B.clone()` doesn't need to do anything beyond calling `super.clone()` in this instance. – user207421 Nov 13 '17 at 23:25