Why does the specified object be eligible for garbage collection? - java

For the record, I'm NOT a Java Beginner, but -- rather - an intermediate-level guy who kinda forgot a bit about fundamentals about Java.
class C{
public static void main(String a[]){
C c1=new C();
C c2=m1(c1); //line 4
C c3=new C();
c2=c3; // line 6
anothermethod();
}
static C m1(C ob1){
ob1 =new C(); // line 10
return ob1;
}
void anothermethod(){}
}
From the above code:
Why is it that after line 6, 2 objects of type C are eligible for Garbage Collection(GC)?
Why isn't it that in line 4 and line 10, a copy of c1 is passed into the m1() method. So, eventually in line 6, there is going to be 1 Object (not 2) that are going to be eligible for GC. After all, isn't java pass -by-value rather than pass-by-reference?

There's a difference between pass-references-by-value and pass-values-by-reference :)
Is Java Pass By Reference
Java is never pass by reference right right
Pass By Reference Or Pass By Value
You might want to check out Jon Skeet's article on C# parameter-passing semantics as well, seeing as it's his favorite 'programmer ignorance' pet peeve:
What's your favorite 'programmer ignorance' pet peeve.
So basically, I see your code do the following:
c1 = new C("Alice");
// m1(C obj1) { -- c1 gets passed to m1, a copy of the reference is made.
// -- there are now two references to Alice (c1, obj1)
// obj1 = new C("Bob"); -- there is now one reference to Alice
// and one reference to Bob
// return obj1; -- returns a reference to Bob(c1 still reference Alice)
// } -- when m1 returns, one of the references to Alice disappears.
c2 = m1(c1); // c2 points to Bob
c3 = new C("Charlie");
c2 = c3; // <-- Bob is eligible for collection.
// There are now two references to Charlie

What makes you think two objects of type C are available for GC after line 6? I only see one (c2). What tool are you using that tells you otherwise?
Regarding your question about passing c1 into your m1 method: What you pass (by value) is a reference to the object -- a handle by which you can grab the object, if you will -- not a copy of it. The fact you pass a reference into m1 is completely irrelevant, in fact -- you never use that reference, you immediately overwrite it with a reference to a new object, which you then return (this does not affect the c1 that is still referenced in main).

Related

is this how the static-polymorphism works for variables in java

i want to make sure that my understanding is correct in static-polymorphism
please look at the code below
class a {
int x=0;
}
class b extends a {
int x=4;
}
public class main4 {
public static void main(String[] args) {
a f = new b();
System.out.println(f.x);
b ff = new b();
System.out.println(ff.x);
}
}
the output is
0
4
does that happened because the compiler looks at the declared type of the reference and upon that determines which x to print at compile time ??
(f is declared as type a, the compiler looks at f.x and decides it means a.x)??
& if so,is this called a static-polymorphism or hiding or what ??
thanks in advance
Polymorphism is like looking on the object via the key hole. You don't see the whole object but only that it's part which corresponds to the type of variable you have assigned a reference to the object to.
The object can be seen as different "shapes/forms" - it depends what the key hole you are looking through. But it is still the same object in computer's memory. The form you can see depends on the type of variable you have assigned the object to.
Polymorphism is a multi-form of seeing same object.
If you have object created by new b() - you'll see it as a b class representant when you assign this object to the variable of type b. And you'll see it as a a class representant when you assign it to the variable of type a.
But it is still the same object. And... you can cast it between variables:
f = (a)ff;
and you'll see that suddenly the same object is seen as an representative of a class (including visibility of x field belonging to the a class).

Pointers and objects in java

