This piece of code is from a book. The question is,
how many objects are created
how many objects are eligible for gc when the line // do stuff is reached.
The answers, according to the book, are 5 and 2. Here is the code:
class Dozens {
int[] dz = {1,2,3,4,5,6,7,8,9,10,11,12};
}
public class Eggs{
public static void main(String[] args){
Dozens[] da = new Dozens[3];
da[0] = new Dozens();
Dozens d = new Dozens();
da[1] = d;
d = null;
da[1] = null;
// do stuff
}
}
In answer to the first question, do you also count the int[] dz object as an additional object each time you instantiate Dozens?
Similarly, when you reach // do stuff, in calculating the number of objects eligible for gc, for each Dozens object, do you also count the int[] dz object contained therein?
I did not count the int[] dz objects, and arrived at the answers 5 and 3.
Can someone explain what I might be doing wrong?
Thanks.
I have annotated the code below with comments to highlight where references are created or lost.
When counting allocations, one must include the allocation of the array stored in the field dz. My suspicion is that you counted the assignment of object references to da[0] and da[1] as allocations. Since they are copying a reference, and not creating a new object; they only affect when the objects can become GCable and do not create a new object.
class Dozens {
int[] dz = {1,2,3,4,5,6,7,8,9,10,11,12};
}
public class Eggs{
public static void main(String[] args){
Dozens[] da = new Dozens[3]; // +1 object, the array containing 3 nulls
da[0] = new Dozens(); // +2 objects, Dozens and the array in Dozens.dz
Dozens d = new Dozens(); // +2 objects, Dozens and the array in Dozens.dz
da[1] = d; // +0, d now has two refs to it
d = null; // +0, d now has one ref to it
da[1] = null; // -2, d now has no refs to it so both d and its internal array become available for GC
// do stuff
}
}
Summing the totals up gives, 1+2+2=5 allocations. The -2 at the end concludes that 2 objects have become available for GC
Related
I have a question which I consider to be rather vague.
How many objects(instances) of class A are created by the following method:
void create() {
A a;
A b;
A[] s;
a = new A();
b = a;
s = new A[10];
}
class A { }
I am not sure how to count the array. We can easily see that the objects a and b are the same, but do we consider the array itself to be an object, or do we consider that it has 10 objects, which are null?
I thank you in advance!
s = new A[10] is an object of A[], it's not an object of class A.
Therefore, you don't count the 10 null references of the array.
only a = new A() is created.
I ran the above code through the Eclipse profiler and found that only one instance was created a = new A() which b also references. Hence there was only one instance created. The array of type A was not allocated as null until I assigned an object to the first index of the array. Hope this helps.
In the below code, EX1 and EX 2 prov the homogeneous theory but in EX3 it holds multiple types values. So then, how we can say arrays are homogeneous? What is the exact theory behind this?
public class Test {
public static void main(String[] args) {
// Ex 1
int [] intArr = new int[5];
intArr[0] = 1;
intArr[1] = 2;
// Ex 2
int [] intArr2 = new int[5];
intArr2[0] = 1;
intArr2[1] = "ss";
// Ex 3
Object [] objArr = new Object[5];
objArr[0] = 1;
objArr[1] = "ss";
objArr[3] = new Object();
}
}
There are a two concepts here: inheritance and auto-boxing
Inheritance -
A String inherits from Object and hence is an Object. This means that String gets all methods and properties defined in the Object class automatically at compile time. It is an Object plus additional stuff that is specific to the String. However, it can be viewed by Java as an Object because it is an Object. When it is added to the array, it is added as an Object, not as a String. That is because the Array is defined as an Array of objects.
char a = "ss".charAt(1); // Legal as charAt(..) is a method in the String class
Object [] objArr = new Object[5];
objArr[1] = "ss";
objArr[1].charAt(1); // Not legal because charAt(..) method is not defined for Object
See Oracle Tutorial.
Auto-Boxing -
Java performs a shortcut known as auto-boxing to a automatically convert primitives to a special set of wrapper Classes all of which inherit from Object. Hence, because of auto-boxing and inheritance, assigning a number to an Object will convert that number to an Object as well.
Hence, everything added to the array was added as an Object. It is true that the objects in the array may be classes that inherited from Object. However, as far as the array is concerned, they are of type Object. Even so, if you were to pull it out of the array and cast it as an Integer, you could do so. It still carries the Integer information with it but that information in not available without a cast. From the array's point of view, it is only an Object.
See Oracle Tutorial.
I wrote the following code. It works great, but I have a question (so I don't bomb any future additions). Here's the code:
public class MoreStuff extends javax.swing.JFrame {
// Globals
int quiz[][]; // Used for Quiz subroutines
...
private void btnGetQuizActionPerformed(java.awt.event.ActionEvent evt) {
Functions fns = new Functions();
String strout;
int i = 0;
// Get the quiz
quiz = fns.GetQuiz();
The fns.GetQuiz() returns a 2-dimensional array perfectly.
My question is this: Having declared a multidimensional array at the class level, when the computer executes quiz = fns.GetQuiz, have I passed an object or have I only copied a reference?
Let's say GetQuiz()'s implementation is simply:
public int[][] GetQuiz() {
int[][] someArray = new int[10][];
return someArray;
}
The line int[][] someArray = new int[10][]; allocates an array on the heap and assigns a reference to that object to someArray.
When the method GetQuiz() finishes executing, the only thing "destroyed" is someArray, which is simply the reference to the array. The array itself lives on the heap, and only becomes eligible for garbage collection once there are no more references to the array.
In your example, because a copy of the reference is assigned to the quiz variable, even when someArray is destroyed, you still have quiz's reference pointing to the array, so the garbage collector will not try to destroy the array.
I think you might find the information in this thread helpful: Stack and Heap memory in Java.
In your program, quiz will hold its value even after the execution of btnGetQuizActionPerformed() because it receives a copy of the reference tofns.
I have an assignment I am working on where I have two classes.
Class A is called Points. It contains data for a 2D coordinate, and additional data associated to that specific point.
Class B is called Particles. It contains an array of objects of class A as well as some additional information.
I have a list of Particles. At initialization, all Particle objects contain an identical array of Points.
If I then change the value of the first position in the Points array in any Particle, I then see that all other Particles have mirrored this change. This is not the bahaviour I want. Instead, I want any changes in any Particle to be unique to that object.
public static class Particle{
public double[][] current = new double[NC][2];
public double[][] pBest = new double[NC][2];
public double[][] vel = new double[NC][2];
public Points[] points = new Points[array.length];
public double pbestfitness = 0.0;
public Particle(){
}
//standard get/set methods here
}
public static class Points{
public int x;
public int y;
public double centroidx;
public double centroidy;
public Points(){
this.x = -1;
this.y = -1;
this.centroidx = -1;
this.centroidy = -1;
}
public int getx(){
return x;
}
public void setx(int a){
x = a;
}
public int gety(){
return y;
}
public void sety(int a){
y = a;
}
public double getcx(){
return centroidx;
}
public void setcx(double a){
centroidx = a;
}
public double getcy(){
return centroidy;
}
public void setcy(double a){
centroidy = a;
}
}
initialization:
for(int i = 0; i < NP; i++){
p = new Particle();
initbest = new double[NC][2];
points = new Points[array.length];
points = array.clone();
for(int j = 0; j < NC; j++){
x = minx + r.nextInt(maxx - minx + 1);
y = miny + r.nextInt(maxy - miny + 1);
p.setCentroid(j, x, y);
initbest[j][0] = x;
initbest[j][1] = y;
}
p.setpBest(initbest);
p.setVel(initV);
p.points = points;
particles.add(p);
}
I thought that the issue was that I was copying each array of type A by address location rather than value, so I tried using System.arraycopy, and Arrays.copyOf() as well as array.clone, but none of them worked.
Here is code where I make a change to one object, but the change is mirrored in all objects:
particles.get(i).points[j].centroidx = particles.get(i).current[closest][0];
particles.get(i).points[j].centroidy = particles.get(i).current[closest][1];
The idea is basically I'm taking a set of point, adding a bunch of centroids, then finding which centroid is closest to each point and associating that point to that centroid. I run this with a set number of random starting positions, hence why I need to have a set number of copies of the starting positions represented by particles. I have ensured that the calculation for finding the closest centroid works using a testing data set of a low number of set points and centroids.
What happens after I complete an iteration of the first particle is that all the other particles are changed, when I have explicitly stated that the centroids of just the first particle is being changed. After the end of the first iteration of all particles is completed, all particles carry identical points arrays with centroids equivalent to the last copy that was changed. instead of unique points arrays with centroid data associated with that particle.
So the first particle will have a list of points with centroids that are not found to be a member of that particle. Instead, it holds the centroid data of the last particle of the previous iteration.
All the Point objects with same index reference the same object. So when you change one of them, all the other objects with the same index in all the arrays will change as well. You must make sure that on initialization you make a depp copy of all the Point objects. A deep copy means that the information (in fields) is all the same, but they refer to different objects (You must make a deep copy of the fields too). Arrays.copyOf will not help you because it will create a shallow copy (The points at the same index will refer to the same object.) You need to implement the clone method on point that will create a deep copy of the point. Then during initialization, just call point.clone().
See What is the difference between a deep copy and a shallow copy?.
I have a couple of suggestions.
First, when you describe a problem for which you provide code, refer to the variables/arrays/whatever with the names they have in the code. I don't know what you mean by A and B, and don't intend to dig through the code enough to guess, only to be wrong.
Second, if changing the data in one place automatically shows up in the other, then you almost certainly have a reference to the same object in the two places. If you do this:
A a = new A();
B b = new B();
b.setA(a);
array1[0] = a;
array2[0] = b;
then a change to a will be reflected in the object in both array1 and array2.
To prevent that, you can create an object of type A that is a copy of a, and put THAT into b before putting b into array2. Look up information on the Object.clone() method.
After testing the code (see below), I found out that I don't understand some fundamentals.
Class A.
class A {
private String s;
private int[] array;
private B b;
public A(String s, int[] array, B b) {
this.s = s;
this.array = array;
this.b = b;
}
}
Class B.
class B {
public int t;
public B(int t) {
this.t = t;
}
}
I thought that any changes I did after A a = new A(s, array, b); would affect a. Don't all the fields of a and the variables s, array, b refer to the same object?
String s = "Lorem";
int array[] = new int[] {
10, 20, 30
};
B b = new B(12);
A a = new A(s, array, b);
s = "Dolor";
array = new int[] {
23
};
b = new B(777); // Initialized with a new value, a.b keeps the old one. Why?
System.out.println(a);
The output.
String Lorem
Array [10, 20, 30]
B 12
And about this.
B b2 = new B(89);
B b3 = b2;
System.out.println(b3);
b2 = null;
System.out.println(b3); // b2 initialized with null, b3 keeps the old one. Why?
The output.
89
89
However, if I have two lists, this shows that they both refer to same object.
ArrayList<String> first = new ArrayList<String>();
first.add("Ipsum");
ArrayList<String> second = new ArrayList<String>();
second = first;
first.add("The Earth");
System.out.println(second);
The output.
[Ipsum, The Earth]
The difference is assignment versus modification.
Assignment (=) makes the variable point to something else, so this won't change the underlying data. So any other variables pointing to the same data don't change.
Modification (pretty much anything except =) doesn't change what the variable points to, it just modifies the underlying object. So any other variables pointing to the same data do change.
For you example:
b = new B(777); is assignment, so only b is changed to point to something else. a.b won't change.
b2 = null; is assignment, so only b2 is changed to point to something else. b3 won't change.
If you were to say b2.t = 5, this would be modification (we're not assigning a new value to b2, we're modifying it by changing one of its members), so b3 will change as well.
I hope that explains it.
No. The thing is, you are not changing a, you are assigning a new value to s. S is a String, which are immutable, which means you can never make a change to the value of s. You can, however, change the reference in S, which is what you are doing.
To make yourself more clear try these lines of code..
String s = "Lorem";
int array[] = new int[] {10, 20, 30};
B b = new B(12);
//A a = new A(s, array, b);
s = "Dolor";
array = new int[] {23};
b = new B(777);
A a = new A(s, array, b);
System.out.println(a);
ArrayList<String> first = new ArrayList<String>();
first.add("Ipsum");
ArrayList<String> second = new ArrayList<String>();
second = first;
second.add("The Earth");
first.remove("The Earth");
System.out.println("second :"+second);
What are the current values the String s, array and the object b are holding while creating the instance of class A ( at the time of calling class A constructor ) will be printed. After creating class A instance, the String s, array and object b will be referred as a.s, a.array and so. If you assign a new value to s, array and b, it wont affect the class A instance.
And for the array list question, the two array lists will refer the same reference only. If you want different reference then do like this... (But always = assign operator will make same reference only )
ArrayList<String> first = new ArrayList<String>();
first.add("Ipsum");
ArrayList<String> second = new ArrayList<String>(first);
second.add("The Earth");
System.out.println("first :"+first);
System.out.println("second :"+second);
Thanks Dukeling for explaing how assignments works with objects and primitives, I am adding here to explain how the list works when operations performed on them.
When we consider the two array lists created in the above code in the question, both the variables first and second are pointing to the same array object that resides in the memory.
So when an add operation is performed the underlying object itself gets updated. So the print operation prints the second array list which pointed to the same array-list object created during the creation of first array-list.