22

What is a copy constructor?

Can someone share a small example that can be helpful to understand along with defensive copying principle?

catch23
  • 17,519
  • 42
  • 144
  • 217
user2094103
  • 685
  • 3
  • 7
  • 14

5 Answers5

24

Here's a good example:

class Point {
  final int x;
  final int y;

  Point(int x, int y) {
    this.x = x;
    this.y = y;
  }

  Point(Point p) {
    this(p.x, p.y);
  }

}

Note how the constructor Point(Point p) takes a Point and makes a copy of it - that's a copy constructor.

This is a defensive copy because the original Point is protected from change by taking a copy of it.

So now:

// A simple point.
Point p1 = new Point(3,42);
// A new point at the same place as p1 but a completely different object.
Point p2 = new Point(p1);

Note that this is not necessarily the correct way of creating objects. It is, however, a good way of creating objects that ensures that you never have two references to the same object by accident. Clearly this is only a good thing if that is what you want to achieve.

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

Copy constructors one often sees in C++ where they are needed for partly hidden, automatically invoked operations.

java java.awt.Point and Rectangle come to mind; also very old, mutable objects.

By using immutable objects, like String, or BigDecimal, simply assigning the object reference will do. In fact, due to the early phase of Java after C++, there still is a silly copy constructor in String:

public class Recipe {
    List<Ingredient> ingredients;

    public Recipe() {
        ingredients = new ArrayList<Ingredient>();
    }

    /** Copy constructor */
    public Recipe(Recipe other) {
        // Not sharing: ingredients = other.ingredients;
        ingredients = new ArrayList<>(other.ingredients);
    }

    public List<Ingredient> getIngredients() {
        // Defensive copy, so others cannot change this instance.
        return new ArrayList<Ingredient>(ingredients);
        // Often could do:
        // return Collections.immutableList(ingredients);
    }
}

On request

Leaking class with copy constructor:

public class Wrong {
    private final List<String> list;

    public Wrong(List<String> list) {
        this.list = list; // Error: now shares list object with caller.
    }

    /** Copy constructor */
    public Wrong(Wrong wrong) {
        this.list = wrong.list; // Error: now shares list object with caller.
    }

    public List<String> getList() {
        return list; // Error: now shares list object with caller.
    }

    public void clear() {
        list.clear();
    }
}

Correct class with copy constructor:

public class Right {
    private final List<String> list;

    public Right(List<String> list) {
        this.list = new ArrayList<>(list);
    }

    public Right(Right right) {
        this.list = new ArrayList<>(right.list);
    }

    public List<String> getList() {
        return new ArrayList<>(list);
    }

    public List<String> getListForReading() {
        return Collections.unmodifiableList(list);
    }

    public void clear() {
        list.clear();
    }
}

With testing code:

public static void main(String[] args) {
    List<String> list1 = new ArrayList<>();
    Collections.addAll(list1, "a", "b", "c", "d", "e");
    Wrong w1 = new Wrong(list1);
    list1.remove(0);
    System.out.printf("The first element of w1 is %s.%n", w1.getList().get(0)); // "b"
    Wrong w2 = new Wrong(w1);
    w2.clear();
    System.out.printf("Size of list1 %d, w1 %d, w2 %d.%n",
        list1.size(), w1.getList().size(), w2.getList().size());

    List<String> list2 = new ArrayList<>();
    Collections.addAll(list2, "a", "b", "c", "d", "e");
    Right r1 = new Right(list2);
    list2.remove(0);
    System.out.printf("The first element of r1 is %s.%n", r1.getList().get(0)); // "a"
    Right r2 = new Right(r1);
    r2.clear();
    System.out.printf("Size of list2 %d, r1 %d, r2 %d.%n",
        list2.size(), r1.getList().size(), r2.getList().size());
}

Which gives:

