Field Overwrite does not work within a method body - Java - java

Here's a question that goes right back to basics (I think) although had me stumped in a recent coding project I undertook with a few friends.
Here's code variation one:
public class Test {
private String test;
public Test(){
test = "tester";
changeString(test);
}
public void changeString(String t){
t = "blue apples";
}
public String getTest(){
return test;
}
public static void main(String[] args){
Test t = new Test();
System.out.println(t.getTest());
}
}
Why does the program print out "tester" instead of "blue apples"? Shouldn't the method changeString(String) turn the field 'test' into "blue apples"?
Thanks for your responses in advance!

Java is pass by value and not pass by reference. Therefore, the changes made to the passed t String, won't be reflected in your test String.
public void changeString(String t){
t = "blue apples";
test = t; // Include this line to assign the value of `t` to `test`.
}

First you assign "Tester" to test. Next you call changeString passing it a reference of test.
This method simply assigns "blue apples" to t. In doing so, it creates a new String before making the assignment. Because t is passed by value, the change is not reflected when the method returns
Instead, you would need to do something more like...
public void changeString(String t){
text = t;
}
And use changeString("blue apples");
or
public String changeString(){
return "blue apples";
}
And use test = changeString();

You are doing,
test = "tester";
changeString(test);
String is immutable in java.
public void changeString(String t){
t = "blue apples";
}
In the above lines you are changing the value of the parameter passed to that method, Not the test.
To see change try
public void changeString(String t){
t= "blue apples";
test=t; // now assigned the value
}

String is immutable in JAVA. Immutablity means once an instance is created it remains the same. In your case
In your case you created a tester reference to point to a new String "Tester"
Since string is immutable when you passed the object to the method and tried to reassign the reference to a new String "Blue Apples" what you did was created a reference t in the scope of method which pointed to blue apples. If you would had had printed t you would have got "Blue Apples" since the scope of t is till the method.
After returning the tester reference still points to the same old string "tester" and hence it gets printed.
As with String all other wrapper classes are also immutable. You would observe same behavior with Integer, Boolean objects

This happens because String object is immutable, hence cannot change its value post assignment. You can use StringBuffer or StringBuilder isntead

Related

what is the correct and best way to pass argument by reference to a method?

This is my code :
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
String str = new String("this is a text");
System.out.println(str);
getThis(str);
System.out.println(str);
}
private static void getThis(String str) {
str = "text changed";
}
}
and the output is :
this a text
this a text
I want str change after the getThis method called.
I know I should pass str by reference, and I know that this can be done by declaring the str as static and out of the main method and then call it in the method like this Main.str. But is it the correct way and standard way to pass by reference?
Java is not pass by reference, it's always pass by value. And for references.
It's passing references as values to the caller. You can do it by returning the String value from getThis() method and assigned to the same variable
public class Main {
public static void main(String[] args) {
String str = new String("this is a text");
System.out.println(str);
str = getThis();
System.out.println(str);
}
private static String getThis() {
return "text changed";
}
}
As others have stated Java is always pass by value with the slight caveat that when you pass in objects (like String) you are passing the value of a Reference to an object on the heap.
In your example, assignment has no effect outside the method and since Strings are immutable you can't really do much. If you passed in a StringBuilder then you could mutate the state of the object on the heap.
More generally instead of passing in an Object x you can pass in a wrapper object that contains a set method. Java provides an AtomicReference which allows you to do this.
In java, "references to objects are passed by value". So, any
reference to a non-primitive object that you pass will be directly
used and changes will be reflected in the original object.
Also, as a side note, Strings are immutable, so, you
will get a new String if you try to change it (Strings cannot be changed), the original one will not be changed.

"Variable may not have been initialized"

I've got a method that creates a String and another method that changes Strings
void create(){
String s;
edit(s);
System.out.println(s);
}
void edit(String str){
str = "hallo";
}
My compiler says that it "may not have been initialized".
Can someone explain this?
Variable may not have been initialized
As you define the s inside a method you have to init s in it somewhere every variable in a program must have a value before its value is used.
Another thing not less important, your code won't never work as you expected cause
Strings in java are inmutable then you cannot edit your String, so you should change your method edit(Str s).
I Change your code to something like this but i think your edit method should do another thing rather than return "hallo".
void create(){
String s=null;
s =edit(); // passing a string to edit now have no sense
System.out.println(s);
}
// calling edit to this method have no sense anymore
String edit(){
return "hallo";
}
Read more about that java is passed by value in this famous question : Is Java "pass-by-reference"?
See this simple Example showing that java is passed by value. I cannot make an example with only Strings cause Strings are inmutable. So i create a wrapper class containing a String that is mutable to see differences.
public class Test{
static class A{
String s = "hello";
#Override
public String toString(){
return s;
}
}
public static void referenceChange(A a){
a = new A(); // here a is pointing to a new object just like your example
a.s = "bye-bye";
}
public static void modifyValue(A a){
a.s ="bye-bye";// here you are modifying your object cuase this object is modificable not like Strings that you can't modify any property
}
public static void main(String args[]){
A a = new A();
referenceChange(a);
System.out.println(a);//prints hello, so here you realize that a doesn't change cause pass by value!!
modifyValue(a);
System.out.println(a); // prints bye-bye
}
}
You declare local variable s in method create, so that you need to initialized it before you use it. Remember that java does not have default value for local variable.
Init String s = "" or whatever value than your code will run normally.
try to initialize the string "s" to a null value, since you have declared a variable "s" but it has not been initialized. Hence it can't pass the reference of that variable while used as parameter.
String s = null;
Hope this helps
Give your variable S a value or as Jeroen Vanneve said "Change it to String s = null;"

