I need to get some clarification on Java references (pointers).
I have read this (Java is Pass-by-Value, Dammit! by Scott Stanchfield) excellent write up on Java's way of passing variables around. As far as I understand everything is passed around as memory pointers.
public class foo{
int a;
int b;
public foo(a, b){
this.a = a;
this.b = b;
}
}
so in some code like this:
foo aFoo = new foo(1,2); //new foo created at adress 0x40 for instance
someFunc(aFoo);
the argument to someFuncis actually the number 0x40 (albeit this might be a simplification, but to get a sense for the pattern).
Now, suppose i created another class
public class bar{
foo aFoo;
public bar(){
this.aFoo = new foo(1,2);
}
}
and instantiated the following variables
bar aBar = new bar();
foo bFoo = new foo(3,4);
now suppose i want to copy the values of aBar.aFoo into bFoo like
bFoo = aBar.aFoo;
If i now do
bFoo.a = 1234;
did i also just change aBar.aFoo.a into 1234 or does that variable still hold the value 1?
By my own logic, bFoo.a is just a pointer, so assigning a new variable should alter both places, but this seems incorrect. So I guess i have not fully understood Java's "reference is really a pointer" concept. Or rather, i might understand the pointer part of it, but not the dereferencing of the pointers, since this is done implicitly compared to in C where you always know.
bFoo = aBar.aFoo;
-> you have assigned the aBar.aFoo reference to bFoo local variable. This is called aliasing because now you have two ways to refer to the same object: bFoo and aBar.aFoo.
bFoo.a = 1234;
-> you have assigned 1234 to the a field of the object referred to by bFoo. This object is referred to by aBar.aFoo as well.
Result: you have changed the value of aBar.aFoo.a.
Related
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).
When I use the this keyword for accessing a non-static variable in a class, Java doesn't give any error. But when I don't use it, Java gives an error. Why must I use this?
I know when should normally I use this, but this example is very different from normal usages.
Example:
class Foo {
// int a = b; // gives error. why ?
int a = this.b; // no error. why ?
int b;
int c = b;
int var1 = this.var2; // very interesting
int var2 = this.var1; // very interesting
}
The full description is in section 8.3.3 of the Java Language Specification: "Forward References During Field Initialization"
A forward reference (referring to a variable that is not declared yet at that point) is only an error if the following are all true:
The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of C or an instance initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
See the bolded text: "the use is a simple name". A simple name is a variable name without further qualification. In your code, b is a simple name, but this.b is not.
But why?
The reason is, as the cursive text in the example in the JLS states:
"The restrictions above are designed to catch, at compile time,
circular or otherwise malformed initializations. "
In other words, they allow this.b because they think that a qualified reference makes it more likely that you have thought carefully about what you're doing, but simply using b probably means that you made a mistake.
That's the rationale of the designers of the Java Language. Whether that is true in practice has, to my knowledge, never been researched.
Initialization order
To expand on the above, in reference to Dukeling's comment on the question, using a qualified reference this.b will likely not give you the results you want.
I'm restricting this discussion to instance variables because the OP only referred to them.
The order in which the instance variables are assigned is described in JLS 12.5 Creation of New Class Instances.
You need to take into account that superclass constructors are invoked first, and that initializations code (assignments and initialization blocks) are executed in textual order.
So given
int a = this.b;
int b = 2;
you will end up with a being zero (the value of b at the time that a's initializer was executed) and b being 2.
Even weirder results can be achieved if the superclass constructor invokes a method that is overridden in the subclass and that method assigns a value to b.
So, in general, it is a good idea to believe the compiler and either reorder your fields or to fix the underlying problem in case of circular initializations.
If you need to use this.b to get around the compiler error, then you're probably writing code that will be very hard to maintain by the person after you.
Variables are declared first and then assigned. That class is the same as this:
class Foo {
int a;
int b;
int c = b;
int var1;
int var2;
public Foo() {
a = b;
var1 = var2;
var2 = var1;
}
}
The reason you can't do int a = b; is because b is not yet defined at the time the object is created, but the object itself (i.e. this) exists with all of its member variables.
Here's a description for each:
int a = b; // Error: b has not been defined yet
int a = this.b; // No error: 'this' has been defined ('this' is always defined in a class)
int b;
int c = b; // No error: b has been defined on the line before
You have presented 3 cases:
int a = b;
int b;
This gives error because the compiler will look for b in the memory and it will not be there. but when you use this keyword then it specifies explicitly that the b is defined in the scope of the class, all class references will be looked up for it, and finally it will find it.
Second scenario is pretty simple and as I described, b is defined in the scope before c and will not be a problem while looking for b in the memory.
int var1 = this.var2;
int var2 = this.var1;
In this case no error because in each case the variable is defined in the class and assignment uses this which will look for the assigned variable in the class, not just the context it is followed by.
For any class in Java this is a default reference variable (when no specific reference is given) that either user can give or the compiler will provide inside a non-static block. For example
public class ThisKeywordForwardReference {
public ThisKeywordForwardReference() {
super();
System.out.println(b);
}
int a;
int b;
public ThisKeywordForwardReference(int a, int b) {
super();
this.a = a;
this.b = b;
}
}
You said that int a = b; // gives error. why ? gives compile time error because b is declared after a which is an Illegal Forward Reference in Java and considered as a compile-time error.
But in the case of methods Forward Reference becomes legal
int a = test();
int b;
int test() {
return 0;
}
But in my code, the constructor with the argument is declared before both a & b, but not giving any compile-time error, because System.out.println(b); will be replaced by System.out.println(this.b); by the compiler.
The keyword this simply means current class reference or the reference on which the method, constructor or the attribute is accessed.
A a1 = new A(); // Here this is nothing but a1
a1.test(); // Here this is again a1
When we say a = this.b; it is specifying that b is a current class attribute, but when we say a = b; since it is not inside a non-static block this won't be present and will look for an attribute declared previously which is not present.
Please look at the Java Language Specification: https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2.3
This is the reason, IMO: The usage is via a simple name.
So in this case you have to specify the name using this.
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.
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
One of the most popular answers to one of the most popular questions in Java here reads:
Java is always pass-by-value. The difficult thing to understand is that Java passes objects as references and those references are passed by value.
So what does "Java passes objects as references and those references are passed by value." mean?
Does it mean that:
The memory location to which the original variable points is copied as the value of the new temporary variable? (if this is the case, all the changes made inside the function will be reflected in the original, right?)
If not, what does it mean?
Think of objects references as "pointers to a value"
When you pass a value into a method, you pass the pointer in, therefore the two pointers (the one in the method, and the one you passed in) point to the same thing.
Consider this
public static void main(String[] args){
Foo cl = new Foo();
cl.z= 100;
method(cl);
System.out.println(cl.z);
}
private static void method(Foo bar){
bar.z=10;
}
Before you call method, cl.z would be 100, but after you pass it in, it would be equal to 10.
What is not correct is this:
public static void main(String[] args){
Foo cl = new Foo();
cl.z= 100;
method(cl);
System.out.println(cl.z);
}
private static void method(Foo bar){
bar = new Foo();
bar.z=10000;
}
This would NOT print out 10000, because you cannot assign the pointer to reference a different object
When we say Java is pass-by-value, it means that if you modify a parameter inside a method, it has no effect on the caller. For example:
public void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
All this does is swap local copies of the parameters. Thus, if you say
int x = something;
int y = somethingElse;
swap(x, y);
x and y would not change.
The same is true for references:
public void someOperation(MyClass a) {
a = ...something...;
}
Inside your method, a is a copy of whatever reference you pass in; if you reassign a to something else in the method, it doesn't affect any variable in the caller.
MyClass x = ...;
someOperation(x);
x does not change, even though you've changed the parameter a inside the method.
Note that this means that x itself will not change. It will not point to a different MyClass instance, even though a in the method was changed to refer to a different MyClass instance. However, even though the reference does not changed, the object that the reference refers to could be changed by the method.
It means the reference (a memory pointer to the object) is passed by value. If you modify the object, you modify the reference to the object; thus the change will be seen across your application. If you modify the pointer, then your only change it for the scope of your method.
void method(Foo f) {
f.bar = 10; // Seen accross your application.
f = new Foo(); // Modifying your pointer. This does not change the previous object.
}
Yes, Java is always pass-by-value, with both reference types and primitive types. But that doesn't mean that changes within functions always affect the object passed in as an argument.
If a primitive type is passed in, then there is no reference passed, it's by pure value, and any values in the calling scope will not change.
If a reference type is passed in, whether or not a function can modify it depends upon if the type is mutable (the object can be modified) or immutable (the object itself cannot be modified, a new object must be created for all modifications).
If it is mutable, like StringBuilder or HashMap<String, String>, then the function is able to modify it and changes within the function will still be in place after the function call returns. However, note that changing what a reference type points to is not modifying it, in that case, you are only changing what the reference type points to, not the original object referenced by an argument, but doing an operation like strbuilder.append("xyz") is.
If it is immutable, like String or Integer then all modifications within the function will create a new object and the changes will not be in place after the function call returns.
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.