Remove reference and change static variables within a method - java

Let's say we got an object and a static variable that counts the generated objects
variable = new Foo();
Foo.getObjCounter(); // -> 1
Is there a way in java to put this code:
variable = null;
Foo.decreaseFooCounter();
Into one method such as:
variable.delete();
Foo.getFooCounter(); // -> 0
or
Foo.delete(variable);
Foo.getFooCounter(); // -> 0

You can achieve such behaviour by using WeakReferences or more specific a Set backed by a WeakHashMap. See the following example:
class Foo {
private static final Set<Foo> references = Collections.newSetFromMap(new WeakHashMap<>());
public Foo() {
references.add(this); // register ourselves
}
public static int getFooCounter() {
return references.size();
}
// rest of the methods
}
Though the reference to the created Foo will only be removed if they have been free'd up by the garbage collector. To quote the doc:
[...] Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object [...]

Related

GC in Java Setter

In a Java setter method that assigns a new Object to a field such as:
public class MyClass
{
private String s;
public void mySetter(String newS) {
s = newS;
}
}
Does the previous String s get garbage collected after mySetter is called or should I null out s before I assign it to the new value?
public class MyClass
{
private String s;
public void mySetter(String newS) {
s = null;
s = newS;
}
}
Does the previous String s get garbage collected after mySetter is called or should I null out s before I assign it to the new value?
If your previous String s is not referenced anywhere then it will be. But it won't happen immmedialtely after mySetter is called. No need to set it to null.
no need to null out, the garbage collector will find the string if no one else references it.
You don't have to do s = null; part. In Java a variable is in fact a reference to physical object in RAM memory. So when you do s = newS; you make a variable s point to a new object in RAM and the old object is no longer referenced by any of your variables and will be garbage collected.
Garbage collection will only happen when memory space is required by JVM
so in your case it will not be garbage collected as soon as your method gets called.
for more already an answer here
Also while assigning string to another value, you need not to set it to null first, as when you assign a new value to string means that now your reference variable is not pointing to previous value of the String object but to the new one and Java provides you the flexibility of not worrying about GC like other programming language. So don't try doing GC, Java can take care of it for you

Is it possible to set to null an instance of a class within the class

Is it possible to set to null an instance of a class within the class. For example, could I do something like this
int main{
//Create a new test object
Test test = new Test();
//Delete that object. This method should set the object "test" to null,
//thus allowing it to be called by the garbage collector.
test.delete();
}
public class Test{
public delete(){
this = null;
}
}
I have tried this and it does not work. Using "this = null" I get the error that the left hand side needs to be a variable. Is there a way to achieve something similar?
An instance of an object doesn't know which references might be referring to it, so there's no way that code within the object can null those references. What you're asking for isn't possible(*).
* at least not without adding a pile of scaffolding to keep track of all the references, and somehow inform their owners that they should be nulled - in no way would it be "Just for convenience".
You can do something like this
public class WrappedTest {
private Test test;
public Test getTest() { return test; }
public void setTest(Test test) { this.test = test; }
public void delete() { test = null; }
}
"this" is a final variable. you can not assign any values to it.
If you want to set the reference null you can do this
test = null;
this is a reference to the instance of your class. When you modify a reference variable, it only modifies that reference and nothing else. For example:
Integer a = new Integer(1);
Integer b = a;
a = new Integer(2); //does NOT modify variable b
System.out.println(b); //prints 1
Is it possible to set to null an instance of a class within the class?.
You cannot do this from the member methods of the same instance. So, this=null or that sort of thing will not work.
How come one set an instance to an null?
That question itself is wrong, we set references to null but not instances. Unused objects automatically garbage collected in java.
If you set test=null it will eventually gets garbage collected.
int main{
//Create a new test object
Test test = new Test();
// use the object through test
test=null;
}

How long do my static variables live?

I have a class that looks like:
public class BadCodeStyle {
private static String theAnswer = null;
public static void setAnswer(String whatsNew) {
theAnswer = whatsNew;
}
public static String getAnswer() {
return (theAnswer == null) ? "I don't know" : theAnswer;
}
}
Of course that's a simplification of the actual class. What really happens is that the static method retrieves a framework object if the variable is null. Setting the variable just serves to insert a mock value for test runs where I want to isolate the code from the framework (retrofitting code for testability is fun - like poking your own eye type of fun).
When I do BadCodeStyle.setAnswer("42") the static method behaves like a Singleton (?). I did read the classloader explanation and conclude: the variable will stay as long as the class is loaded and that would be as long as the JVM runs? Is that correct?
Static class variables live as long as the class definition is loaded. This is usually until the VM exits. However, there are other ways a class can be unloaded. See, for example, this thread and this one.
Static variables are common to all objects (shared) more precisely. it doesn't belong to any instance of class (objects). so its obvious that it cannot be garbage collected with objects.
class X
{
static string str;
}
X obj1 = new X();
X obj2 = new X();
when you define X.str compiler 'll say replace with Class reference.
But it belongs to Class object. we refer to it as Class variable too. (classloader loads the class)
so its single variable (singleton 's actually a pattern that uses single object [use private constructors and using a method to return that single object] )
As you read the memory is reclaimed only when the program is done. it doesn't get (reclaimed) garbage collected in between [Non used objects 'll be garbage collected normally] .
so its lifetime exists as long as the process exists [program is running].
checkout lifetime of variables: www.cs.berkeley.edu/~jrs/4/lec/08

Can you safely synchronize on a Java method parameter?