Pass by "Reference Value"? Some clarification needed

I know that in Java, everything is passed by value. But for objects, it is the value of the reference to the object that is passed. This means that sometimes an object can get changed through a parameter, which is why, I guess, people say, Never modify parameters.
But in the following code, something different happens. s in changeIt() doesn't change when you get back to main():
public class TestClass {
static String str = "Hello World";
public static void changeIt( String s ) {
s = "Good bye world";
}
public static void main( String[] args ) {
changeIt( str );
System.out.println( str );
}
}
I'm guessing -- and I'd like confirmation -- that when you say s = "something" it's the same or equivalent to saying String s = new String("something"). Is this why s doesn't change? Is it assigned a whole new object locally which gets thrown away once you exit changeIt()?
that when you say s = "something" it's the same or equivalent to saying String s = new String("something")
Yes, pretty much. (though the JVM might do optimizations so that the same string literal used several times refers to the same String object).
Is this why s doesn't change? Is it assigned a whole new object locally which gets thrown away once you exit changeIt()
Yes. As you say, everything is passed by value in Java, even references to object. So the variable s in changeIt( String s ) is a different value from str you use in main(), it's just a local variable within the changeIt method.
Setting that reference to reference another object does not affect the caller of changeIt.
Note that the String object s refer to is still the same String as str refers to when entering the changeIt() method before you assign a different object to s
There's another thing you need to be aware of, and that is that Strings are immutable. That means that no method you invoke on a string object will change that string. e.g. calling s.toLowerCase() within your changeIt() method will not affect the caller either. That's because the String.toLowerCase() does not alter the object, but rather returns a new String object.
When you write
s = "Good bye world";
you are changing the value of s to be a reference to the new string. You are not changing the value of the string referenced by s.
Yes, now 'S' points to brand new object whose scope is limited to that method. String may not be perfect example to understand pass-by-value concept. Instead of string, let us say pass some mutable object reference and make changes to that assign new object inside the method. You don't see them outside of the object.
public class MyMain {
private static void testMyMethod(MyMain mtest) {
mtest=new MyMain();
mtest.x=50;
System.out.println("Intest method"+mtest.x);
}
int x=10;
public static void main(String... args)
{
MyMain mtest = new MyMain();
testMyMethod(mtest);
System.out.println("In main method: "+mtest.x);
}
}
Read second answers in this SO discussion.

Java Object Reference and Java Methods