let's consider the following code:
public class Test {
private int a;
public Test(){
this.a = 1;
}
public static void main(String[] args) {
Test A = new Test();
Test B = A;
// TEST1
B.a = 0;
System.out.println(A); // prints 0
// TEST2
B = null;
System.out.println(A); // also prints 0
}
public String toString(){
return Integer.toString(this.a);
}
}
In TEST1, we modify B and then A is modified because B points to A.
I may understand why in TEST2 A doesn't become null, because B now points to null.
But the results of the two tests seem contradictory: why A doesn't become null ?
Thanks.
The variables A and B were both referencing the same object. B.a = 0 is altering that object. But when you reassign B = null, you're not altering the object. You're just altering the variable.
Test A = new Test();
The variable A points to an instance of type Test
Test B = A;
The variable B points to the same instance as variable A does.
B.a = 0;
The instance, variable B is pointing to (the same instance variable A points to), is changed.
B = null;
Variable B does not point to any instance anymore, while variable A still points to the same instance of type Test as before.
The main thing to understand is that variables A and B do hold a pointer to an instance of type Test. The instance of type Test is represented somewhere in memory and many variables may reference (point) to it.
The expression:
B.a = 0;
means: find the instance B is pointing at and modify its state in memory.
The expression:
B = null;
means: let B point to some other instance in memory (in your case to no instance at all). While the expression:
B = A;
means: let B point to the same instance in memory as A does point to.
By making object b null, you just cut the referance between the test object which resides in the heap and the B. The other referance between the test object and the A remains regardless of the other referances of the object unless you cut it or changed it.
regards
In Java variables are stored in the stack, while objects themselves are stored in the heap. Primitive type values are also stored in the stack, thus primitive type variables don't touch heap at all. But object variables on the stack contain heap addresses instead of values themselves. So by assigning null to B you change the B's (and only B's) value on the stack, but the heap value remains unchanged, and A's value on the stack remains unchanged, so A still references the same object in the heap allowing you to access its attributes and methods.

Inheritance:instanceof operator confusing

consider the code below :
class B
{
int j =100;
}
class A extends B
{
int i=10;
}
public class Test
{
public static void main(String[] args)
{
A obj =new A();
System.out.println(obj);
B obj1 =obj;
System.out.println(obj1); // here i am confused
if( obj1 instanceof A )
{
System.out.println("yes"); //here i am confused
}
}
}
here the output is :
A#35186a
A#35186a
yes
Now obj1 is an instance of class B which is superclass , so why does the toString() show it to be object of A ? Also how can instanceof operator show it to be instance of class A ?
You have to distinguish between the reference and the actual object.
B obj1 = obj;
Here you create a new reference of type B named obj1. The object referenced is still an A object though, this can never be changed.
obj1 is pointing at obj which is an instance of A (see the new A()) you have got there. On the left hand side you are just referencing the super class. Your obj1 will only be able to see methods in B. obj will be able to see all methods in B and A (subject to correct access)
From the java trail
Declaration: The code left of the = associates a variable name with an object type.
Instantiation: The new keyword is a Java operator that creates the object.
Initialization: The new operator is followed by a call to a constructor, which initializes the new object.
There isn't any toString method in your code, you print the memory place holders (Java don't allow you to see the exact location of the object in the memory).
When you do "extends" you say "A is a son of B",then in the lines:
A obj =new A();
System.out.println(obj);
You create an A object and print is memory place holder (remember, A is son of B, so if you want to describe it, imagine a box called A and a box called B connected to her (on top of her, because it's her father)).
Now in the next lines:
B obj1 =obj;
System.out.println(obj1); // here i am confused
You create another object called obj1 and you assign him the memory place holder of A so, it's the first object that you created, called obj. how can you assign A object to a B? Polymorphism!1 and again you print it's memory place holder.
Next you do if:
if( obj1 instanceof A ){
System.out.println("yes"); //here i am confused
}
So, obj1 is an instanceof of A (it's a box of A and on top of her is a box of B (it's father, polymorphism)), and you print "Yes".
In polymorphism you print the lowest method, so you print the A methods if there is any, and if there isn't you "climbing up" to the father and check there and so on..
Polymorphism (computer science)
Now obj1 is an instance of class B which is superclass
That is not true, obj1 is still an instance of A. You just happen to assign a pointer of the super class to an already existing pointer of class A.
If you want an instance of class B just do this:
B b = new B();
If you want an instance of class A you can do this:
A a1 = new A();
or
B a2 = new A();
The later, a2, is correct because A is of type B. However, a2 is still an instance of A, because we used new A().

Understanding how Java handles objects when used as method parameters

I have been playing around with Java and cannot quite understand how java methods work with objects which are passed to them.
For example, In the code below i create some "Container" object instances which contains another object and a primitive. When i pass this "Container" object to methods, I can change the object that is held inside the container instance either directly modfying its value or using the new operator to construct a new object and replace its original. These changes are permanent as their values are that of the new objects when examined outside the method.
What is confusing me greatly is that although i can change a Containers inner object via methods, I cannot actully change the container itself. By this i mean that if i pass a container to a method and try to alter it via swapping or assignment from the new operator.
Below is the code i use to test the modification of an object instances attributes and then modification of the actual instance itself.
class InsideRef{
char myChar;
InsideRef(char newVal){
myChar = newVal;
}
}
class Container{
InsideRef myInRef = null;
int myPrimitive = 0;
Container(char innerChar, int innerPrim){
myInRef = new InsideRef(innerChar);
this.myPrimitive = innerPrim;
}
public void myDetails(){
System.out.format("Container.%s => myPrimitive -> %d || myInRef => %s -> %c.%n",
this.hashCode(),this.myPrimitive,this.myInRef.hashCode(),this.myInRef.myChar);
}
}
class AttribRefModder{
public static void ModObjRefVal(Container toEdit){
toEdit.myInRef.myChar = 'Z';
}
public static void ModNewObjReference(Container toEdit){
toEdit.myInRef = new InsideRef('Y');
}
}
class RefSwapper{
public static void RefSwap(Container A, Container B){
System.out.println("Swapping....");
System.out.print("OBJECT A -> ");
A.myDetails();
System.out.print("OBJECT B -> ");
B.myDetails();
Container temp = A;
A = B;
B = temp;
System.out.print("SWAPPED A -> ");
A.myDetails();
System.out.print("SWAPPED B -> ");
B.myDetails();
System.out.println("Exiting....");
}
public static void RefNew(Container A){
System.out.println("Assigning Reference New Object....");
A = new Container('V',999);
System.out.print("NEW C REF -> ");
A.myDetails();
System.out.println("Exiting....");
}
}
public class ReferenceModding{
public static void main(String[] args){
System.out.println("-----------MODDING INNER REFS----------");
Container C1 = new Container('A', 111);
System.out.print("ORIGINAL A -> ");
C1.myDetails();
AttribRefModder.ModObjRefVal(C1);
System.out.print("MODDED A.Ref -> ");
C1.myDetails();
AttribRefModder.ModNewObjReference(C1);
System.out.print("NEW A.Ref -> ");
C1.myDetails();
System.out.println("----------SWAPPING REFERENCES----------");
Container C2 = new Container('B',222);
RefSwapper.RefSwap(C1, C2);
System.out.print("OBJECT A -> ");
C1.myDetails();
System.out.print("OBJECT B -> ");
C2.myDetails();
System.out.println("----------ASSIGN NEW OBJECTS----------");
Container C3 = new Container('C',333);
System.out.print("OBJECT C -> ");
C3.myDetails();
RefSwapper.RefNew(C3);
System.out.print("OBJECT C -> ");
C3.myDetails();
}
}
I apologise if this is too much code i have posted. It's just i've been playing with Java all day and this object parameter business has really confused me. I cant work out why Java methods allows me to edit and assign a new object to the InsideRef refrences that are held inside a container class but do not allow me to perform the same operations on the actual container classes.
Thanks for any help you may be able to provide.
You have stated the characteristic of Java correctly.
Under the covers, you pass a reference -- a memory address is a good model -- of an object. So you can change anything referred to by that reference.
But you cannot change what the caller thinks of as "that object" -- the caller has a memory address containing the address passed to you, and you cannot change that. So regardless of what you do, you cannot change which object is referred to, only what is 'inside' that object.
I think the confusion comes from this part in RefSwap:
Container temp = A;
A = B;
B = temp;
In Java, this only affects the variables A and B within that method. It won't change what objects A and B point to when the method returns to the location where it was called from. So in main the objects C1 and C2 still refer to the same Container objects, these are not swapped around.
Parameter passing in java is always by value. This meaning that having a parameter in the left side of an assignment has no effect at all outside the method call; it just changes the value of the reference (pointer) you copied on the method call stack, so you have lost that value for the rest of the method.
For example, PL/SQL has a true parameter passing by reference, if you declare there
-- True pass-by-reference
procedure my_procedure(my_integer out integer) is
begin
my_integer := 6;
end;
You will see after the procedure call that the integer you passed there has changed its value. However, java does not support this parameter passing. Think of something like this in C:
// Just stepping on the values on the method call stack
void my_function(int* my_integer) {
my_integer = 0;
}
Does this change the value of the integer referenced by the pointer? No, it just crunches the pointer value. This is what you do with your
A = new Container('V',999);
I hope this has been of any help to you :)
When i pass this "Container" object to methods
The first thing you need to understand is it's not possible to "pass" an "object". The only types in Java are primitive types and reference types. That means every value is either a primitive or a reference. A "reference" is a pointer to an object. The type Container is a reference type -- it is the type of a pointer to an object, specifically, a pointer to instances of the class Container.

