I'm a C++ guy learning Java. I'm reading Effective Java and something confused me. It says never to write code like this:
String s = new String("silly");
Because it creates unnecessary String
objects. But instead it should be written like this:
String s = "No longer silly";
Ok fine so far...However, given this class:
public final class CaseInsensitiveString {
private String s;
public CaseInsensitiveString(String s) {
if (s == null) {
throw new NullPointerException();
}
this.s = s;
}
:
:
}
CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
String s = "polish";
Why is the first statement ok? Shouldn't it be
CaseInsensitiveString cis = "Polish";
How do I make
CaseInsensitiveString
behave likeString
so the above statement is OK (with and without extendingString
)? What is it about String that makes it OK to just be able to pass it a literal like that? From my understanding there is no "copy constructor" concept in Java?
Both str1 and str2 belongs to tha same String object, "foo", b'coz Java manages Strings in StringPool, so if a new variable refers to the same String, it doesn't create another one rather assign the same alerady present in StringPool.
Here both str1 and str2 belongs to different Objects, b'coz new String() forcefully create a new String Object.
CaseInsensitiveString and String are different objects. You can't do:
because "Polish" is a String, not a CaseInsensitiveString. If String extended CaseInsensitiveString String then you'd be OK, but obviously it doesn't.
And don't worry about the construction here, you won't be making unecessary objects. If you look at the code of the constructor, all it's doing is storing a reference to the string you passed in. Nothing extra is being created.
In the String s = new String("foobar") case it's doing something different. You are first creating the literal string "foobar", then creating a copy of it by constructing a new string out of it. There's no need to create that copy.
You can't. Things in double-quotes in Java are specially recognised by the compiler as Strings, and unfortunately you can't override this (or extend
java.lang.String
- it's declaredfinal
).First, you can't make a class that extends from String, because String is a final class. And java manage Strings differently from other classes so only with String you can do
But whit your class you have to invoke the constructor. So, that code is fine.
literal will go in pool and s1 will refer.
this time it will check "foo" literal is already available in StringPool or not as now it exist so s2 will refer the same literal.
"foo" literal will be created in StringPool first then through string arg constructor String Object will be created i.e "foo" in the heap due to object creation through new operator then s3 will refer it.
same as s3
so
System.out.println(s1==s2);// **true** due to literal comparison.
and
System.out.println(s3==s4);// **false** due to object
comparison(s3 and s4 is created at different places in heap)
Enough has been said from the first point. "Polish" is an string literal and cannot be assigned to the CaseInsentiviveString class.
Now about the second point
Although you can't create new literals, you can follow the first item of that book for a "similar" approach so the following statements are true:
Here's the code.
// Test the class using the "assert" keyword
That is, create an internal pool of CaseInsensitiveString objects, and return the corrensponding instance from there.
This way the "==" operator returns true for two objects references representing the same value.
This is useful when similar objects are used very frequently and creating cost is expensive.
The string class documentation states that the class uses an internal pool
The class is not complete, some interesting issues arises when we try to walk the contents of the object at implementing the CharSequence interface, but this code is good enough to show how that item in the Book could be applied.
It is important to notice that by using the internalPool object, the references are not released and thus not garbage collectible, and that may become an issue if a lot of objects are created.
It works for the String class because it is used intensively and the pool is constituted of "interned" object only.
It works well for the Boolean class too, because there are only two possible values.
And finally that's also the reason why valueOf(int) in class Integer is limited to -128 to 127 int values.