I am unable to understand how this works
public void addToRule(Rule r) {
if (!getRuleList().contains(r)) {
getRuleList().addElement(r);
}
}
If I run this code:
obj.addToRule(r);
System.out.println(getRuleList().contains(r));
it prints out true how can this happen?
btw ruleList is a vector member of the main class and is not a static variable(don't think this matters but sharing anyway).
import java.util.Vector;
public class RuleEngine{
private Vector ruleList = new Vector();
public Vector getRuleList(){
return ruleList;
}
public void addToRule(Rule r){
if(!getRuleList().contains(r))
getRuleList().addElement(r);
}
public static void main(String args[]){
RuleEngine re = new RuleEngine();
Rule r = new Rule("Rule1");
re.addToRule(r);
System.out.println(re.getRuleList().contains(r));
}
}
class Rule{
public String name = "";
public Rule(String nam){
this.name=nam;
}
}
OK people have told me that this works because of the pass by reference in java. I get it. but what can i do to get a copy of that object instead of its reference?
I'm guessing getRuleList() is returning a reference to a List (or something similar). Think of it as a pointer (or more specifically, a copy of a pointer) if you're familiar with C. You're working on the same underlying instance of the object when you call getRuleList().
For proof, try: System.out.println(getRuleList() == getRuleList()); The == operator will only compare if the two references are pointing to the same object (not a deep equal like .equals). You'll see that until you call setRuleList() with a different object reference that the statement holds true.
These assumptions are of course without seeing your full code.
So, to answer your questions you have to at first know how Java passes Variables.
a Variable has a value:
int i = 1234;
Person p = new Person("Peter");
Now, the Variable i contains exactly 1234, while the Variable p contains the Memory Adress of the created Person.
so i contains 1234 and p contains the adress (let's say a4dfi3).
anyMethodYouLike(p);
System.out.println(p.getName());
public void anyMethodYouLike(Person somePerson) {
somePerson.rename("Homer");
}
so in this example, we give the Method anyMethodYouLike the Variable p... wait! we give the Method the value of the Variable (a4dfi3). The Method then calls rename on this Variable (which still has the same adress as p has, hence it modifies the same Person that p points to).
So, after the Method, the Name of the Person p points to, gets printed, which results in "Homer".
someOtherMethod(p);
System.out.println(p.getName());
public void someOtherMethod(Person somePerson) {
somePerson = new Person("Walter");
}
In THIS example we still give the adress of our Person called "Peter" to the Method. But this time, the Method creates a new Person in somePerson (therefore overriding the adress in somePerson to.. let's say 13n37s.
BUT! the Person at a4dfi3 wasn't changed! The print call still outputs "Peter" and not "Walter".
Now, let's see how this behaves with primitives:
someMethod(i);
System.out.println(i);
public void someMethod(int someInt) {
someInt++;
}
So, the Value of i (1234) gets passed to someInteger. Then someInteger gets incremented to 1235. But i is still 1234.
This is the big difference between Objects and primitives in Java.
Hope I could help,
Ferdi265
From your comments it looks like you have not completely understood what the difference is between a value and a reference in Java. Basically, objects are always passed around as references in Java.
Consider
class Test {
private List list = new ArrayList();
public List getList() {
return list;
}
}
The getList() method will return a reference to the list object. It will not return a copy of the list object. Doing something like
Test test = new Test();
String s = "ABC";
test.getList().add(s);
System.out.println(test.getList().contains(s));
Will return true since the first time getList() is called, a referece to the list is returned, on which add(s) is invoked. The second time getList() is called, it returns a reference to the same list, not a copy of it, not a new list - the same reference. Calling contains(s) will return true since it the same list onto which the object s was added.
Consider this, however.
Test test1 = new Test();
Test test2 = new Test();
String s = "ABC";
test1.add(s);
System.out.println(test2.getList().contains(s));
This will print out "false". Why? test1.getList() returns a reference to the list inside test1 and test2.getList() returns a reference to the list inside test2. Here, s was added to test1:s list, so it will not be contained inside test2:s list.
It should always print true, because you add the rule to the rule list in case it is not there. What happens is:
you tell the object to add add a rule to its rule list
the objects checks if the rule exists, and if it doesn't, adds it
So it is guaranteed to contain the rule after the code is executed.

Could I change the reference inside one method with this reference as argument in Java?

private static void changeString(String s) {
s = new String("new string");
}
public static void main(String[] args) {
String s = new String("old string");
changeString(s);
System.out.println(s); // expect "new string"
}
How could I make the output of "new string" happen with s as the only argument to method changeString?
thanks.
In Java arguments are passed by value, object arguments pass a reference to the object, this means that you can change the reference of the argument, but that does not change the object you passed the reference to. You have two possibilities, return the new object (preferred) or pass reference to a container that can receive the new reference (collection, array, etc.) For example:
private static String changeStringAndReturn(String s) {
return new String("new string");
}
private static void changeStringInArray(String[] s) {
if (null != s && 0 < s.length) {
s[0] = new String("new string");
}
}
References in Java are passed by value, so even if you modify the reference inside the function, changes won't be reflected back to the calling function because what you modify inside the function is just a copy of the original reference not the original reference itself.
But you can return the new string from your changeString method instead of trying to modify the reference there(inside the function) itself.
Only if you make the function
private static void changeString(String[] s) {
s[0] = new String("new string");
}
String are immutable, and Java has no concept of a 'pointer-to-a-reference' as a first class datatype. If you don't like the above, you can make a little class containing a single String field.
You can, of course, return the new string from your changeString method instead of trying to change it in place.
Alternately, you can create an object that wraps or contains a string, and pass that in. The ChangeString method would change the string that was internal to your object, and the main method would still be holding a reference to that object.
Otherwise, you can't do this. String is immutable, and java always passes objects as a value that is a pointer to a particular object. Change where you're pointing, and you aren't referencing the same object anymore.
Strings are immutable in Java and parameters are passed by value so you can't change them (there is not equivalent to ref in C#). You can pass in a StringBuilder and change it's contents just as easily.
A: You can't, in Java object references are pass by value.
If you really need to, you can create a wrapper like this and use it the way you expected:
private static void changeString( _<String> str) {
str.s("new string");
}
public static void main(String[] args) {
_<String> s = new _<String>("old string");
changeString(s);
System.out.println(s); // prints "new string"
}
I know this is old, but, just for posterity, most of this is mostly wrong.
In Java, non-primitives are passed by reference. Primitives (boxed and unboxed) are passed by value.
To directly answer OP, you're getting a reference to the actual String you passed. However, as #bmarguilies correctly pointed out - Strings are immutable in Java. Any assignment to a String creates a copy, then assigns the newly-assembled copy to the reference.
This is not possible in Java as everything in Java is passed by value. In this case where the argument is an object reference it is the value of the reference that is passed into the method, not the reference itself.
Java does not allow out parameters like C#, so you will not be able to achieve this as such.
Its ugly but you could change the String to global static:
private static String s;
private static void changeString(String t) {
if(s.equals(t))
s = new String("new string");
}
public static void main(String[] args) {
s = new String("old string");
changeString(s);
System.out.println(s); // expect "new string"
}

Categories