简体   繁体   中英

In Java, how super.clone() method “knows” which object has called it?

I'm really confusing with this (maybe it sounds strange to you, sorry about that). For example, if I have class A and override clone method and in body I have super.clone().. It calls clone() method from Object class, and my question is HOW clone method in Object class knows which object to clone.. Maybe I do not understand well super (I know when use this that you know to use current object of class).

All Java classes, if they do not define an explicit extends , extend Object . A call to super.clone() or really any call to super.someMethod() will call the implementation of that method one link up in the class hierarchy instead of calling the implementation of that method defined in the class.

Take for instance

public class A {
    public void someMethod(){
        System.out.println("A.someMethod()");
    }
}

and

public class B extens A {
    @Override
    public void someMethod(){
        super.someMethod(); //call the implementation of someMethod() as defined in A
        System.out.println("B.someMethod()");
    }
}

This:

new A().someMethod();

will print A.someMethod();

And this:

new B().someMethod();

Will print

A.someMethod()
B.someMethod()

EDIT 1

A slightly more complex example:

public class SuperTest {

    public static class A {

        public void someMethod() {
            System.out.println(
                    this.getClass().getSimpleName()+".someMethod()");
        }
    }

    public static class B extends A {

        @Override
        public void someMethod() {
            super.someMethod();
        }
    }

    public static void main(String[] args) {
        new B().someMethod();
    }
}

Will print B.someMethod()

super is used to call an implementation higher up the class hierarchy but it is still called on the object that is doing super call.


EDIT 2

As this pertains to clone() , which is in and of itself not great and should be avoided at all costs. You can read up on the reasons why all over the internet.

A canonical implementation of clone() really requires all classes in the class hierarchy of a Class to provide a canonical implementation of clone() . The implementation of clone() should start with a call to super.clone() because we expect that the parent class will do the cloning of all that class's members and assign them and return the object. Then the child class's clone() implementation should then copy its member fields and assign them to the clone.

We can see this happening in the expanded example

public class SuperCloneTest {

    public static class A implements Cloneable {

        private String member1;

        public A(String value) {
            this.member1 = value;
        }

        @Override
        public Object clone() {
            System.out.println("In A.clone()");
            System.out.printf("Class of `this` in A.clone(): %s\n", this.getClass().getSimpleName());
            A clone;
            try {
                clone = (A) super.clone();

                System.out.printf("Class of clone in A.clone(): %s\n", clone.getClass().getSimpleName());
                System.out.printf("Value of member1 in A.clone(): %s\n", this.member1);

                clone.member1 = this.member1;

                return clone;
            } catch (CloneNotSupportedException e) {
                //A implements Cloneable so we can be sure this won't happen
                throw new UnsupportedOperationException(e);
            }
        }
    }

    public static class B extends A {

        private String member2;

        public B(String value1, String value2) {
            super(value1);
            this.member2 = value2;
        }

        @Override
        public Object clone() {
            System.out.println("In B.clone()");
            System.out.printf("Class of `this` in B.clone(): %s\n", this.getClass().getSimpleName());

            B clone = (B) super.clone();
            System.out.printf("Class of clone in B.clone(): %s\n", clone.getClass().getSimpleName());
            System.out.printf("Value of member2 in B.clone(): %s\n", this.member2);

            clone.member2 = this.member2;

            return clone;
        }
    }

    public static class C extends B {

        private String member3;

        public C(String value1, String value2, String value3) {
            super(value1, value2);
            this.member3 = value3;
        }

        @Override
        public Object clone() {
            System.out.println("In C.clone()");
            System.out.printf("Class of `this` in C.clone(): %s\n", this.getClass().getSimpleName());

            C clone = (C) super.clone();
            System.out.printf("Class of clone in C.clone(): %s\n", clone.getClass().getSimpleName());
            System.out.printf("Value of member3 in C.clone(): %s\n", this.member3);

            clone.member3 = this.member3;

            return clone;
        }
    }

    public static void main(String[] args) {

        new C("value1", "value2", "value3").clone();
    }
}

And when we run it we get this:

In C.clone()
Class of `this` in C.clone(): C
In B.clone()
Class of `this` in B.clone(): C
In A.clone()
Class of `this` in A.clone(): C
Class of clone in A.clone(): C
Value of member1 in A.clone(): value1
Class of clone in B.clone(): C
Value of member2 in B.clone(): value2
Class of clone in C.clone(): C
Value of member3 in C.clone(): value3

Here we can see that this is always C and so is the clone. Going all the way up the stack and calling super.clone() in A calls Object.cone() which will allocate and object of the same type as this .

The clone method in Object is a default implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM