I don't get how copy constructors work in detail - java

What is the purpose of this code?
public Fraction(Fraction other) {
num = other.num;
denom = other.denom;
}
If you have a constructor like this:
public Fraction(int n, int d) {
num = n;
denom = d;
}
Why do you have to initialize other.num to num and other.denom to denom. What is with the syntax of the copy constructor? What is the purpose?

It is much more convenient to use.
If you have a simple constructor like:
public Fraction(int n, int d) {
num = n;
denom = d;
}
You can copy the instance original with following code:
Fraction copy = new Fraction(original.num, original.denom);
When using a copy constructor you perform following call:
Fraction copy = new Fraction(original);
In case you have many parameters this can be much more convenient. What is when you change the arguments of your constructor or your object? Without a copy constructor you have to change all such calls.
Noteworthy fact from M. Prokhorov's comment:
There is no special syntax for copy constructors, they are just
logical style of implementing a parameterized constructor.

If you were to simply type
public Fraction(Fraction other) {
}
Java isn't simply going to guess that you want to copy the values of other into the new object. Java does not automatically initialize your variables for you like that. For it to be a copy constructor, you still have to manually type out the code that copies the fields from other to the object you are creating. Like this:
public Fraction(Fraction other) {
num = other.num;
denom = other.denom;
}
The constructor creates a new Fraction but it is the code you type inside it that manually performs the "copying" that makes it a "copy constructor" and allows you to do
Fraction a = Fraction(4, 20);
Fraction b = new Fraction(a);
// b has the same values as a but is a different object
Of course, if you already have another constructor, a shorter way to make a copy constructor is
public Fraction(int n, int d) {
num = n;
denom = d;
}
public Fraction(Fraction other) {
this(other.num, other.denom);
}

There are 2 good reasons for using a copy constructor instead of the constructor passing all parameters :
when we have a complex object with many attributes it is convenient to use the copy constructor
if we add an attribute to the existing class, then we can just change the copy constructor to take this new attribute into account instead of changing every occurrence of the other constructor

If you have an instance of the Fraction object like:
Fraction fr = new Fraction(1, 2); //represents 1/2
Of course you can copy it by just assigning it to a new variable:
Fraction copy = fr;
But now, both fr and copy point to the same object (same location in memory). If, for some reason, copy changes to 1/3, fr will change too.
Sometimes you want a completely fresh copy of your original object. That is where it is really handy to write:
Fraction copy = new Fraction(fr);
Now you can independently manipulate copy and fr without worrying about unwanted changes in any of them.
You can read this tutorial to gain more in-depth information on the subject.

Related

How do you know what type of constructor to use?