Take this code:
public class MyClass {
private final Object _lock = new Object();
private final MyMutableClass _mutableObject = new MyMutableClass()
public void myMethod() {
synchronized(_lock) { // we are synchronizing on instance variable _lock
// do something with mutableVar
//(i.e. call a "set" method on _mutableObject)
}
}
}
now, imagine delegating the code inside myMethod() to some helper class where you pass the lock
public class HelperClass {
public helperMethod(Object lockVar, MyMutableClass mutableVar) {
synchronized(lockVar) { // we are now synchronizing on a method param,
// each thread has own copy
// do something with mutableVar
// (i.e. call a "set" method on mutableVar)
}
}
}
can "myMethod" be re-written to use the HelperClass by passing its lock var, so that everything is still thread safe? i.e.,
public void myMethod() {
_helperObject.helperMethod(_lock, _mutableObject);
}
I am not sure about this, because Java will pass the lockVar by value, and every thread will get a separate copy of lockVar (even though each copy points to the same object on the heap). I guess the question comes down to how 'synchronized' keyword works -- does it lock on the variable, or the value on the heap that the variable references?
Synchronization is done upon objects, not variables.
Variables/members [sometimes] contain objects and it is the resulting object contained in [variable] x that is actually synchronized upon in synchronized(x).
There are a few other issues with thread-visibility of variables (e.g. might read a "stale" object from a variable), but that does not apply here: there is no re-assignment of _lock and the visibility of the initial ("final") assignment is guaranteed. Because of this it is guaranteed that, in this case, the method parameter will always contain the correct (same) object used for the synchronization.
If the lock object used (where presumably _lock is not final) changes, however, then that would require re-evaluation of the appropriate values/thread-visibility but otherwise does not differ from any cross-thread access.
Happy coding.

Java memory allocation on stack vs heap

I feel like a novice for asking this question -- but why is it that when I pass the Set below into my method and point it to a new HashSet, it still comes out as the EmptySet? Is it because local variables are allocated on the stack, and so my new is blown away when I exit the method? How could I achieve the functional equivalent?
import java.util.HashSet;
import java.util.Set;
public class TestMethods {
public static void main(final String[] args) {
final Set<Integer> foo = java.util.Collections.emptySet();
test(foo);
}
public static void test(Set<Integer> mySet) {
mySet = new HashSet<Integer>();
}
}
Java passes references by value, think of mySet as just a copy of the foo reference. In void test(Set<Integer> mySet) , the mySet variable is just a local variable within that function, so setting it to something else doesn't affect the caller in main.
mySet does reference(or "point to" if you like) the same Set as the foo variable does in main though.
If you want to alter the reference in main, you could do e.g.:
foo = test(); //foo can't be final now though
public static Set<Integer> test() {
return new HashSet<Integer>();
}
... Is it because local variables are allocated on the stack, and so my new is blown away when I exit the method?
No. It is because of the argument passing semantics of Java.
Java arguments are passed "by value", but in the case of an object or array type, the value you are passing is the object/array reference. When you create and assign a new set object to mySet, you are simply setting the local variable / parameter. Since Java uses pass by value, this has no effect on the foo variable in the main method.
When you enter the test method, you have two copies of the reference to the HashSet instance created in the main method; one in foo and one in mySet. Your code then replaces the reference in mySet with a reference to a newly created HashSet, but this new reference doesn't get passed back to the caller. (You could change your code to pass it back ... for example as the result of the test method. But you have to do this explicitly.)
OK - however -- if I were to do add or some other operation within my method call, that allocation would be preserved. Why is that?
That is because when you call an instance method using the reference in foo or mySet, that method is executed on the object (HashSet) that the reference refers to. Assuming that the two references point to the same object, your "allocation will be preserved". Or more precisely, you can observe the effects of operations on one reference to an object via operations on other references to the same object.
Just remember that Java method calls copy references to object, not the objects themselves.
By the way you won't be able to add elements to a set returned by Collections.emptySet(). That set object is immutable. Calling (for example) add on it will throw an exception.
Your 'foo' referred to an empty set going into the test() call, the test call did not modify that object, and so it's still an empty set on return from there.
Within the test() method, 'mySet' is just a local reference, which refers to the original set (foo) on entry, and when you did the assignment of a new HashSet to that reference, you lost the reference to the original set. But these effects are all entirely local to the test() method, because java simply gave test() a duplicate of the reference to the original set.
Now, within test(), since you have a reference to the original object, you can modify that object. For instance, you could add elements to that set. But you can't change the reference in the calling function, you can only change what it refers to. So you can't replace the one collection with a different one, and if you wanted a HashSet in the first place, you'd have to new the HashSet in main().
Not sure I understand the question. In the test method, you are instantiating a new set and assigning it to the local mySet variable. mySet then no longer will reference the same set as foo does back in Main.
When you return from the method, foo still references the original emptySet() and the HashSet created in the method will be marked for garbage collection.
import java.util.HashSet;
import java.util.Set;
public class TestMethods {
public static void main(final String[] args) {
final Set<Integer> foo = java.util.Collections.emptySet();
test(foo);
}
public static void test(Set<Integer> mySet) {
// here mySet points to the same object as foo in main
mySet = new HashSet<Integer>();
// mySet now points to a new object created by your HashSet constructor call,
// any subsequent operations on mySet are no longer associated with foo, because
// they are no longer referencing the same object
}
}
How could I achieve the functional
equivalent?
I am not sure if I understand this question, are you looking for a return?
public static Set<Integer> test(Set<Integer> mySet) {
for(Integer i : mySet){
// do something??
}
mySet = new HashSet<Integer>();
return mySet;
}
Now, if you assign foo to what test returns, you have the "functional equivalent"?
you should read this book:
"A Programmer's Guide to Java SCJP Certification: A Comprehensive Primer (3rd Edition)"

Categories