Java, pass-by-value, reference variables

I have a problem with understanding the "pass-by-value" action of Java in the following example:
public class Numbers {
static int[] s_ccc = {7};
static int[] t_ccc = {7};
public static void calculate(int[] b, int[] c) {
System.out.println("s_ccc[0] = " + s_ccc[0]); // 7
System.out.println("t_ccc[0] = " + t_ccc[0]); // 7
b[0] = b[0] + 9;
System.out.println("\nb[0] = " + b[0]); // 16
c = b;
System.out.println("c[0] = " + c[0] + "\n"); // 16
}
public static void main(String[] args) {
calculate(s_ccc, t_ccc);
System.out.println("s_ccc[0] = " + s_ccc[0]); // 16
System.out.println("t_ccc[0] = " + t_ccc[0]); // 7
}
}
I know that because s_ccc is a reference variable, when I give it to the method calculate() and I make some changes to its elements in the method, the changes remain even after I leave the method. I think that the same should be with t_ccc. It is again
a reference variable, I give it to the method calculate(), and in the method I change the referece to t_ccc to be that of s_ccc. Now t_ccc should be a reference variable pointing to an array, which has one element of type int equals to 16. But when the method calculate() is left, it seems that t_ccc points its old object. Why is this happening? Shouldn't the change remain for it, too? It is a reference variable after all.
Regards
There's an extended discussion of how Java passes variables at an earlier question "Is Java pass by reference?". Java really passes object references by value.
In your code, the references for the arrays (which are objects) are passed into calculate(). These references are passed by value, which means that any changes to the values of b and c are visible only within the method (they are really just a copy of s_ccc and t_ccc). That's why t_ccc in main() was never affected.
To reinforce this concept, some programmers declare the method parameters as final variables:
public static void calculate(final int[] b, final int[] c)
Now, the compiler won't even allow you to change the values of b or c. Of course, the downside of this is that you can no longer manipulate them conveniently within your method.
Here's a simple way to understand it.
Java always passes copies of arguments. If the argument is a primitive type (e.g. an integer), then the called method gets a copy of the primitive value. If the argument is a reference type, then the called method gets a copy of the reference (not a copy of the thing referred to).
When your main method begins, each of s_ccc and t_ccc refers to a distinct array.
This is the situation, where parentheses indicate variables and square brackets indicate the actual array structures:
(s_ccc) ---> [7]
(t_ccc) ---> [7]
Assuming that you meant calculate(s_ccc, t_ccc), then at the beginning of the calculate method:
(s_ccc) ---> [7] <---(b)
(t_ccc) ---> [7] <---(c)
Locals b and c are copies of globals s_ccc and t_ccc respectively.
Still within calculcate, after b[0] = b[0] + 9 has completed:
(s_ccc) ---> [16] <---(b)
(t_ccc) ---> [7] <---(c)
The zero (only) position in the array referred to by b has been modified.
The assignment c = b within calculate produces this situation:
(s_ccc) ---> [16] <---(b)
^------(c)
(t_ccc) ---> [7]
The local reference variable c, now contains the same reference as b. That has no effect on the global reference variable t_ccc, which still refers to the same array as before.
When calculate exits, its local variables (on the right-hand side of the diagrams) disappear. The global variables (on the left-hand side) were not used in calculate, so they are unaffected. The final situation is:
(s_ccc) ---> [16]
(t_ccc) ---> [7]
Neither c_ccc nor t_ccc were changed; each still refers to the same array as before calculate. Calling calculate changed the content of the array referenced by s_ccc, using a copied reference to that array (in b).
Local variable c started as a copy of t_ccc and was manipulated within calculate, but that changed neither t_ccc itself nor it's referenced data.
The method receives variables by value. Those values can't be changed (as far as the caller of the method sees), but the values contained within them can (if it's an object, or as in this case, an array).
So when you change the value b[0] inside the array, the change can be seen outside the method. However the line
c = b;
will change the value of c inside the method, but that change will not be seen outside the method, since the value of c was passed by value.
The line calculate(s_ccc, s_ccc); indicates you're not actually doing anything to t_ccc.
However, should this line have read calculate(s_ccc, t_ccc); than the effect remains the same.
This is due to the fact that you're assigning a new value to c here: c = b;
When assigning a new value to a reference argument the reference is lost.
This is the difference between altering a by reference variable and assigning a new value.
On entry to calculate(), b points at s_ccc and c points at t_ccc. Altering b[0] will therefore change s_ccc, as you've seen.
However, the assignment
c = b;
only points c at the same object b is pointing at, namely s_ccc. It does not copy the contents of what b points to to what c points to. As a result, t_ccc is unchanged. If you added the following line to the end of calculate():
c[0] = c[0] + 5;
s_ccc[0] would be 21.

Categories