Changing the value of an object in a method changes it globally? - java

Here's my Code
Class A
public class A {
private int a;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
Class Change
public class Change {
public void changeSomething(A a){
a.setA(13);
}
}
Class Learn
public class Learn {
public static void main(String[] args) {
A a = new A();
Change change = new Change();
change.changeSomething(a);
System.out.println(a.getA());
}
}
The output is 13. Now when i am passing an object to the changeSomething method, internally the value of Object A has been changed but why do i see this effect outside that function?
Is not this equivalent to passing by value in C where unless you return that variable/Object you dont get the updated value.
i.e. dont i need to do a=changeSomething(a); and set the return type of this method to be as A?
Thanks

You're passing a reference to the original object around. When you write a method
void someMethod(A param) { ... }
param is a reference to the original object. The original object isn't being copied. Consequently when you change this object, the change is visible wherever that object is observed.
When you write:
private A a = new A();
it's important to realise that the variable is a reference to object type A, not an actual object type A. It's a fine distinction, granted.
The above behaviour can cause unexpected effects across your system, and it's an argument for immutability, especially in threaded environments where changes can be triggered from multiple threads.

Short:
changeSomething() will update the value for object so if you refer to same instance you will get the same value back
Bit long explanation:
//an Object of A created and its reference is set to a
A a = new A();
//instance of Change is created and its reference is set to change
Change change = new Change();
//it passes reference's (a) 's value to the changeSomething method
//which invokes `setA()` on instance referred by a (which is the same instance that waas crated in line 1
change.changeSomething(a);
//so you will get the changed value here
System.out.println(a.getA());

Well the code you provided works directly on an instance of A. This instance is changed, no matter if you return it or not. Its still the same instance of your object. And this instances variable reflects the new value.

This is because you pass the Object, and objects in Java are always passed by reference. Only primitive (int, double, char, long...) are passed by value.
In C it could be:
public void changeSomething(A& a){
a.setA(13);
}

Related

Returned object changes private reference variable values

Say I have a class with a reference type variable in it. I don't want the stored values of the object that this variable stores to be able to change, but I want to be able to get the object itself/access its values. This calls for making it private and creating a getter, but no setter. Doing this however only limits my ability to change the object that the variable points to, but it doesn't prevent me from changing the values of the object itself.
private void program(){
Test test = new Test(3);
out.println(test.getA().a); // initial value, prints 3
test.getA().a = 4; // changes referenced value through getter, even though the object is private, and has no setter
out.println(test.getA().a); // changed value, prints 4
}
class Test{
private A a;
public Test(int a){
this.a = new A(a);
}
public A getA(){
return a;
}
}
class A{
public int a;
public A(int a){
this.a = a;
}
}
In the code above I can use the getter to access the object's values, even though I made the variable private to try to prevent this from happening. The only way that I see around this is to create a new A object that I return every time I call the getter method, but to me this seems inefficient as it takes up unnecessary space in memory.
Is there a better way of reading the object while still preventing change or am I missing something?
Thanks in advance.
This is a common problem and there are 2 main solutions:
The way you described with copy-constructor or clone() method in getter
You can make your A class immutable - just make all fields final and initialize it once through constructor or nested builder
Also i advise not to make value-type fields public AT ALL
Usefull links:
https://www.baeldung.com/java-immutable-object
https://www.journaldev.com/129/how-to-create-immutable-class-in-java
https://web.mit.edu/6.005/www/fa15/classes/09-immutability/

What exactly happens during object creation? (Java)

I've been studying from Head First Java and I'm currently on the constructors chapter. They've explained that an object is created by calling a constructor after the new keyword.
My question: What is it exactly that runs when you create a new object? Let's take the following as sample code:
public class Const {
// instance variables
int number;
String name;
// Constructors
public Const() {
//implicit super
System.out.println("no-arg constructor");
}
public Const(int i, String s) {
//implicit super()
number = i;
name = s;
System.out.println("two-arg constructor");
}
// test method
public void doSomething() {
System.out.println("I'm a test");
}
// Main
public static void main(String[] args) {
Const c1 = new Const();
Const c2 = new Const(5, "Jerry");
}
}
Now here is what I believe is happening under the hood when creating c1:
public Const() is called
super() is called
the Object part of Const is built.
public Const() is back on top of the stack.
Now here comes my trouble. When and how exactly are the instance variables and methods for the object created (what implicit code is added)?
What exactly happens during object creation? (Java)
Constructor being called, which will call the super method of the parent Class(By Default Object class, so the new Class will have access of all members of Object class)
Memory Allocation
Fields are initialized (by assigned value or if not given then by default value)
rest code block of the constructor will be executed
So the only difference here is:
Const c1 = new Const();
Here number will be initialized by int default value which is 0 and name will be initialized by null, which is the default value of String
Const c2 = new Const(5, "Jerry");
Instead here it will be 5 and Jerry respecively
With the new Const(), the constructor will be called and the class will be loaded to the main memory.
public Const() {
//implicit super
super()
}
The super keyword in java is a reference variable that is used to refer parent class objects, which is by default Object class. The keyword “super” came into the picture with the concept of Inheritance.
So now it has access of all members of Object class i.e. toString, equals :
as you can access
c1.toString() or c1.equals(obj)
When and how exactly are the instance variables and methods for the
object created (what implicit code is added)?
I think now you understood how instance variables are created, and the default values are assigned to them based on the type.
If still not clear, try to understand the internal arch, that might help:
JVM Arch

Having an method argument as 'Object' type

Suppose I have the following method:-
public static void abhay(Object a){
....
}
and I use it somewhere like this:-
public static void main(String[] args){
...
Kaal b = new Kaal();
abhay(b);
...
}
where Kaal is a class, obviously.
Now, what will be the class type(object type at compile time) of a inside the method abhay? In other words, what will be the class of a, in the eyes of compiler, when inside method abhay?
Also, how above is different than below?
(given that we only change the definition of abhay):-
public static void abhay(Kaal a){
....
}
"Java is always 'call by value'. Instead of the object, only the reference to the object, is passed as an argument, where this reference, is, the value."
If the above fact has any relevance to the answer to this question, please try to explain in context of above fact.
The compiler only cares about the signature of the method it is currently in.
It can't know and doesn't care about how that method is invoked.
So, to the compiler sees that abhay() has declared a to be an Object; and that is what the compiler knows about a.
Of course, at runtime, a call like b instanceof Kaal will result to true.
And just for the record: this has nothing to do with call-by-value or call-by-reference.
The answer is straight forward. Given the following method signature:
public static void abhay(Object a)
and you invoke it by abhay(new Kaal());
It is like saying:
Object a = new Kaal(); //only able to access members of Object
Because you told Java to handle it as an Object, it will be treated as an Object. To access members of Kaal:
((Kaal)a).kaalMethod();
This is just a matter of Java complying to the data type given in the parameter list. It has nothing to do with "pass by value". Further more, both instances Kaal and Object are objects. You are not even dealing with primitives here where the value are referring to the actual content of the primitives.
Take Kaal as a parameter and you can access Kaal methods
public static void abhay(Kaal a){
a.getSomeKaalMethod(); // works
....
}
Take Object as a parameter, and pass a Kaal class, and you can't access Kaal methods or fields
public static void abhay(Object a){
a.getSomeKaalMethod(); // doesnt work
....
}
Unless you cast the object to Kaal
public static void abhay(Object a){
Kaal k = (Kaal)a;
k.getSomeKaalMethod(); // works
....
}
You might want to check if is instanceof Kaal other wise I dont see why you will take a Object instead of the class
public static void abhay(Object a){
if(a instanceof Kaal){
Kaal k = (Kaal)a;
k.getSomeKaalMethod(); // works
}
}

Java supports pass-by-value. But can't make out the reason of the below code [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
Code:
class AB{
int i=5;
}
class BC{
public void test(AB a){
a.i=10;
}
}
public class ATest{
public static void main(String aa[]){
AB a = new AB();
//Base class variable value
System.out.println(a.i);
BC b = new BC();
//Modifying the object "a"
b.test(a);
//Printing the base class object
System.out.println(a.i);
}
}
// Output : 5
// 10
If it is pass-by-value, the output should have been 5 and 5
Java uses pass-by-value but if the parameter is an object Java passes by value the reference to the object, so the called method can change the content of the object, not the object as a whole.
This does not mean that objects are passed by reference (the comment by Joachim Isaksson is wrong).
ADDED to answer to the comment by Arijeet Saha:
When I say "the called method can change the content of the object, not the object as a whole", I mean that if you change the object as a whole the caller doesn't see the change.
Consider the following example:
public void test(Person p) {
p.setName("Pino");
p = new Person();
p.setName("John");
}
The first line of test() changes the content of the object received by the method, the second line changes the object as a whole (it assigns a new object to the formal parameter), the third line changes the content of the new object. In this case the caller sees a Person object with name "Pino", not "John", because the change made by the second line of test() is not visible to the caller; it is not visible because objects are not passed by reference.
Let me first clear what does pass-by-value mean?
It means what ever you are passing to a method, it will recieve its copy not the actual adress.
So in your case you too are passing the value the variable a, and its value (which is referance to an object or adress to an object) is copied to the method(AB a).
Java's parameter passing is quite tricky - When an object is passed to a function, you can manipulate the object's fields but you cannot manipulate object itself. The object reference is passed by value. So, you can say:
class someClass{
int i = 5;
}
class Foo
{
static void func(someClass c)
{
c.i = 3;
}
}
class MainClass{
public static void main(){
someClass c = new someClass();
System.out.println(c.i);
Foo.func(c);
System.out.println(c.i);
}
}
Expect your output to be:
5
3
Changes to the fields of c persist.
but if manipulate the object itself, this manipulation will only persist in Foo.func() and not outside that function:
class someClass{
int i = 5;
}
class Foo
{
static void func(someClass c)
{
c.i = new someClass();
c.i = 3;
System.out.println(c.i);
}
}
class MainClass{
public static void main(){
someClass c = new someClass();
System.out.println(c.i);
Foo.func(c);
System.out.println(c.i);
}
}
Expect your output to be:
5
3
5
What has happened? c.i has the value 5 in MainClass.main() in Foo.func(), c itself is modified to point to another instance of someClass, containing the value 3. However, this change is not reflected to the actual object that has been passed. The c in Foo.func() and MainClass.main() are different objects now. That's why changes to the c of Foo.func() do not affect the c in MainClass.main().
Java always passes parameters as by value.
It's important to understand what is the value (what a variable holds).
For primitives it's the value itself.
For objects it's a reference.
When you pass an object as a parameter - the reference to the object is copied but it still points to the original object.

Why does sysout(upper class) invoke toString of lower class after assigning lower class to upper class?

I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.

Categories

Resources