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.
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).
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 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.
how to use getter setter in two different class
Class A{
int a = 10;
GetterAndSetter gs = new GetterAndSetter();
gs.setValue(a);
}
Class GetterAndSetter {
int a ;
public void setValue(int a){
this.a = a;
}
public int getValue(){
return a;
}
}
class B {
int c;
GetterAndSetter gs = new GetterAndSetter();
c = gs.getValue();
}
While printing c it gives null. And tell me if it is valid or not.
Whenever you write this
GetterAndSetter gs = new GetterAndSetter();
what you're doing is to create a new instance of GetterAndSetter. Two instances that you create won't have any connection between them.
Inside class A, you create a new instance, and set its value. Inside class C, you create a new instance, and read its value. But because you've got two different instances, the value you're reading isn't connected with the value you're setting.
This is roughly like:
I buy an envelope, and put some money inside it.
Later on, I want to get the money back, so I buy a new envelope, and look for the money inside it.
You have to be looking in the same envelope that you put the money in, if you want to find it!
In class A, your code creates a new instance of GetterAndSetter and sets a value to the property. In class B, however, your code creates again another new instance of GetterAndSetter , then gets the value.
The instances your code works with in classes A and B are not the same - hence you don't obtain the values set in A when trying to get it in B. The instance of GetterAndSetter created in B is not used anymore after the code in B exits.
To fix this, you need to pass a reference to the GetterAndSetter instance from class A to B. You can do this e.g. by passing it as a parameter to a method of B, or by creating a new instance of A in B and calling a method that provides an instance of GetterAndSetter.
An example of the first option (pass as parameter):
Class A{
...
GetterAndSetter createAndSet();
int a = 10;
GetterAndSetter gs = new GetterAndSetter();
gs.setValue(a);
return gs;
}
...
}
class B {
...
void getValueFromGetterAndSetter(GetterAndSetter gs) {
int c;
c = gs.getValue();
...
}
...
}
To connect the instances, we of course also need to have another piece of code (assuming instances of A and B exist already):
...
b.getValueFromGetterAndSetter(a.createAndSet());
...
You have used different reference. You should use same reference so that only you can access the value.
you need to understand the basics of oops, you have created one instance inside class A and you are trying to access in Class B which is possible only if you pass the reference of that object from Class A to B. In that case you have to have the instance of GetterAndSetter which you have created in Class A in Class B, instead you have created another new instance which will create new reference in memory, and the class variable a will be null.
In your code, both class A and B create new objects for GetterAndSetter. Hence they are not shared between these classes. Thats why you are getting null.
I wounder how your code print null for C. I think it would be "0" instead.
It is valid, here is what happens:
You create object gs in class A
Then you set the value of a of that object to 10
You then create another object gs in class B
Last but not least, you ask the object gs from class B what its value for a is.
Guess what, its NULL as you did not set its value anywhere so it wont return one.
This is the code I have, please look at it before you read the question
package ict201jansem2012;
public class Qn3b {
public static void main(String[] args) {
int a = 1;
int b[] = {4,5};
String s = "Good luck!";
method1(b[1]);
System.out.println("(1) b[0] = "+b[0]+"; b[1] = "+b[1]);
method2(b);
System.out.println("(2) b[0] = "+b[0]+"; b[1] = "+b[1]);
method3(a);
System.out.println("(3) a = " + a );
method4(s);
System.out.println("(4) s = " + s );
}
public static void method1(int b) {
b = 7;
}
public static void method2(int[] b) {
b[0] = 3;
}
public static void method3(int a) {
a = 3;
}
public static void method4(String s) {
s = "UniSIM";
}
}
Output:
(1) b[0] = 4; b[1] = 5
(2) b[0] = 3; b[1] = 5
(3) a = 1
(4) s = Good luck!
So my question is ,
This is intresting for me to know as learning programmer. The int b array 0 index value has changed, but not the other variables like the String s and int a. Before i ran this program I roughly thought in my mind that the variable will change their values as the methods are called ,this is because the method is being called and the main method vairable such as a,s and b array are passed and then they are being modified.
So in a nutshell why is that the b array 0 index is changed while the other variables are not changed?
Because you said you were a beginner programmer, I'll do a little writeup to explain (or try to explain) exactly what is happening.
It is because you are passing an argument to your method1 - method4 methods
These arguments, themselves, are references to other objects.
When you use the assignment operator, an equals sign, you overwrite that reference for the value in the current scope - where variables can be 'seen'.
In your code:
In the case of method1 you are creating a new reference, the variable can only be seen within that scope. That is, when you then go b = << expr >> you are assigning the variable b within method1's scope the value, not b in the main scope. The same is true of your method3 and method4 methods, you are assigning a new value to the respective variables within that scope, as you are creating new references rather than altering the original objects.
But, method2's code behaves differently, this is because you are mutating the object inside that code. You are altering the object directly - rather than creating a new reference inside that scope.
Consider the code below
int[] array = new int[] {1, 2};
public void test()
{
method1(array);
System.out.println(array[0] + ", " + array[1]);
method2(array);
System.out.println(array[0] + ", " + array[1]);
}
// because we are working with objects, the identifier, can be different to the arrays identifier
// in this case, I've chosen to use 'a' instead of 'array' to show this
public void method1(int[] a)
{
// this mutates the array object
a[0] = 2;
}
public void method2(int[] array)
{
// this overwrites the method2.array but not the global array
array = new int[] { 1, 2, 3 };
}
We create a new array, with identifer 'array' in the global scope. (In Java, this would be the classes own scope)
In method1, we take an argument, which is the same object being passed as the global array object, so when we mutate it, both objects will change. So, the first print statement will be
"2, 2"
Where array[0] has been altered
N.B. Because we dealing with objects, the 'name' of the variable doesn't matter - it will still be a reference to the same object
However, in method2, we take an argument, like in method1, but this time we use the assignment operator to assign that variable to a new value in the scope that it's currently in - so the global array isn't altered, so we still print out
"2, 2"
For a beginner programmer, I would personally write a few test programs where you get to fully understand how variables and scopes work.
But just know, everytime you create a new block of code, a new scope is created, local variables to that scope can only be seen in that scope and ones below it.
For instance:
public void test()
{
int a = 5;
method1(a);
System.out.println(a); // prints 5
}
public void method1(int a)
{
// a is only viewable in the method1 scope
// and any scopes below it, that is, any scopes created within method1
// and since we use an assignment operator, we assign method1.a a value, not global 'a' a value
a = 123;
if (true)
{
// this is a new scope, variables created in this block cannot be seen outside it
// but can see variables from above it
System.out.println(a); // prints 123
}
}
Here, we create a new scope inside method1 inside the if statement, which can see a above it. However, because method1 and test's scopes are both independent, when we use the assignment operator, we assign the value of a to the local scope. So a is different in both test and method1
I hope you understand better now.
I'm not very good at conveying things, but if it even helped a little bit in understanding scopes I did well, plus, it was fun.
Java is pass-by-value, but most values (everything that's not a primitive, in this case int[] and String) are references, which means they act like pass-by-reference.
Here's a nice writeup: http://javadude.com/articles/passbyvalue.htm
arrays are special type of objects and memory will be allocated on HEAP. When you pass array as parameter to method it will be pass as reference-value (copy of the reference).
This means initial b and this new reference points to same object. Unless new reference points to another object, changes on this reference will reflect on same object. That is why you are seeing value reflected on original array.
All of the values were passed TO the inner methods, but the inner methods returned nothing. However, method2 modified the internal value of the array that was passed to it, so that inner value appeared modified on return.
Note that method2 is the only one where you did not assign to the variable (parameter) itself, but rather assigned to an element of the object whose reference was passed in.
There is a critical difference between modifying the reference (pointer) to an object, and modifying the object itself.