What is a copy constructor?
Can someone share a small example that can be helpful to understand along with defensive copying principle?
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.
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.
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:
Why doesn't Java have a copy constructor?
Copy Constructor in Java
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());
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
Related
I am new to Java and I need some clarification how to approach an issue.
I have a class Epicycle, defined below:
public class Ts_epicycle {
private double epoch;
private double[] tle = new double[10];
}
In another class, Refine I am calling a method that requires the tle array:
// create an instance of Epicycle
Epicycle e = new Epicycle();
methodExample(keps1, keps2, e.tle);
In methodExample, I would be setting the array values for tle
1) What is best way for creating getters/setters for the tle array? (and for the other variable too).
2) In the methodExample, I need to pass in the argument for the whole tle array rather than any particular index of it. How would I go about this.
Apologies if i'm not making it clear.
In fact an interesting question:
In order that altering entries in the gotten array does not alter the original object,
you would need to return a copy of the array. Not so nice.
public class TsEpicycle {
private double epoch;
private double[] tle = new double[10];
public double[] getTLE() {
return Arrays.copyOf(tle, tle.length);
}
}
Alternatively you could use the List class instead of an array:
public class TsEpicycle {
private double epoch;
private List<Double> tle = new ArrayList<>();
public List<Double> getTLE() {
return Collections.unmodifiableList(tle);
}
}
This does not make a copy, but simple disallows at run-time to alter the list.
Here the inefficiency is in the Double objects wrapping doubles.
The best might be to use the new Stream class: for iterating through the doubles:
public class TsEpicycle {
private double epoch;
private double[] tle = new double[10];
public DoubleStream getTLE() {
return Stream.of(tle);
}
}
As a general best practice every field in a class that you need to access from another class should be provided with a getter and (if the object is intended as mutable) a setter.
As well explained by Joop Eggen in his answer is usually a good practice to return a copy or a proxy (for example a List/Collection referencing the array), in order to preserve the state of the original array.
If you want to only allow users to edit the array one at a time, then you can add the synchronized keyword to the method signature. Accessing an array is already thread safe so you don't need anything there
For example:
double getTle(int index) {
return tle[index]
}
synchronized void setTle(int index, double value) {
tle[index] = value;
}
This only allows the method to be called once at a time
your array is an object like any other object in java .
// to declare and initialize your array
private int[] st = new int[10];
//getter and setter
public int[] getSt() {
return st;
}
public void setSt(int[] st) {
this.st = st;
}
//for the last method u can use
public void method(int value)
{
for(int i = 0 ; i<st.lenght ; i++){
st[i] += value; // for exemple
}
I am fairly new to java, and recently learned how to cast an ArrayList to an object. My current issue when I'm adding variables to an ArrayList is:
The method set(int, GenericMissile) in the type
ArrayList is not applicable for the arguments (int,
float)
I have tried to correct this in many ways, from changing the return value of the setLocationX() method to GenericMissile setLocationX() to casting the global variable to GenericMissile, with no results.
My main question is: How do I go about making the ArrayList in the second class file work with the ArrayList arguments?
To further this question, is there a way to make a class file be casted to any one return value?
Below is my first class, which contains the object I'm running in the second class:
public class GenericMissile {
float currentX;
float setLocationX() {
currentX = (float) Math.ceil(Math.random() * 801);
return currentX;
}
}
and in the other class file, I have:
import java.util.ArrayList;
public class GameManager {
ArrayList<GenericMissile> allM;
public static void main(String[] args) {
GameManager obj = new GameManager();
obj.getInfo();
}
void getInfo() {
allM = new ArrayList<>();
GenericMissile build = new GenericMissile();
allm.set(0,build.setLocationX());
}
}
GenericMissile#setLocationX() returns float and your ArrayList is bound to type GenericMissile, so you're feeding it the wrong type. Did you mean:
allM = new ArrayList<>();
GenericMissile build = new GenericMissile();
build.setLocationX();
allM.set(0, build);
You could also make GenericMissile return itself on build.setLocationX() by slightly modifying the setLocationX:
GenericMissile setLocationX(){
float setLocationX(){
currentX = (float) Math.ceil(Math.random()*801);
return this;
}
This was a question on an exam. Luckily I picked the right answer, but I still can't see why it's right.
Consider this program:
class D {
protected C c;
public D(C c) {
this.c = new C(c);
}
public C getC() {
return c;
}
public void setC(C c) {
this.c = c;
}
}
class C {
protected String s;
public C(String s) {
this.s = s;
}
public C(C c) {
this(c.s);
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public static void main(String[] args) {
C c1 = new C("1");
C c2 = new C("2");
D[] d = {
new D(c1), new D(c1), new D(c2), new D(c2)
};
d[0] = d[3];
c1.setS("3");
String r = "";
for (D i: d) {
r += i.getC().getS();
}
System.out.println(r);
}
}
It'll print 2122. I would expect 2322 however (I'm clearly wrong when you run the code). My reasoning behind that:
In the third line of the main method, four instances of D get initialized.
The constructor of D makes a new instance of C. An instance of C has a String variable which points somewhere to a spot in the memory. Now the instance variable c, let's call it c3, of the object in d[1] has a instance variable (type String), let's call it s3, pointing to the same memory as the String s1, variable of c1.
So when we change s1, I'd expect the value of s3 also to change, since it's pointing to the same spot in the memory.
On a side note, if you change the constructor of D, see below, you'll get 2322 instead. Which I'd expect, since now the variable c3 in d[1] is pointing directly towards the memory location of c1.
public D(C c) {
this.c = c;
}
My thoughts so far on the explanation (could be wrong):
When initializing the instance variable s1/s3, new String objects get made (so far I assumed they were pointing towards "1" in the String pool, since the constructor of C makes it look that way)
When changing s1, it's pointer will be redirected towards "3" in the String pool. Rather than "1" becoming "3" in the pool.
Could anyone explain this behaviour? What are the errors in my (faulty) reasoning?
This is not related to String pooling at all. Main answer: Is Java "pass-by-reference" or "pass-by-value"?
That's because D creates a new instance of C based on C#c. This mean that the instance of D#c is not the same instance as parameter C passed in constructor D, thus modifying that instance won't affect the current instance in D#c.
Re explaining all this in nice terms.
Here's what you're testing:
class Surprise {
String item;
public Surprise(String item) {
this.item = item;
}
//this is called copy constructor
//because you receive an object from the same class
//and copy the values of the fields into the current instance
//this way you can have a "copy" of the object sent as parameter
//and these two object references are not tied by any mean
public Surprise(Surprise another) {
//here you just copy the value of the object reference of another#item
//into this#item
this.item = another.item;
}
}
class Box {
Surprise surprise;
public Box(Surprise surprise) {
//here you create a totally new instance of Surprise
//that is not tied to the parameter surprise by any mean
this.surprise = new Surprise(surprise);
}
public static void main(String[] args) {
Surprise surprise1 = new Surprise("1");
Surprise surprise2 = new Surprise("2");
Box[] boxes = {
new Box(surprise1),
new Box(surprise1),
new Box(surprise2),
new Box(surprise2)
};
boxes[0] = boxes[3];
//you update surprise1 state
//but the state of Box#surprise in the boxes that used surprise1
//won't get affected because it is not the same object reference
surprise1.item = "3";
//print everything...
System.out.println("Boxes full of surprises");
//this code does the same as the printing above
for (Box box : boxes) {
System.out.print(box.surprise.item);
}
System.out.println();
}
}
I have a class called Variable
Class Variable{ private String name; private int[] domain; //...etc}
which represents variable in specific structure (constraint satisfaction problem).
I have instantiated set of variables in ArrayList< Variable > and filled up an array of integers.
ArrayList<Variable> vars=new ArrayList<Variable>();
Variable a=new Variable("A",new int[]{1,2});
vars.add(a);
// Define all variables;
int[] cons=new int[vars.size()];
for(int i=0;i<cons.length;i++)
cons[i]=number_of_constraints(vars.get(i));
// cons contains number of involved constraints for each variable
Now I need to sort them descending based on the number of constraints.
In other words: Given list of Objects [(A,{1,2}) , (B,{3,4}) , (C,{5,6}) ] and an array of integers cons={1,2,0} how to sort the list of objects descending based on the array of integers?
Use a sorted collection like a TreeSet
class Variable {
private String name;
private int[] domain;
};
final Set<Variable> variables = new TreeSet<Variable>( new Comparator<Variable>() {
public int compare(Variable o1, Variable o2) {
//Do comparison here
//return -1 if o1 is less than o2
//1 if o1 is greater than o2
//0 if they are the same
}
});
Now you have a sorted Set of your Variables. This is guaranteed to always be sorted.
If you would like to keep Class Variable intact, the following code will sort the given vars outside:
Collections.sort(vars, new Comparator<Variable>() {
public int compare(Variable var1, Variable var2) {
return var2.number_of_constraints() - var1.number_of_constraints();
}});
If you can change Class Variable, let it implement interface Comparable:
class Variable implements Comparable<Variable> {
//...
public int compareTo(Variable other) {
return this.number_of_constraints() -
other.number_of_constraints();
}
}
Then you can sort vars by:
Collections.sort(vars);
As far as a Variable contains numOfConstraints, according to your code, you can make your Variable class implement Comparable interface, like
public class Variuable implements Comparable<Variable> {
private int numOfConstraints;
public int compareTo(Variable other){
if(this == other) { return 0; }
return (numOfConstraints == other.numOfConstraint) ? 0 : ((numOfConstraints > other.numOfConstraint) ? 1 : -1);
}
}
And then use the utility method java.util.Collections.sort(vars);, that's it.
Your Variable class should implement the Comparable interface,
When it does you should implement the compareTo method.
After that you can sort it by calling the Collection.sort method.
If you want to sort by a permutation if your indexes that's just a matter of creating a new ArrayList and mapping each index to the new index (using a for loop)
Here is such a (generic) method
public static <T> ArrayList<T> permutate(ArrayList<T> origin,int[] permutation){
ArrayList<T> result = new ArrayList<T>(permutation.length);
for(int j=0;j<permutation.length;j++){
result.add(null);
}
for(int i=0;i<permutation.length;i++){
result.set(i, origin.get(permutation[i]));
}
return result;
}
You can do myArrayList= permutate(myArrayList, new int{1,2,3});
Here is example usage in a more basic use case (integers):
public static void main(String... args){
ArrayList<Integer> origin = new ArrayList<>(4);
origin.add(1);
origin.add(2);
origin.add(3);
origin.add(4);
int[] per = new int[]{2,1,3,0};
origin = permutate(origin,per);
System.out.println(Arrays.toString(origin.toArray())); //prints [3,2,4,1], your permutation
}
ArrayList<String> constraints_list=new ArrayList<String>();
public void setConstraints(ArrayList<String> c)
{
c = constraints_list;
constr = true;
}
i want to make ArrayList c to be ArrayList constraint_list...
how to do that?
It's not totally clear to me what you want to do. However, object references are passed by value in Java, so setting the value of c (as in your code) won't work. The typical way to set c from an instance variable is to write a getter rather than a setter:
public ArrayList<String> getConstraints() {
return constraints_list;
}
You can then say:
ArrayList<String> c = getConstraints();
If on the other hand, you are trying to do the opposite (set constraints_list from the passed in parameter), then your assignment is the wrong way round:
public void setConstraints(ArrayList<String> c) {
constraints_list = c;
constr = true;
}
You should also consider whether it's better to make a copy of the list, in which case you could do:
public void setConstraints(ArrayList<String> c) {
constraints_list = new ArrayList<String>(c);
constr = true;
}