The first element of w1 is b.
Size of list1 0, w1 0, w2 0.
The first element of r1 is a.
Size of list2 4, r1 5, r2 0.
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • How will assigning the object reference for an immutable object produce a copy? Won't you just end up with two references to the same object? – darrenmc Feb 20 '15 at 12:21
  • @darrenmc here the recipes will be copies in the following sence: the lists of ingredients are separate instances. Every Ingredient however is shared. If Ingredient is an immutable object. like cabbage, then fine. If Ingredient is Recipe specific, say with quantity, then one would need to copy every Ingredient too. In my answer I wanted to stay at the top level, the field `ingredients`. – Joop Eggen Feb 20 '15 at 13:08
  • 1
    Beware, `BigDecimal` is not actually immutable. See https://stackoverflow.com/a/12600683/14731 – Gili Feb 20 '18 at 05:36
  • @Gili yes as BigDecimal is not final, a BigDecimal could actually be a mutable subclass. Fortunately all BigDecimal fields are private, so using a BigDecimal constructor is unproblematic. With BigInteger - that might be used for cryptography - one might imagine some exploit. – Joop Eggen Feb 20 '18 at 08:22
  • @JoopEggen The fact that all fields are private does not make the class immutable. A malicious sub-class can use reflection to read their values. Even without access to the fields, it could return incorrect results or snoop on the application's interaction with the object. – Gili Feb 21 '18 at 16:53
  • 1
    @Gili though with BigDecimal the API has an immutable behaviour of itself, so a child class has a hard time messing up the base object. Of course it could mallciously reimplement all and reflection is always a possibility. I do agree with you. But so is the final class String. And not to forget byte code manipulation, AOP and such. – Joop Eggen Feb 22 '18 at 08:24
  • @JoopEggen Could you modify and demonstrate the above Copy Constructor scenarios through a Java's main method for better understanding ? – deepakl.2000 Oct 23 '21 at 19:15
  • @deepakl.2000 I am on my smart phone now, and defensive copying (for containers, lists) means just one object holds the list, others should not be allowed to alter it. For this at most a copy of the list is given out. And on receiving a list in the constructor: make a copy, so the original owner that passed the list may not alter it as when it would be your class member. – Joop Eggen Oct 23 '21 at 19:31
  • Fundamental is javas pass-by-value. A list object is just a value: its "address", which is passed around. So assignment causes sharing an object (address). – Joop Eggen Oct 23 '21 at 19:36
  • @JoopEggen If you can provide the workable code, it would be great – deepakl.2000 Oct 24 '21 at 06:36
  • 1
    @deepakl.2000 added to answer. And corrected the code slightly. Were you too polite to indicate an error? Please, I make them all the time at fresh code. – Joop Eggen Oct 25 '21 at 08:18
  • @Joop Eggen , Could you please add the public static void main method for Recipe Class,Wrong Class,Right Class . It will be helpful a lot. – deepakl.2000 Oct 25 '21 at 12:07
  • @JoopEggen , Could you please add the public static void main method for Recipe Class,Wrong Class,Right Class . It will be helpful a lot. – deepakl.2000 Oct 25 '21 at 12:49
  • 1
    @deepakl.2000 sorry, forgotten to copy. – Joop Eggen Oct 25 '21 at 17:52
  • @JoopEggen Could you please add the public static void main method Java code for Recipe Class – deepakl.2000 Oct 27 '21 at 06:49
  • @Joop Eggen , Could you please add the public static void main method for Recipe Class – deepakl.2000 Oct 27 '21 at 08:32
  • @deepakl.2000 Sorry, a bit stressed; less time for stackoverflow. Bye – Joop Eggen Oct 27 '21 at 15:40
  • @JoopEggen , OK when you find time, do update it. It would be useful for learning purposes. – deepakl.2000 Oct 27 '21 at 17:59
  • @JoopEggen , Could you please add the public static void main method for Recipe Class – deepakl.2000 Apr 30 '22 at 11:32
  • @deepakl.2000 `class Recipe { ... public static void main(String[] args) { ... } }` For sample code creating objects and copying them, try coding yourself. – Joop Eggen Apr 30 '22 at 15:29
2

Copy constructor in java can be used when you need to clone an object

class Copy {
   int a;
   int b;
  public Copy(Copy c1) {
    a=c1.a;
    b=c1.b;
  }
}

In java when you give Copy c2=c1; simply creates a reference to the original object and not the copy so you need to manually copy the object values.

See this:

Community
  • 1
  • 1
Lakshmi
  • 2,204
  • 3
  • 29
  • 49
1

This is where you create a new object, by passing an old object, copying its values.

Color copiedColor = new Color(oldColor);

instead of :

Color copiedColor = new Color(oldColor.getRed(),
                              oldColor.getGreen(), oldColor.getBlue());
Mordechai
  • 15,437
  • 2
  • 41
  • 82
1

A copy constructor is used to create a new object using the values of an existing object.
One possible use case is to protect original object from being modified while the copied object can be used to work upon.

public class Person  
{  
   private String name;  
   private int age;  
   private int height;  


/** 
 * Copy constructor which creates a Person object identical to p.  
 */  
   public person(Person p)  
   {  
      person = p.person;  
      age = p.age;  
      height = p.height;  
   }  
.
.
. 
}

Related to defensive copy here is a good read