I know this is probably a very stupid question but I've looked at a lot of different sources and I can't seem to understand the difference between the no-arg constructor and the constructors with arguments. I'm under the impression that the no-arg constructor accepts as many arguments as you want, and the constructors with, say, 2 arguments, only accepts 2.
import java.io.*; //the File class
import java.util.*; //the Scanner class
public class Distance implements Comparable<Distance>
{
private int myFeet, myInches;
public Distance()
{
myFeet = myInches = 0;
}
public Distance(int f, int i)
{
myFeet = f;
myInches = i;
}
public Distance(Distance arg)
{
myFeet = arg.getFeet();
myInches = arg.getInches();
}
}
I just don't understand why it's necessary to have both Distance(int f, int i) and Distance(Distance arg) and how you know which constructors to use. Also, what is Distance arg? Is "arg" just a placeholder variable or is it an actual Java keyword? It'd be great if I could get an explanation about constructors!
A no-arg constructor takes 0 arguments (no arguments). It just runs the code inside the constructor, and you'll often see it used to initialize values to some pre-determined defaults (like yours that just sets feet and inches both to 0). In contrast, a constructor that takes in arguments can have its values set to different values at run-time.
This constructor
public Distance(Distance arg)
is called a copy constructor. It takes in an argument of the same class and just copies its attributes into the current object under construction.
Which constructor you use is entirely based on what you need. Some classes won't have all types of constructors defined, so you're limited. Others will have several constructors defined, so you can use whichever one the situation calls for.
Short answers:
I'm under the impression that the no-arg constructor accepts as many arguments as you want, and the constructors with, say, 2 arguments, only accepts 2.
A no-arg or parameterless constructor accepts no arguments. This is for the purpose of creating a default instance of a given class. In fact, if you did not provide any constructor, Java compiler provides a default no-arg constructor for your class. If you declare a constructor with n arguments (e.g. public Person(String name, int age), then constructing an instance of that class by calling that constructor requires you to provide the correct number, type and order of those arguments (e.g. Person p = new Person("Larry", 32)).
Perhaps you are confusing this type of constructor with a vararg or variable arity method that accepts one or more arguments of a given type (there are some gory details that you should read up). Since a constructor of a class is similar to any other instance method (there are differences), you could have variable arity constructors, but they are rarely used:
class Chameleon {
private final String color;
private final String location;
private final int lifeSpanYears;
/**
* Constructs a default Chameleon that has GREEN color, is from Africa and
* has 5 years of life span.
*/
public Chameleon() {
this.color = "GREEN";
this.location = "Africa";
this.lifeSpanYears = 5;
}
/**
* Constructs a specific instance of Chameleon with given color, location
* and life span.
*/
public Chameleon(String color, String location, int lifeSpanYears) {
//validate arguments
this.color = color;
this.location = location;
this.lifeSpanYears = lifeSpanYears;
}
/* Constructs a Chameleon from given one or more string params.
If given, first argument is the color and if given, the second
argument is the location. Life span of the instance will be 5 years.
<b> Note: this is for illustration purposes only. </b>
*/
public Chameleon(String... props) {
if (props.length == 0) {
this.color = "GREEN";
this.location = "Africa";
} else if (props.length == 1) {
this.color = props[0];
this.location = "Africa";
} else {
this.color = props[0];
this.location = props[1];
}
this.lifeSpanYears = 5;
}
public Chameleon(Chameleon mold) {
this.color = mold.color;
this.location = mold.location;
this.lifeSpanYears = mold.lifeSpanYears;
}
public static void main(String[] args) {
Chameleon c = new Chameleon(); // no-arg constructor is called
System.out.println(c.color); // => GREEN
System.out.println(c.location); // => Africa
System.out.println(c.lifeSpanYears); // 5
Chameleon c2 = new Chameleon("BLACK", "Asia", 4); // specific constructor is called, right number, type and order of arguments is provided
System.out.println(c2.color); // => BLACK
System.out.println(c2.location); // => Asia
System.out.println(c2.lifeSpanYears); // 4
Chameleon c3 = new Chameleon("BROWN", "California"); // this time it should be the vararg constructor!
System.out.println(c3.color); // => BROWN
System.out.println(c3.location); // => California
System.out.println(c3.lifeSpanYears); // 5 again
Chameleon c4 = new Chameleon("BROWN"); // this time it should be the vararg constructor again!
System.out.println(c4.color); // => BROWN
System.out.println(c4.location); // => Africa
System.out.println(c4.lifeSpanYears); // 5 again
Chameleon c5 = new Chameleon(c2); // this time the _copy_ constructor is called. c5 is a copy of c2.
// although c5 is a copy of c2, it is a distinct entity; think of c5 as
// an identical twin of c2.
System.out.println(c5.color); // => BLACK
System.out.println(c5.location); // => Asia
System.out.println(c5.lifeSpanYears); // 4
}
}
I just don't understand why it's necessary to have both Distance(int f, int i) and Distance(Distance arg)
Well, it is not necessary per se. It's a convenience. The underlying mechanism that enables this is called method overloading which means you could declare two constructors (or methods) with the same name (class name in this case) in a class. Every constructor can construct an instance of a class in a way it chooses to. Ideally, all the constructors should construct properly initialized instances. If you followed some basic object oriented programming good practices, you should not go wrong here.
In this particular case, you are providing two constructors: the first that takes both feet and inches and the other that takes another instance of the same class. The second constructor embodies what is knows as a copy constructor which should create a copy of the passed argument. Thus, if you have an already available instance d of the Distance class, you can create a copy of that using:
// get d from somewhere
Distance dCopy = new Distance(d);
See the copy constructor (and its use) provided in my example code above.
and how you know which constructors to use
Here you will need to read the documentation or source of the class that you intend to use. Well-written classes like the JDK provide good documentation for you to look at.
Also, what is Distance arg?
It is an instance of the class Distance that is used as a constructor argument. Again, see the main method of the Chameleon example.
Is "arg" just a placeholder variable or is it an actual Java keyword?
Yes, the former. It's more commonly known as an argument or a formal parameter.
Constructors are used to instantiate a Class.
There can be default constructors which does not initialize any of the properties in the class.
In your code the default constructor is :
public Distance()
{
myFeet = myInches = 0;
}
A class can be instantiated in many ways, and for that constructors are needed. There can arguments in constructors. These arguments automatically set the properties of the class inside the constructors. So we don't need to set the properties individually.
For eg in your code:
public Distance(int f, int i)
{
myFeet = f;
myInches = i;
}
public Distance(Distance arg)
{
myFeet = arg.getFeet();
myInches = arg.getInches();
}
In the first constructor the properties are set individually in the constructor.
In the second case it is set from another Distance Object.
Args is not a keyword, it is the name of the object of type Distance.
If no external constructor is written then it will take its default constructor ( Which is handled by java internally ).
If for a class A , a constructor public A() is present then it will consider this one as a constructor.
Now if you have a constructor like,
public A()
{
<something>
}
Then while creation of object you have to write just,
A objectA = new A();
If you have a constructor like,
public A(int x)
{
<something>
}
then while declaring you have to write,
A objectA = new A(<any integer>);
Here you can't write,
A objectA = new A();
So when you are declaring constructor then only those will be considered.
Now in your code,
public Distance()
{
myFeet = myInches = 0;
}
public Distance(int f, int i)
{
myFeet = f;
myInches = i;
}
public Distance(Distance arg)
{
myFeet = arg.getFeet();
myInches = arg.getInches();
}
You can create the object of Distance class in three manners,
Distance distance = new Distance();
Distance distance = new Distance(1,2);
Distance distance2 = new Distance();
Distance distance = new Distance(distance2);
So in all the cases the object is created and the values are initialized. But it is written in multiple way to approve multiple type or mannered coding and to give the code more options to create the object.
Lastly arg is just a variable name.

How do getter methods work on arrays?

public class foo {
private int a[];
private int b;
public foo(){
a = new int[] {1,2};
b= 3;
}
public int[] getA(){
return this.a;
}
public int getB(){
return this.b;
}
I noticed that it's possible to change a value of A by accessing the object like this:
foo f = new foo();
f.getA()[0] = 5; // f.a[0] changes to 5
but it isn't possible to do something like:
f.getB = 5; // gives error
f.getA() = new int[]{2,3}; //gives error
can someone explain me how this works, and how to prevent the user from changing the value of an array cell?
Thanks in advance.
In Java, array is a reference type, which means that the value of an array expression is a reference to the actual array.
The return value of getA() is, therefore, a reference to the private array inside your object. This breaks encapsulation: you give access to your object's internals.
You can avoid this by either returning a reference to a copy of your internal array, or by providing a different API which only returns individual elements, say a method getA(int index).
f.get(A) returns a reference to an array. You can access that array the way you access any array, and assign values to its elements with f.get(A)[i]=... (though it makes more sense to store the returned array in a variable, which would let you access that array multiple times, without having to call f.get(A) each time).
You can't, however, assign anything f.get(A) via f.get(A)=.., since a method call is not a valid left side of an assignment operator. For all you know, a call to f.get(A) may generate a new array that is not referred to by a member of the foo class, so assigning f.get(A)= new int[5]; would make no sense, since there would be no variable in which to store the new array.
The same explanation applies to f.getB() = 5;.
Instead of giving away the array, to allow the caller to do what they like with it you can use an indexed getter
public int getA(int n){
return this.a[n];
}
public void setA(int n, int x) {
this.a[n] = x;
}
Now, the caller has no access to the array and cannot change it without you knowing.

Initialize object A in java equal to another object B [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I copy an object in Java?
How can I initialize an object (say A) in java and set its initial member values equal to a second object (say B). After initialization I want to modify the members of A without modifying the members of B. So at initialization of A I only want to copy the data of B. How is this done in a nice way??
You could implement and use clone
MyClass b = new MyClass();
MyClass a = b.clone();
Note: some classes are not Cloneable, or have broken implementations. e.g. only have a shallow copy when they should be a deep copy.
If the class is Serializable you can serialize it and deserialize it in memory. Not exactly nice but it works.
Or you could create your own "copy" constructor.
One possible solution for that would be implement clone method on your class and use clone as follows:
MyClass a = new MyClass();
MyClass b = a;
You will notice that clone() isn't really a public method, so your will need to expose it. Additionally you need to tell Java that your object is Cloneable (this is done making your class implement Cloneable). The following code ilustrate it:
public class MyClass implements Cloneable {
#Override
protected MyClass clone() throws CloneNotSupportedException {
return (MyClass)super.clone();
}
}
That all depends on the type of the members. I'll give an Example:
class A
{
public float value;
public int[] anArray;
public A(B b)
{
//primitive may be assigned directly.
this.value = b.value;
// other types different approaches:
//copy the contents of the array
this.anArray = new int[b.anArray.length];
System.arraycopy(b.anArray, 0, this.anArray, 0, b.anArray.length);
}
}
class B
{
float value;
int[] anArray;
public B(int size)
{
this.value = 3f;
this.anArray = new int[size];
for (int i = size - 1; i >= 0; i--)
{
this.anArray[i] = i * 10;
}
}
}
B b = new B(5);
A a = new A(b);
Cloning is a straightforward option for copying. If you ever want to do something where you need more control, create your own method that performs your copy exactly how you need it:
public MyType copy()
{
MyType a = new MyType();
// Initialize how you need to here, use the object this was called from if you'd like
a.property = this.property;
// etc.
return a;
}
This gives you more direct control, but takes more time to code. If clone will suit your purposes, stick to that.
EDIT: I am going to give an example based on your comments on this answer.
Let us assume we have the following types:
TypeA: has the following member variables
int number = 5; // Default value built in by constructor.
int letter = 'x'; // Value is 'a' when constructed but has been changed.
ArrayList<TypeB> list = {b1, b2, b3} // All are initialized.
TypeB: has the following member variables
double decimal = 5.32
TypeC someObject = ...
TypeC: has some stuff, but we are going to ignore it.
Now, When we want to copy TypeA, we must do the following:
Copy over the number and character directly as they are value types.
Copy over a reference to the ArrayList which contains a reference to some TypeBs.
Luckily those are easy steps.
int copyNumber = this.number;
char copyChar = this.letter;
ArrayList<TypeB> copyList = this.list;
return new TypeA(copyNumber, copyChar, copyList);
Now that assumes a particular constructor that takes those three arguments, but hopefully you get the idea.
It would get tricky if you wanted to just get values, not references to all of the TypeBs in the ArrayList. You would have to loop through the ArrayList and create new TypeBs that copied all of ITS values (double and TypeC objects as either references or values...)
In short, what you want is an easier copy to perform. Simple assignment operators copy values with primitive types and references with Objects.

Change Value of function arguments in Java

I need to convert C code to Java.
The minimal C code is:
void changeX(int *x)
{
*x=5;
}
changeX is called in function B as:
void B()
{
int k= 2;
changeX((int*) &k);
}
The problem while converting it into Java is that x is not a class member so i cannot use this. How can i convert such code to Java?
Assuming you're really asking, "Can I use pass-by-reference in Java" (which that C code isn't using, but is emulating with pointers, which also aren't supported in Java) the answer is no.
Options:
Pass in a reference to an object which does contain a field you can change
(Ugly, but equivalent to the above in some senses) Pass in an array of size 1 constructed using the local variable, mutate the variable in the method, and then set the local variable again based on the array contents afterwards
Return the new value and assign it that way
Change your design so you don't need this
The last two of these options are the nicest ones. If you could give more information about the bigger picture - why you think you want to do this - that would be helpful.
Use one-element array reference:
void changeX(int[] x) {
// do not forget about checks
x[0] = 5;
}
void test() {
int[] x = {0};
changeX(x);
}
Being a primitive, and not a class member, you cannot pass the reference to another method. Use a class member instead.
You should return the new value of x,the method should as follow:
private int changeX(int x){
return 5;
}
You existing C code is incorrect:
void B()
{
int k= 2;
// you are not passing address of variable k but instead
// you are passing k (which is 2) as the address whose location needs
// to be changed. So you are writing to address 2 which you don't own.
changeX((int*) k);
}
What you need is:
changeX(&k);
Now this is changing the value of a variable by passing it by address. Now such a thing is not possible in Java which always uses pass by value. But you can get similar effect by enclosing the int variable inside an Integer object or an integer array (also an object) and pass the object by value.
Simply put Java has no equivalent to a pointer to a basic type - in order to achieve this you need a reference int type something like
class RefInt {
public int Value;
RefInt(int x) { Value=x; }
}
And you pass this in the same context and it works like so:
RefInt X=new RefInt(3)
ChangeX(X);
Obviously in this context simply changing the return value to type int and assigning it would be better but that doesn't solve your general problem.
Option1:
Put the int variable in a wrapper class. Pass that the method. In the method you can change the value in wrapper instance.
Option2:
Make changeX() return int and replace all changeX(k) with k = changeX(k).

Array and methods?

I'm doing a task for a course in Java programming and I'm not sure how the following thing is working? The method below takes the value from an array and a integer. The integer should be added to the array and then be used outside the method in other methods and so on, but how could this work when the method has no return for the new content of the array? There is a void in the method? Have I missed something? Preciate some help? Is there something about pointers?
public static void makeTransaction(int[] trans, int amount);
Arrays in Java are objects. If you modify the trans array inside the method, the changes will be reflected outside of it1. Eg:
public static void modify(int[] arr)
{
arr[0] = 10;
}
public static void main(...)
{
int x = {1, 2, 3};
System.out.println(x[0]); // prints 1
modify(x);
System.out.println(x[0]); // now it prints 10
}
Note that native arrays can't be dynamically resized in Java. You will have to use something like ArrayList if you need to do that. Alternatively you can change the return type to int[] and return a new array with the new element "appended" to the old array:
public static int[] makeTransaction(int[] trans, int amount)
{
int[] new_trans = Arrays.copyOf(trans, trans.length + 1);
new_trans[trans.length] = amount;
return new_trans;
}
1 It is also worth noting that as objects, array references are passed by value, so the following code has no effect whatsoever outside of the method:
public void no_change(int[] arr)
{
arr = new int[arr.length];
}
You can't add anything to an array. Java arrays have a fixed length. So indeed, what you want to do is impossible. You might make the method return an int[] array, but it would be a whole new array, containing all the elements of the initial one + the amount passed as argument.
If you want to add something to an array-like structure, use an ArrayList<Integer>.
Do you have to keep the method signature as is?
Also, can you be a bit more specific. When you say "the integer should be added to the array", are you referring to the amount argument? If so, then how is that amount added? Do we place it somewhere in the array or is it placed at the end, thus extending the array's length?
As far as pointers go, Java's pointers are implicit, so if you don't have a strong enough knowledge of the language, then it might not be so clear to you. Anyways, I believe that Java methods usually will pass objects by reference, and primitives by value. But, even that isn't entirely true. If you were to assign your object argument to new object, when the method terminates, the variable that you passed to the method is the same after the method executed as it was before. But, if you were to change the argument's member attributes, then when the method terminated those attributes values will be the same as they were inside of the method.
Anyways, back to your question, I believe that will work because an array is an object. So, if you were to do the following:
public static void makeTransaction(int[] trans, int amount)
{
trans[0] = amount;
}
// static int i;
/**
* #param args
*/
public static void main(String[] args)
{
int[] trans = {0,1,3};
makeTransaction(trans, 10);
for(int i = 0; i<trans.length; i++)
{
System.out.println(trans[i]);
}
}
The output of the array will be:
10
1
3
But, watch this. What if I decided to implement makeTransaction like so:
public static void makeTransaction(int[] trans, int amount)
{
trans[0] = amount;
trans = new int[3];
}
What do you think that the output will be? Will it be set to all zero's or will be the same as it was before? The answer is that the output will be the same as it was before. This ties in to what I was saying earlier.
I might've assigned that pointer to a new object in memory, but your copy of the pointer inside of the main method remains the same. It still points to the same place in memory as it did before. When the makeTransaction method terminates, the new int[3] object that I created inside of it is available for garbage collection. The original array remains intact. So, when people say that Java passes objects by reference, it's really more like passing objects' references by value.

Categories