scope question in java

M

marty

Why does myMethod change the value of myDate but not myString?
Am I missing some scoping principle here?


import java.util.Date;

public class test1 {

public test1()
{
String myString = new String("String1");
Date myDate = new Date (100, 11, 31);
System.out.println("Value is " + myDate + " " + myString);
myMethod(myDate , myString);
System.out.println("Value is " + myDate + " " + myString);
}

public static void main(String args[])
{
test1 mytest = new test1();
}

public void myMethod(Date myDate, String myString) {
myString = "String2";
myDate.setYear (105);
}

}
 
M

marty

Is that because one is an assignment, the other is a method?
Is there a some fundemental Java rule lurking in here somewhere?
 
T

Tor Iver Wilhelmsen

marty said:
myString = "String2";

This changes the local (stack) pointer, and has no effect on the
caller value.
myDate.setYear (105);

This, however, changes the state of the passed pointer's object, and
thus will change the caller value.
 
E

Eric Sosman

marty wrote:

Please don't top-post (fixed).
Is that because one is an assignment, the other is a method?

More or less, yes.
Is there a some fundemental Java rule lurking in here somewhere?

The "fundamental rule" is that arguments to methods
and constructors are always passed by value. Some people
say that primitives are passed by value while objects are
passed by reference, but that is (IMHO) an unnecessary
obfuscation: if you think of the argument as a reference
value that refers to an object that's "elsewhere," the
reference itself is passed by value.

So when the method executes `parameter = newvalue'
on one of its parameters, it's only changing its own copy
of the reference value it was passed; the caller's copy
isn't affected at all. Try your code again, but replace
`myDate.setYear(105)' with `myDate = new Date(105, 11, 31)'
and see what happens.

You could also ponder changing `myString = "String2"'
to `myString.changeContents("String2")', which would change
the content of the String object that the myString reference
refers to. There is, however, one slight obstacle to actually
performing this experiment: there's no such method for the
String class! Thus, this exercise must remain a "thought
experiment" and not something you can actually do -- but if
you *could* change a String (the way you can change a Date),
the experiment would illustrate the parallel.

Operators ( =, ==, !=, ... ) work on primitives and on
references. Methods ( .toString(), .setYear(), ... ) work
on the referred-to objects.
 
R

Rick

yeah, don't try to return values through parameters. This is not
commonly done and makes debugging hard (you have to think) Instead
return a method value or set instance variables and use getters to get
to them after the return.
 
D

Dimitri Maziuk

marty sez:
Is that because one is an assignment, the other is a method?
Is there a some fundemental Java rule lurking in here somewhere?

Yes. All primitive types and object references are created on the
stack and passed by value. Changing a reference only changes it
(its copy) in current scope. Once you return and stack frame is
discarded, it reverts to previous value.

Object references are pointers. Assignment operator only copies
the address, no copy constructor is called.

Dima
 
A

Alun Harford

marty said:
Why does myMethod change the value of myDate but not myString?
Am I missing some scoping principle here?
public void myMethod(Date myDate, String myString) {
myString = "String2";
myDate.setYear (105);

<snip>

Think about what:
myString = "String2";
actually means.

It's a nice easy shortcut for:

char[] data = { 'S', 't', 'r', 'i', 'n', 'g', '2' };
myString = new java.lang.String( data );

That should be enough for you to work out why.

Alun Harford
 
S

shakah

It is reasonable to expect that the myMethod function in your example
would modify both arguments. Notwithstanding the convoluted
explanations already posted, the issue is simply that String objects
don't act like other objects -- they are immutable, and changing their
value creates a new object.

You can get the results you expect with StringBuffer objects, e.g.

public void myMethod(Date myDate, StringBuffer myString) {
myString.setLength(0) ;
myString.append("String2") ;
myDate.setYear(105) ;
}
 
L

Lee Fesperman

shakah said:
It is reasonable to expect that the myMethod function in your example
would modify both arguments. Notwithstanding the convoluted
explanations already posted, the issue is simply that String objects
don't act like other objects -- they are immutable, and changing their
value creates a new object.

Don't add to it by being convoluted yourself. They are immutable so you *can't* change
their value ... all you can do is create a new object. That is not changing their value.
 
S

shakah

Point taken, should have been something like "[String objects] are
immutable, so code that appears to change their value (e.g. by
assigning a string literal, appending, etc.) results in a new object".

Still, the OP's observation/question still hinges solely on the String
object's not-always-obvious immutability.
 
P

Patricia Shanahan

shakah said:
Point taken, should have been something like "[String objects] are
immutable, so code that appears to change their value (e.g. by
assigning a string literal, appending, etc.) results in a new object".

Still, the OP's observation/question still hinges solely on the String
object's not-always-obvious immutability.

I don't think the issue has anything to do with the
immutability of String. It is simply a matter of the
difference between modifying a reference and modifying the
object it references. Here is an example program:

public class ParameterExample {

public static void main(String[] args) {
MyWeirdClass x = new MyWeirdClass();
MyWeirdClass y = new MyWeirdClass();
x.field1 = 33;
x.setField2(-4);
System.out.println("main x before call: " + x);
System.out.println("main y before call: " + y);
modSub(x, y);
System.out.println("main x after call: " + x);
System.out.println("main y after call: " + y);
}

static void modSub(MyWeirdClass x1, MyWeirdClass y1) {
x1 = new MyWeirdClass();
System.out.println("modSub x1: " + x1);
y1.field1 = 1234;
y1.setField2(-97);
System.out.println("modSub y1: " + y1);
}
}

class MyWeirdClass {
public int field1 = 1;

private int field2 = -1;

public void setField2(int val) {
field2 = val;
}

public String toString() {
return "field1=" + field1 + " field2=" + field2;
}
}

The output is:

main x before call: field1=33 field2=-4
main y before call: field1=1 field2=-1
modSub x1: field1=1 field2=-1
modSub y1: field1=1234 field2=-97
main x after call: field1=33 field2=-4
main y after call: field1=1234 field2=-97

Despite the mutability of MyWeirdClass, the assignment to x1
in modSub has no effect on the object referenced by x in
main. On the other hand, the assignment to y1.field1 in
modSub does change the content of the object referenced by y
in main.

Patricia
 
S

shakah

Getting my butt kicked on this topic -- you are of course correct. I'll
think a bit more before posting in the future.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top