This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
I am writing a static analysis tool for Java programs. And during analysis of assignment operators, for example, I want to know if underlying objects are using copy-by-value or copy-by-reference.
In case of primitive data types, I know, variables use copy-by-value.
int x = 5;
int y = x; // Both are pointing to independent memory locations.
In case of objects, usually they copy reference value of other objects. For example,
MyClass obj1 = new MyClass();
MyClass obj2 = obj1; // Both instances pointing to the same memory location.
However, in special cases, such as
String str1 = "myString";
String str2 = str1; // Both pointing to independent memory locations.
str1 = null; // Only str1 gets null
Objects use copy-by value, in my opinion. Please correct me if I am wrong. Similarly, StringBuilder and other java/lang/* classes that are declared with final keyword, their objects/instances behave like that. However, when being passed as parameter to a method, their reference values are passed.
So my question is that is there any way to find all such special cases where objects always use copy-by-value behavior? How can I find all such classes? This may not be an easy task, any kind of suggestion is welcome. Thanks.
For :
String str1 = "myString";
String str2 = str1; // Both pointing to independent memory locations. NO!
str1 = null; // Only str1 gets null
Consider this example :
public static void main(String[] args) {
String s1 = "hello";
String s2 = s1;
System.out.println(s2 == s1); // true . Both pointing to same location
s1=null; // s2 still points to "hello"
}
Related
This question already has answers here:
Difference between string object and string literal [duplicate]
(13 answers)
Closed last year.
Given this example code:
class basic {
public static void main(String[] args) {
String s1 = "Java";
String s2 = new String("Java");
}
}
Are s1 and s2 both reference variables of an object?
Do those two lines of code do the same thing?
Lines 3, 4 don't do the same thing, as:
String s1 = "Java"; may reuse an instance from the string constant pool if one is available, whereas new String("Java"); creates a new and referentially distinct instance of a String object.
Therefore, Lines 3 and 4 don't do the same thing.
Now, lets have a look at the following code:
String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2); // true
s2 = new String("Java");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
== on two reference types is a reference identity comparison. Two objects that are equals are not necessarily ==. Usually, it is wrong to use == on reference types, and most of the time equals need to be used instead.
Initializing String using a new keyword String s2 = new String("Java"); creates a new object in the heap of memory. String initialized through this method is mutable means to say the value of the string can be reassigned after initialization.
Whereas, String s1 = "Java" direct String initialization using the Literal creates an object in the pooled area of memory. String created through Literal doesn’t create a new object. It just passed the reference to the earlier created object.
This question already has answers here:
Java Object Assignment
(8 answers)
Closed 2 years ago.
So I was watching an introductory Java tutorial, and it said that if you declare a reference type, and another one equal to that object, if you change the first object, the second one will change as well. For example:
Point p1 = new Point(1, 1);
Point p2 = p1;
p1.x = 5;
System.out.println(p2);
and this would give me an output of
java.awt.Point[x=5,y=1]
However, I tried this with a String:
String s1 = "Hello, World!";
String s2 = s1;
s1 = "Goodbye, World!";
System.out.println(s2);
but I got
Hello, World!
as an output.
Why does this happen, and does it mean that Strings are a special type of reference types because they are used to commonly?
Strings in Java are immutable objects. They never change. When you do a new assignment it simply creates a new String. The old one remains to be collected by the garbage collector. Your Point class is not an immutable object.
I work with a lot of things in python and it is the same situation. Take a list, for example, which has multiple values stored. That will change when you've done the equivalent of your code in python. Strings will not change as you've said. The thing with code is that objects and classes like lists will change because they're not stored in memory. They are merely references, not new objects. When you reassign a string, assignment works properly because it is just one value.
String is a 'special' object in java. It's an immutable object (Fixed and cannot be modified), and would be the only object that can be declared without the new keyword.
If you use StringBuilder, StringBuffer those are mutable String and your values will be modified upon change.
When you dive deeper, Java String comes with many confusing understanding. When you use "==", 2 different string with same value returns the same reference of the memory address. Eg.
String a1 = "abc"
String a2 = "abc"
a1 == a2 //returns true because a1 and a2 points to same reference (but not always!)
a1 == new String("abc") //returns false
/**Do use "equals", not == for string's value comparison**/
If you can wrap your mind around memory object references:
String s1 = "Hello, World!"; //let's say it's allocated to memory address 0x0012
String s2 = s1; //s2 points to same memory address 0x0012
s1 = "Goodbye, World!"; //s1 points to new memory address 0x1113
System.out.println(s2) //printing value in still in memory address 0x0012
It's equivalent as, s1 points to new Object, s2 points to the old Object.
and when you refer back to your Point example
Point p1 = new Point(1, 1);
Point p2 = p1; //p2 is referring to p1's memory address
p1.x = 5;
p1 = new Point(2,2); //Assign to new memory address, here is like the line for s1="Goodbye,world"
System.out.println(p2.x); //You now still get 5, because it's still old object.
So to fix a string that is mutable, you need something like "Class"."method" to change in order to retain the same object being modified. Hence something like:
StringBuilder sb1 = new StringBuilder("Hello World");
StringBuilder sb2 = sb1; //Points to same reference address.
sb1.append("Goodbye World");
System.out.println(sb2.toString()); //Now you get Hello WorldGoodbye World.
sb1.setLength(0).append("Goodbye World"); //clear then set to new value.
System.out.println(sb2.toString()); //Now you get Goodbye World.
This question already has answers here:
What is the difference between "text" and new String("text")?
(13 answers)
Difference between string object and string literal [duplicate]
(13 answers)
Closed 8 years ago.
what is the difference between these two implementations :
String s1 = "java";
and
String s2 = new String("java");
is s1 is able to perform all the functions that s2 will do?? like to uppercase, append etc..
The only Difference is String s1 = "java" will create a String Literal and it will be stored in a String Pool And for String s2 = new Sting("java") an Instance object will be created plus a String Literal in String pool.
For Second part Yes you can, Since its a Variable and variable can access library function using dot operator. so s1.toUpperCase() and s2.toUpperCase().
Ex.
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String s1 = new String("java");
System.out.println(s1.toUpperCase());
String s2 = "java";
System.out.println(s2.toUpperCase());
}
}
Result : JAVA JAVA
For the first part of question, it has been asked many times and answered many times like here and I don't think we need a better answer there
For the second part of your question,
is s1 is able to perform all the functions that s2 will do?? like to
uppercase, append etc..
Absolutely yes! Try "hello".toUpperCase()
String s = "abc"; // creates one String object and one reference variable
In this simple case, "abc" will go in the pool and s will refer to it.
String s = new String("abc"); // creates two objects and one reference variable
In this case, because we used the new keyword, Java will create a new String object
in normal (nonpool) memory, and s will refer to it. In addition, the literal "abc" will
be placed in the poo
String s1="java" // will store in string pool
String s2=new String("java"); //will store in heap
so s1==s2 results in false.
if You want s2 also in pool then u have to call s2.intern(). After that s1==s2 results in true.
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
thank you for taking the time to read this. Sorry if my question is dumb, I tried searching but couldn't quite figure out why I'm having this problem. I was trying to test some code for another application, but I'm having issues. Perhaps I just don't understand arrays properly.
I have a method named halfStepUp in a class named Transpose that, for testing purposes, should return "c#" if given "c" and "d#" if given "d". This is the code:
public class Transpose{
public static String halfStepUp(String note){
String n = null;
if (note == "c") n = "c#";
if (note == "d") n = "d"#;
return n;
}
}
I have the following code in my main method:
String [] scale = new String[2];
scale[0] = "c";
scale[1] = "d";
System.out.println(Transpose.halfStepUp(scale[0]));
This prints "null." What am I doing wrong?
I know the method works because if I use
System.out.println(Transpose.halfStepUp("c"));
It works fine. The solution is probably embarrassingly easy but I couldn't find a good way to word it when searching for help.
Thanks again for reading, and any answers are greatly appreciated!
To add a little more info to the answers you already got:
Java has two types of storage. One is the stack, which includes variable names and their values. One is the heap, that is just a huge collections of free-floating objects.
Now, if you're working with primitive types (like int, boolean or char), assigning a variable like
int myInt = 1;
pushes that variable on thje stack - the name is myInt, the value is 1.
If you, however, have an object (like strings are), assigning a variable does a little bit more.
String myString = "Hey!";
now creates an object (instance of String) somewhere on the heap. It has no name there, only some address in the memory where it can be found.
In addition to that, it pushes a variable on the stack. The name is myString - and the value is the address of the object on the heap.
So why is this relevant to comparing variables? Because == compares values of variables. ON THE STACK, that is. SO if you compare primitive types, everything works as expected. But if you're comparing Objects, == still only compares the values of the variables - which is, in that case, the addresses to the objects. If the addresses are the same, it returns true. That does mean, both variables point to the same object. If the addresses are different, == returns false., Without ever looking at the heap, where the objects really are.
An example:
String a = new String("Hey!");
String b = a;
if (a == b) System.out.println("true");
else System.out.println("false");
will echo "true" - because both variables contain the same object.
String a = new String("Hey!");
String b = new String("Hey!");
if (a == b) System.out.println("true");
else System.out.println("false");
will echo "false" - because you have two objects on the heap now, and a points to the one, while b points to the other. So while the contents of both objects may be the same, the contents of a and b on the stack are different.
Therefore, to compare any object, always use .equals() if you want to compare contents, not instance-equality.
[Addendum]:
With strings, this is even more complicated. As you already found out already,
String a = "Hey!"; // mention the difference to the example above:
String b = "Hey!"; // I did NOT use the `String()` cosntructor here!
if (a == b) System.out.println("true");
else System.out.println("false");
will actually give you "true". Now why is THAT? One might think that we still create two objects. But actually, we are not.
String is immutable. That means, once a String has been created, it cannot be modified. Ever. Don'T believe that? Take a look!
String myString = "test"; // we create one instance of String here
myString += " and more"; // we create another instance of String (" and more")
// and append that. Did we modify the instance stored in
// myString now? NO! We created a third instance that
// contains "test and more".
Therefore, there is no need to create additional instances of String with the same content - which increases performance, as Strings are widely used, in masses, so we want to have as few of them as possible.
To archive that, the JVM maintains a list of String Objects we already created. And every time we write down a String literal (that is something like "Hey!"), it looks in that lists and checks if we already created an instance that has that value. If so, it returns a pointer to that exact same instance instead of creating a new one.
And THIS is, why "Hey!" == "Hey!" will return true.
You should use the .equals() method when comparing strings, not ==. The == operator compares the references to see if they are pointing to the same underlying object. The .equals() method, compares the underlying objects to each other to see if they are semantically equivalent.
Try this instead: (edited from comments)
public class Transpose{
public static String halfStepUp(String note){
String n = null;
if ("c".equals(note)) n = "c#"; //using .equals as a string comparison
if ("d".equals(note)) n = "d#"; //not "d"#
return n;
}
}
The glitch is in this line:
if (note == "c") n = "c#";
This compares strings by address, not by value. Try using "c".equals(note) instead.
class Transpose{
public static String halfStepUp(String note){
String n = null;
if (note == "c") n = "c#";
if (note == "d") n = "d#";
return n;
}
}
public class TransposeTest {
public static void main(String... args) {
String [] scale = new String[2];
scale[0] = "c";
scale[1] = "d";
System.out.println(Transpose.halfStepUp(scale[0]));
}
}
working code
This question already has answers here:
What is the Java string pool and how is "s" different from new String("s")? [duplicate]
(5 answers)
Closed 9 years ago.
in java, i have created 2 string literals having same value
String a = "Hello";
String b = "Hello";
now both of them should have same reference
System.out.println(a==n); // returns true
but when i do
b+=" World";
System.out.println(a==b); // returns false
Now i have 2 questions here
1. why a and b are not referencing to same object after 'b+=' operation?
2. how come i'm able to change string b without any error?(because i have read String class is immutable)
The reason you can change b is because you're technically making a new String object and assigning it to the existing reference.
b += " World"
is the same as
b = b + " World";
b is technically pointing to a new String object. So to start out, a and b are pointing to the same object, but when b is modified it is now a different object, so a will not equal "Hello World" and a==b will now be false.
For examples of mutable String classes, try StringBuffer or StringBuilder. You can use their .append() method to add to the string, along with other methods to modify it.
When you do b+=" World" you are creating a new string instance, of course this does not point to the same old string anymore.
You are not changing the old string, instead you are creating a new string and assigning it to the variable b. Use the final modifier if you want to always refer to the same object with that variable.
a and b are pointing to a String object. Modifying b, means you are now pointing to a new object.
Because Strings are immutable, when you "modify" a string, a new object is created. That's why the second is no longer the same.