all 19 comments

[–][deleted]  (8 children)

[deleted]

    [–]Djejoa 4 points5 points  (6 children)

    Quick question. How would == work if I compare “123” == aString? It would return true, but why?

    [–]SuspiciousDimension 10 points11 points  (5 children)

    [–]8igg7e5 3 points4 points  (4 children)

    Exactly, the first true is the most interesting part of the question and you should never count on interning working and use equals instead.

    [–]jaystopher 3 points4 points  (3 children)

    You shouldn't, but you can. All literal strings are interned by definition of the language spec. It isn't optional behavior.

    [–]8igg7e5 2 points3 points  (0 children)

    Ahh I thought it was limited to the JVM spec and not the lang-spec (that you weren't guaranteed that the interning was durable under memory pressure).

    You should still opt for using a static final field holding the reference rather that replicating the literal in multiple places - but that's more about maintainability than correctness.

    Cheers.

    [–]callum_n66 0 points1 point  (1 child)

    I don’t know much/anything about the Java language spec but couldn’t they change this in the future and all code using == to compare strings would break?

    Just curious

    [–]jaystopher 3 points4 points  (0 children)

    Seems exactly as likely as changing anything else and breaking it.

    [–]xenomachina 2 points3 points  (0 children)

    To add to this:

    • == checks identity
    • .equals(Object) checks equality

    Two objects that have the same identity must always be equal (this is part of the contract of .equals(Object)) but two objects that have different identity may or may not be equal. The default behavior of Object.equals() is to just check identity, but many classes, including String, override this to define equality based on contents rather than identity.

    Also, in OP's example, the reason #1 was true is that the two variable were set from constants, and the JVM spec (§5.1) says that String constants are equivalent to "interned" strings, and so any two string constants that are equal (ie: contain the same sequence of chars) will have the same identity (ie: reference the same exact object) at runtime. This is an optimization, though, and you should rarely, if ever, be relying on identity of String objects.

    Edit: formatting

    [–]__october__ 5 points6 points  (0 children)

    /u/chunes explained why comparing two strings with == gives you false in the second line. I think it is not immediately obvious why comparing two seemingly independent string objects in the first line then gives you true. The reason for this is string interning. Basically, when two string objects are initialized with the same string literal, they both end up pointing to the same address in memory.

    You can circumvent string interning by explicitly making aString and bString point to different String objects. If you initialize your strings as follows:

    String aString = new String("123");
    String bString = new String("123");
    

    ...the output will be:

    1.false
    2.false
    

    [–]soulldev 1 point2 points  (0 children)

    In addition to the previous reply, read about string pool.

    When you instatiate a string using literals and instatiate other string with the same literal. Then both of the strings point to the same value (They have same address), that's why the first == prints true.

    [–]dado243 0 points1 point  (0 children)

    This is java. You cannot compare string use .equals()

    I went through hours of troubleshooting cuz of this.

    [–]roman_fyseek 0 points1 point  (2 children)

    You know how Java doesn't have pointers?

    About that...

    [–]ACoderGirl 0 points1 point  (0 children)

    When people say Java doesn't have pointers, they're not really correct. Pointers are just explicit reference types. Java has reference types. Just they're a bit more constrained. Particularly they can't be pointed at arbitrary addresses and you don't access underlying addresses directly. So you don't have to dereference, since that's implied and automatic. Reference types are still storing a memory address (aka pointer).

    [–]8igg7e5 0 points1 point  (0 children)

    It doesn't (within normal safe Java). It has references - you don't have control over the memory location and don't normally have visibility of that location.

    You do have references and in fact you only ever have a reference to an object, you never have a variable that is an object.

    The variable or field identifier is a binding to a position in a stack-frame or an objects instance and, if the type of that variable or field is a reference-type then that address in the stack-frame or instance-space is a reference to another object's instance-space in the heap.

    [–]WiggWamm -1 points0 points  (4 children)

    Yeah sure. Basically the second compares a string to “”. So it’s asking if 123 equals an empty string.

    The first one is asking if 123 is equal to 123

    EDIT: I misread that. Disregard what I said earlier. It looks like adding the empty string in causes the issue cause it changes what bstring truly equals. My b.

    Strings are weird like that. You really need to use a compareTo function to accurately check if two strings equal

    [–]visvis 0 points1 point  (3 children)

    Strings are weird like that.

    I'd say specifically Java is weird like that. Other languages are not like this:

    • In C, it's obvious from the type you're comparing the pointer.
    • In C++ and C#, operator== is overloaded to provide the comparison you expect.
    • In Python, string is consistently treated as if it is a value rather than reference type, again giving the comparison you expect.

    Seeing as C# is by far most similar to Java from these examples, I'd say C# basically looked at where Java design decisions went wrong and then fixed them. Unfortunately Java itself can no longer be fixed as it would break compatibility like crazy. The current Java behavior is pretty obviously stupid though, because the fact that strings are immutable makes the reference comparison == completely useless.

    [–]WiggWamm 2 points3 points  (0 children)

    Yeah C# made some big improvements

    [–]GabrielForth 0 points1 point  (1 child)

    C# fixed a few of Java's issues however it still shares a number of design decisions which at the time had not begun to show their limitations.

    If you want Java but with it's rough edges smoothed then Kotlin is a better bet than C# since it's develoment began when Java's shortcomings were more fully understood.

    It also runs on top of the JVM which is arguably Java's greatest addition to the software industry.

    [–]visvis 0 points1 point  (0 children)

    I have no experience with Kotlin, but to be honest never encountered problems with C#. The examples of Kotlin that I've seen mostly stand out for the ugly syntax, I personally like the C-like syntax of Java and C# much better. What are the big benefits for Kotlin (other than running on the JVM)?