This question already has answers here:
Closed 6 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!
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;
}
}
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.
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