I know Java doesn't have pointers, but I heard that Java programs can be created with pointers and that this can be done by the few who are experts in java. Is it true?
All objects in Java are references and you can use them like pointers.
abstract class Animal
{...
}
class Lion extends Animal
{...
}
class Tiger extends Animal
{
public Tiger() {...}
public void growl(){...}
}
Tiger first = null;
Tiger second = new Tiger();
Tiger third;
Dereferencing a null:
first.growl(); // ERROR, first is null.
third.growl(); // ERROR, third has not been initialized.
Aliasing Problem:
third = new Tiger();
first = third;
Losing Cells:
second = third; // Possible ERROR. The old value of second is lost.
You can make this safe by first assuring that there is no further need of the old value of second or assigning another pointer the value of second.
first = second;
second = third; //OK
Note that giving second a value in other ways (NULL, new...) is just as much a potential error and may result in losing the object that it points to.
The Java system will throw an exception (OutOfMemoryError) when you call new and the allocator cannot allocate the requested cell. This is very rare and usually results from run-away recursion.
Note that, from a language point of view, abandoning objects to the garbage collector are not errors at all. It is just something that the programmer needs to be aware of. The same variable can point to different objects at different times and old values will be reclaimed when no pointer references them. But if the logic of the program requires maintaining at least one reference to the object, It will cause an error.
Novices often make the following error.
Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed.
What you probably meant to say was:
Tiger tony = null;
tony = third; // OK.
Improper Casting:
Lion leo = new Lion();
Tiger tony = (Tiger)leo; // Always illegal and caught by compiler.
Animal whatever = new Lion(); // Legal.
Tiger tony = (Tiger)whatever; // Illegal, just as in previous example.
Lion leo = (Lion)whatever; // Legal, object whatever really is a Lion.
Pointers in C:
void main() {
int* x; // Allocate the pointers x and y
int* y; // (but not the pointees)
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
*y = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
*y = 13; // Dereference y to store 13 in its (shared) pointee
}
Pointers in Java:
class IntObj {
public int value;
}
public class Binky() {
public static void main(String[] args) {
IntObj x; // Allocate the pointers x and y
IntObj y; // (but not the IntObj pointees)
x = new IntObj(); // Allocate an IntObj pointee
// and set x to point to it
x.value = 42; // Dereference x to store 42 in its pointee
y.value = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
y.value = 13; // Deference y to store 13 in its (shared) pointee
}
}
UPDATE: as suggested in the comments one must note that C has pointer arithmetic. However, we do not have that in Java.
As Java has no pointer data types, it is impossible to use pointers in Java. Even the few experts will not be able to use pointers in java.
See also the last point in: The Java Language Environment
Java does have pointers. Any time you create an object in Java, you're actually creating a pointer to the object; this pointer could then be set to a different object or to null, and the original object will still exist (pending garbage collection).
What you can't do in Java is pointer arithmetic. You can't dereference a specific memory address or increment a pointer.
If you really want to get low-level, the only way to do it is with the Java Native Interface; and even then, the low-level part has to be done in C or C++.
There are pointers in Java, but you cannot manipulate them the way that you can in C++ or C. When you pass an object, you are passing a pointer to that object, but not in the same sense as in C++. That object cannot be dereferenced. If you set its values using its native accessors, it will change because Java knows its memory location through the pointer. But the pointer is immutable. When you attempt to set the pointer to a new location, you instead end up with a new local object with the same name as the other. The original object is unchanged. Here is a brief program to demonstrate the difference.
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
System.out.println("Expected # = 0 1 2 2 1");
Cat c = new Cat();
c.setClaws(0);
System.out.println("Initial value is " + c.getClaws());
// prints 0 obviously
clawsAreOne(c);
System.out.println("Accessor changes value to " + c.getClaws());
// prints 1 because the value 'referenced' by the 'pointer' is changed using an accessor.
makeNewCat(c);
System.out.println("Final value is " + c.getClaws());
// prints 1 because the pointer is not changed to 'kitten'; that would be a reference pass.
}
public static void clawsAreOne(Cat kitty) {
kitty.setClaws(1);
}
public static void makeNewCat(Cat kitty) {
Cat kitten = new Cat();
kitten.setClaws(2);
kitty = kitten;
System.out.println("Value in makeNewCat scope of kitten " + kitten.getClaws());
//Prints 2. the value pointed to by 'kitten' is 2
System.out.println("Value in makeNewcat scope of kitty " + kitty.getClaws());
//Prints 2. The local copy is being used within the scope of this method.
}
}
class Cat {
private int claws;
public void setClaws(int i) {
claws = i;
}
public int getClaws() {
return claws;
}
}
This can be run at Ideone.com.
Java does not have pointers like C has, but it does allow you to create new objects on the heap which are "referenced" by variables. The lack of pointers is to stop Java programs from referencing memory locations illegally, and also enables Garbage Collection to be automatically carried out by the Java Virtual Machine.
You can use addresses and pointers using the Unsafe class. However as the name suggests, these methods are UNSAFE and generally a bad idea. Incorrect usage can result in your JVM randomly dying (actually the same problem get using pointers incorrectly in C/C++)
While you may be used to pointers and think you need them (because you don't know how to code any other way), you will find that you don't and you will be better off for it.
Technically, all Java objects are pointers. All primitive types are values though. There is no way to take manual control of those pointers. Java just internally uses pass-by-reference.
Not really, no.
Java doesn't have pointers. If you really wanted you could try to emulate them by building around something like reflection, but it would have all of the complexity of pointers with none of the benefits.
Java doesn't have pointers because it doesn't need them. What kind of answers were you hoping for from this question, i.e. deep down did you hope you could use them for something or was this just curiousity?
All objects in java are passed to functions by reference copy except primitives.
In effect, this means that you are sending a copy of the pointer to the original object rather than a copy of the object itself.
Please leave a comment if you want an example to understand this.
As others have said, the short answer is "No".
Sure, you could write JNI code that plays with Java pointers. Depending on what you're trying to accomplish, maybe that would get you somewhere and maybe it wouldn't.
You could always simulate pointes by creating an array and working with indexes into the array. Again, depending on what you're trying to accomplish, that might or might not be useful.
from the book named Decompiling Android by Godfrey Nolan
Security dictates that pointers aren’t
used in Java so hackers can’t break out of an application and into the operating
system. No pointers means that something else----in this case, the JVM----has to
take care of the allocating and freeing memory. Memory leaks should also
become a thing of the past, or so the theory goes. Some applications written in
C and C++ are notorious for leaking memory like a sieve because programmers
don’t pay attention to freeing up unwanted memory at the appropriate time----not
that anybody reading this would be guilty of such a sin. Garbage collection
should also make programmers more productive, with less time spent on
debugging memory problems.
Java reference types are not the same as C pointers as you can't have a pointer to a pointer in Java.
you can have pointers for literals as well. You have to implement them yourself. It is pretty basic for experts ;). Use an array of int/object/long/byte and voila you have the basics for implementing pointers. Now any int value can be a pointer to that array int[]. You can increment the pointer, you can decrement the pointer, you can multiply the pointer. You indeed have pointer arithmetics!
That's the only way to implements 1000 int attributes classes and have a generic method that applies to all attributes. You can also use a byte[] array instead of an int[]
However I do wish Java would let you pass literal values by reference. Something along the lines
//(* telling you it is a pointer)
public void myMethod(int* intValue);
You can, but not completely. You can't directly access pointers but you can have lists with variables that point to the same location. I came across a way by accident a few years ago.
I'm not sure why but in Java when you set a list to equal another list, rather than copying all the information, a pointer to the original list is made. I'm not sure if it applies to all forms of lists, but it has for the ones I have tested so far. I believe arrayList also has the function clone(), to circumvent this, if you wanted a proper seperate list.
int[] example
public class Main {
public static void main(String[] args){
int[] alpha = new int[] {1,2,3};
int[] beta = alpha;
beta[0]=9;
beta[1]=9;
beta[2]=9;
System.out.println("alpha: " + alpha[0] + ", " + alpha[1] + ", " + alpha[2]);
System.out.println("-beta: " + beta[0] + ", " + beta[1] + ", " + beta[2]);
}
}
arrayList example
import java.util.ArrayList;
public class Main {
public static void main(String[] args){
ArrayList<Integer> alpha = new ArrayList<>();
alpha.add(1);
alpha.add(2);
alpha.add(3);
ArrayList<Integer> beta = alpha;
beta.add(4);
beta.set(0, 5);
System.out.println("alpha: " + alpha.toString());
System.out.println("-beta: " + beta.toString());
}
}
All java objects are pointer because a variable which holds address is called pointer and object hold address.so object is pointer variable.
java can easily has pointer by knowing that the array name is pointer to the the first index. this why when we pass array to function we don't write its square brackets. because array is reference
public class Main
{
public static void func ( int ptr1[] , int ptr2[] )
{
int temp;
temp = ptr1[0];
ptr1[0] = ptr2[0];
ptr2[0] = temp;
}
public static void main(String[] args) {
int x = 5; int y = 8;
// in c language
// int *p = &x; int *q = &y;
// in Java
int p[] = new int[1];
int q[] = new int[1];
p[0] = x; // same as pointer
q[0] = y; // same as pointer
func( p , q ); // passing address ( refrence )
System.out.println( " After Swap " );
System.out.println( "x = " + p[0] + " " + "y = " + q[0] );
}
}
Related
I'm reading section 12.6.1 of Java SE specs and it said:
Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a Java compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.
Another example of this occurs if the values in an object's fields are stored in registers. The program may then access the registers instead of the object, and never access the object again. This would imply that the object is garbage. Note that this sort of optimization is only allowed if references are on the stack, not stored in the heap.
The relevant code is:
class Foo {
private final Object finalizerGuardian = new Object() {
protected void finalize() throws Throwable {
/* finalize outer Foo object */
}
}
}
My question is what kind of JVM would ever store finalizerGuardian in the stack not the heap and why?
The code example is for illustrating the last sentence of your cited text, “Note that this sort of optimization is only allowed if references are on the stack, not stored in the heap” and it is a bit odd that you ripped it off the explaining text:
For example, consider the Finalizer Guardian pattern:
class Foo {
private final Object finalizerGuardian = new Object() {
protected void finalize() throws Throwable {
/* finalize outer Foo object */
}
}
}
The finalizer guardian forces super.finalize to be called if a subclass overrides finalize and does not explicitly call super.finalize.
If these optimizations are allowed for references that are stored on the heap, then a Java compiler can detect that the finalizerGuardian field is never read, null it out, collect the object immediately, and call the finalizer early. This runs counter to the intent: the programmer probably wanted to call the Foo finalizer when the Foo instance became unreachable. This sort of transformation is therefore not legal: the inner class object should be reachable for as long as the outer class object is reachable.
So the code example illustrates a restriction. The “optimizing transformations” mentioned by the specification includes Object Scalarization applied after Escape Analysis has proven that an object is purely local, in other words, the code under optimization spans the entire lifetime of the object.
But it doesn’t need such local objects. As the specification already mentioned, optimized code may keep an object’s fields in CPU registers without the need to re-read them, thus, does not need to keep the object reference anymore. Likewise, a reference variable still in scope may be unused. If that reference was the only reference to an object, removing it from the optimized code allows earlier garbage collection.
Both scenarios would still allow a Foo instance to get eliminated or collected earlier. This in turn would allow the earlier collection of the object (not anymore) referenced by finalizerGuardian. But that doesn’t counteract the intention of this restriction. The specification restricts the optimization to not allow the inner object to get collected earlier than the outer object, but there is no problem in collecting both together, including earlier than naively expected.
Generally, arbitrarily large object graphs may get collected in a single garbage collection cycle, perhaps earlier than naively expected, or even get optimized away completely.
a classic example for such kind of optimization (escape analysis) is a calculation with Point class:
class Point {
double x;
double y;
public Point(final double x, final double y) {
this.x = x;
this.y = y;
}
double length() {
return Math.sqrt(x * x + y * y);
}
static double calc() {
double result = 0;
for (int i = 0; i < 100; i++) {
// this allocation will be optimized
Point point = new Point(i, i);
result += point.length();
}
return result;
}
}
after inlining this new will be not needed because we can extract all fields to local variables like
Point point = new Point(i, i);
double x = point.x;
double y = point.y;
result += Math.sqrt(x * x + y * y);
->
Point point = new Point(i, i);
double x = i;
double y = i;
result += Math.sqrt(x * x + y * y);
now it's obvious that new Point(i, i) is useless and JIT just remove this line.
Note that the allocation was on stack i.e. in a local variable. If it was in a field we'd not be able do that optimization because it's stored in the heap.
That how it works.
about your code snipped: the finalizerGuardian will always in the field (stored in the heap) and JVM can do nothing with this allocation. Furemore if the class Point from the example above contains such field, i think escape analys is not able to remove the allocation because it might change the original behaviour.
I understand that passing an array to a method is still Pass-By-Value, however the "value" that is passed is the reference of the array. This implies that changing the contents of the array would cause the contents to get updated in an earlier frame (if it's a recursive algorithm), or when it goes back to the main method, for that matter.
import java.util.Arrays;
public class SameArrayPassedOn{
public static void main(String[] args) {
int[] a = {1,1,1};
print(a);
fun(a,0);
print(a);
}
static void fun(int[] b, int count)
{
if(count == 1)
return;
b[0] = b[1] = b[2] = 2;
fun(b,1);
}
static void print(int[] a)
{
for(int x : a)
System.out.print(x + " ");
System.out.println("");
}
}
Output 111 222
However, if you create a new array, like for example, in the code below, since the reference is changed, the updates won't be reflected when you go back to the main method.
import java.util.Arrays;
public class NewArrayCreatedAndReferencePassedOn{
public static void main(String[] args) {
int[] a = {1,1,1};
print(a);
fun(a,0);
print(a);
}
static void fun(int[] b, int count)
{
if(count == 1)
return;
int[] newb = {2,2,2};
fun(newb,1);
}
static void print(int[] a)
{
for(int x : a)
System.out.print(x + " ");
System.out.println("");
}
}
Output 111 111
However, my question is, why such a design was chosen for Arrays. Why couldn't it be that, just like for a primitive data type, say, integer variable, a new int is created every time it's passed inside a function, although we are not explicitly creating a new int, or declaring one. Like for example,
import java.util.Arrays;
public class SameIntPassedOn_ButNewCopyCreatedEachFrame {
public static void main(String[] args) {
int i = 0;
fun(i);
}
static void fun(int b)
{
System.out.println(b);
if(b == 10)
return;
b = b+1;
fun(b);
System.out.println(b);
}
}
Output
0 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1
Had the same been done for arrays, it would've allowed us to have a different copy of the array for each frame of the recursive function, which would've been very handy.
I think it would've been nice to have uniformity in behavior, because at the moment, it looks as though, to achieve the same behavior with Arrays, as is exhibited by primitive data types, such as int, float etc, when passed to a method, it is necessary to use a 'new' keyword, and create a new array before passing on to the method.
However, my question is, why such a design was chosen for Arrays.
There are several main reasons.
The first is performance - it would lead to extremely poor performance if a new copy of the array had to be created every single time a method was called on it, especially for recursive calls.
Had the same been done for arrays, it would've allowed us to have a
different copy of the array for each frame of the recursive function,
which would've been very handy.
The second is that you already have the option of passing a copy of the array if you want to - you can create a copy manually and pass that. This way the programmer has the most control - they can choose to let method calls modify the array, or they can choose to pass a copy, allowing each method call its on version of the array to work with. If we forced the programmer to use a copy all the time, they would lose the option of letting method calls modify the array, which can be extremely useful in some situations. The current design gives the programmer the most options.
Why couldn't it be that, just like for a primitive data type...
The last reason is that an array is not a primitive data type - it is an object. The decision was most likely made to make arrays as consistent as possible with the way other objects in Java behave.
The answer is that all objects, in fact all method arguments are passed by value. Your assessment "Had the same been done for arrays" is wrong because the same is done for arrays. Arrays, like all object references, are passed by value. The copy of a primitive value sent to a method is the same value the caller passed. The copy of an array pointer sent to a method is the same value the caller passed. The copy of any object pointer sent to a method is the same value the caller passed.
It points to the same object, because the pointer is copied by value.
Why, you ask? Because it's simple, it's valid, and really has no downside.
Array is a container (data structure) that hold a set of objects.
Those objects could be huge or small. and the array could contain many objects
imagine with each array reference we do full copy
the language will be extremely slow and inefficient
So the main reason for this is the efficiency
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
I have a list of Cell object that represent a board game inside the board class.
Cell boardGame[][] = new Cell[8][8];
I needed a temporary cell to try the player move on him and compare it to the other cells, so I though that I could use a java pass-by-value to do it.
test(board.boardGame);
board.printBoard();
private static void test(Cell[][] boardGame) {
Cell c = new Cell((new Soldier(ChessPiece.QUEEN, Color.WHITE)), 7, 4);
boardGame[7][7] = c;
}
I read some post about java here, but apparently I still didn't catch it 100%.
I expected to see only one white queen on the board, but I saw two.
I know that if you pass a reference you can change its values, but I though that if I would pass the array itself its members won't be modified unless I would execute a return.
Please help me to understand this subject better.
Thanks
Edit:
I think I don't understand when it called attributes and where it doesn't.
I though the different it if you are call "new" or not.
When its part of another object it called attribute right? but every object can be created as part of another object. I can create a new string in dog class and then create the dog class in the animal class and then create it in another class. So only the top class is in the stack?
For exemple:
public class Board { //fake class
int num= 0;
public void test(int i){
i = 1;
}
}
and on another class:
public class Main {
static void outsideTest(Board board){
board.num = 1;
}
public static void main(String[] args) {
Board board = new Board();
System.out.println(board.num);
board.test(board.num);
System.out.println(board.num);
outsideTest(board);
System.out.println(board.num);
}
}
Now I didn't understand why on test() method the num didn't change and on outsideTest() the num change, num as been created in the heap because its part of the board object, so its need to be changed on both cases no?
The best and least confusing way to remember it is as follows: Java passes everything by value, that includes the references. :)
When you have a variable:
Object a = new Object();
you don't actually have an object stored in a. What you have is a reference to an object somewhere in memory.
Likewise when you call a method on an object:
String b = a.toString();
you don't do that. What you call is a method that uses the data of the referenced object as its context.
So when you pass an object as an argument
System.out.println(b);
You don't pass the whole object. You pass the reference and that reference is passed by value.
edit:
If the reference were not passed by value, but by reference, you could do something like this, which fortunately you can't.
public void swap(Object a, Object b){
Object swap = a; a = b ; b = swap;
}
String a = "a";
String b = "b";
swap(a,b);
// would print "b a" if references were
// passed by reference but instead prints
// "a b" as they're passed by value.
System.out.println(a + " " b);
The reference to the object is passed by value, which means that
boardGame = new Cell[8][8];
does not do any harm, but changing anything you get from boardGame does.
Java is essentially always "pass-by-value".
Caveat: It passes the value stored in the memory for the variable.
For primitive data types, the memory is allocated in stack space, whereas for objects reference memory is allocated in stack space but the object itself is created in heap. Similar can be stated for arrays too though they are not exactly objects in a strong sense.
Diagrams below would make it clearer.
Your Cell object 2D array should seem something like anObjectArrayVar (not exactly as the ref in the diagram pointing to the objects should now be pointing to the rows and we would need another level of allocation in heap in between ref and objects for each row (a set of cells refering to the objects).
So, when you pass boardGame, the value stored in the stack is passed that stores the reference to the array of objects (just like the value stored in the anObjectArrayVar). If say the list of refs is stored in location numbered 50 then anObjectArrayVar would have stored that and it passes that value to the test method when we call it. In such a scenario the test method wont be able to goto memory location anObjectArrayVar and change its value (to say 100) as it has only a copy of the value but it could easily change what it refers to(directly or indirectly) like the values in ref or the next level (and add new objects as in your case adding a new cell with queen) or the objects pointed to by them and those changes would reflect through out the program!
I would also like to draw your attention to the fact that the code
boardGame[7][7] = c;
would replace the current cell (as well as the soldier currently in it) which would create major issues if there was originally a soldier in that place at that point in the game. The game state would actually change.
As a suggestion (given the limited knowledge about your design) I would say at least save the cell in some other value in test method before replacing it.
Cell old = boardGame[7][7];
//now do all your operations
boardGame[7][7] = old;//just before returning from the function
I'm a bit confused about information passing to methods in Java. I'm currently studying Java basics on Oracle website and while most things I understand with no problem, some things aren't clear enough to me.
https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
Here is where I'm having doubt. When they write the following code...
public void moveCircle(Circle circle, int deltaX, int deltaY) {
// code to move origin of circle to x+deltaX, y+deltaY
circle.setX(circle.getX() + deltaX);
circle.setY(circle.getY() + deltaY);
// code to assign a new reference to circle
circle = new Circle(0, 0);
}
What do they mean by circle = new Circle(0, 0);? Is it creating a new Cicle object or what? I think what confuses me is how the object parameter is used inside the method declaration.
Can someone explain to me clearly what Passing reference data types is about?
Start with a simpler example:
public class Main {
public static void main(String... args) {
int x = 7;
add(x);
System.out.println(x);
}
public static void add(int y){
y = 10;
}
}
What do you expect this code to print out?
It prints out 7 because even though we're reassigning the parameter received by the add() function, that doesn't affect the original value passed into the function. The x variable in the main() method is still 7.
The example code is just showing you a more complicated example of that with Objects instead of primitives. The lesson you're supposed to learn is that reassigning parameters in a function does not affect their original values.
These changes will persist when the method returns. Then circle is assigned a reference to a new Circle object with x = y = 0. This reassignment has no permanence, however, because the reference was passed in by value and cannot change.
Read the last paragraph carefully.
You are able to modify the attributes of the referenced circle, but if you assign the variable a new reference, no changes were made to the original object. It only tells myCircleto refer to a newly created object. And this object gets immediately garbage collected after the method goes out of scope.
Explanation for the two questions you asked:-
circle = new Circle(0, 0) means that we are assigning values to the constructor of Circle object .
Yes this is creating new circle object by passing values to the reference variable circle.
Hope it helps!
I was trying something, and I came across this interesting scenario. I just wanted to understand what is the major difference in these two snippets.
Initially, I took two sets, initialized one and assigned the reference to other. When I cleared set A, I noticed that Set B size changed to zero as well
Set<String> A = new HashSet<String>();
A.add("hello");
A.add("HEY");
A.add("hey");
Set<String > B = A;
System.out.println("initial sizes :" + A.size() + " " + B.size());
A.clear();
System.out.println("final sizes :" + A.size() + " " + B.size());
The output of this was something like this :
initial sizes :3 3
final sizes :0 0
Now, I tried to depict the same behavior for objects as follows:
Object a1 = new Object();
Object b1 = a1;
System.out.println("initial sizes :" + b1.toString() + " " + a1.toString());
a1 = null;
System.out.println("initial sizes :" + b1.toString() + " " + a1);
The output for this was something like :
initial sizes :java.lang.Object#54182d86 java.lang.Object#54182d86
initial sizes :java.lang.Object#54182d86 null
What is the exact difference here, I was expecting to get a NullPointerException when i tried to print b1.toString()
For primitives such as int, double, float etc, a copy of the value is made and that is passed by value:-
int x = 10;
public void foo(int k){
}
foo(x)
Here k will get a copy of the value stored in x so k will now have a value of 10. However, x and y are in two different memory locations. Changing the value of x will not change the value of k.
For object references a copy of the reference is made and that is passed by value (a reference is nothing more than the address of some memory). So in essence both references will now point to the same object (that is, the same memory location).
Myobject m = new Myobject();
public void bar (Myobject j){
}
bar(m)
A copy of the value of the reference m will be made and assigned to j. Both m and j will now point to the same object.
The difference here, is that a1 and b1 are not the objects themselves but references to those objects. So, if you modify the object referenced by a1 the object referenced by b1 (which is the same object) will change too. If however you tell a1 to point to another instance (or null in this case) it will no longer reference the same object so changes to that won't effect b1.
To go into a little more detail: Java is pass by value. However when you try to pass an object (rather than a primitive value) you're actually passing the value of the reference (also sometimes called the handle). That's why it can sometimes be a bit confusing when trying to determine whether Java is pass by handle or pass by reference.
Check this image. A2/A3 are REFERENCES to bojects. In first case these are references to Set (a1 on image). When one reference modifies object second reference sees the same change
On the other hand if you just set reference = null then you "erase one arrow" from the picture. The reference stops pointing to object, but the other reference still points to it.
You just noticed that java is completly pass by value, in which even references to other objects are passed as value.
If you null an object you are actually not nulling objects, which methods would be executed on the same object. You are only nulling the value of the reference to the object.
Check this example, you are just nulling the value of the reference on list 1, while you are still able to execute the methods on the original list.
ArrayList<Integer> list1 = new ArrayList<Integer>(0);
list1.add(1);
list1.add(2);
ArrayList<Integer> list2 = list1;
list1.clear();
list1 = null;
System.out.println(list2.size());
System.out.println(list1.size()); // will cause an nullpointerexception
The calls of methods on list1 does also effect list2, but nulling the object list1 wont affect the list 1
My answer is an additional element to #I.K. answer. Primitives (copy of value) and Non-Primitives (copy of reference values) - that's the key understanding.
Look at this code where I have put the comments (hosted on IDEONE):
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String a1 = "blablabla";
String b1 = a1;
System.out.println(b1);
System.out.println(a1);
System.out.println(b1.hashCode());
System.out.println(a1.hashCode());
a1 = "wow";
System.out.println(b1.hashCode());
System.out.println(a1.hashCode());
System.out.println(b1);
System.out.println(a1);
Set<String> a = new HashSet<String>();
Set<String> b = a;
a.add("hey");
a.add("HellO");
System.out.println(b.size());
System.out.println(b.hashCode()); // e.g. 69712814
System.out.println(a.hashCode()); // same - 69712814 (It's important to know)
a.clear();
System.out.println(a.size()); // same hashcode i.e. gets affected by the change.
System.out.println(b.size());
You can see that they are effectively hashed using the same code.
String class is a bit special in Java as you probably know that they use the String pool for "Intern"ing the values. If you run the code above you can see that as soon as you do a1 = "wow"; it will create a new value "wow" in the pool and therefore, the hashCode() changes.