![]() |
|||
![]() ![]() |
![]() |
|
![]() |
StringsStrings are objects like any other object in Java. There is a java.lang.String class. However, the compiler has special support for a number of things you might want to do with strings. For example, you can create a new String object like this: String s="Hello world! "; You dont need to write String s = new String("Hello world! "); although you could. You can't do that with any other kind of object. For example, if you write Double d = 7.5; you get this compiler error: Error: Incompatible type for declaration. Can't convert double to java.lang.Double. Strings are the only class that can be initialized from literals without an explicit constructor call. In point of fact, whats really happening is that the compiler figures out that it needs to call a String constructor. It translates the statement String s=Hello world! ; into the following code: StringBuffer sb = new StringBuffer("Hello world! "); String s = new String(sb); This is not the only way the String s="Hello world! "; statement could be compiled. However, somewhere there has to be a call to a String() constructor, even if you didnt write one in the source code.
The Java compiler handles many other idioms for manipulating strings. For example, you probably know that you can concatenate strings with a plus sign (+) like this: String s3 = s2 + s1; The compiler translates that into a sequence of statements like this: StringBuffer sb = new StringBuffer(); sb.append(s1); sb.append(s2); s3 = sb.toString(); Everything is accomplished with method calls. There are no additive operators that truly operate on strings. Thats an illusion supported by the compiler. Several other illusions are also supported by the compiler. Consider this common statement: System.out.println("Count is: " + i); Here you have a String literal concatenated with an int variable. The compiler will translate this into something like this: StringBuffer sb = new StringBuffer("Count is "); sb.append(i); String s = sb.toString(); System.out.println(s); It is much simpler to just write System.out.println("Count is: " + i); than to put all the pieces together inside a StringBuffer yourself. Thats why this intelligence was built into the compiler and the language specification. Much more complex concatenations are compiled similarly. String implementationIn Java, at least the version of Java written by Sun, Strings are implemented as arrays of chars. The String class has three non-static fields: value (an array of chars), offset (an int), and count (also an int). Every string therefore takes up at least 12 bytes of heap memory. However, you also need space for the char array. The char array value has one space for each character in the string. In theory, using the offset and length fields, the value array can have slots for more chars than are actually present in the string. The offset field says which part of the string contains the first character of the string, and the length field says how many characters there are in the string. In practice, theres no way for that to happen. The value array for the string Hello world! thus has length 12. Strings are immutable. Once a string is created, it is never changed. A String variable may change, but a String object never changes. Consider the following code fragment: String s; s = "Hello World!"; s = "Goodbye World"; Here the String variable s is first null. It then refers to an object with the value Hello World! and then to a String object with the value Goodbye World. However, these are two different objects, not different versions of the same object. Similarly, if you were to concatenate another string to s, it would require the creation of still another String object. For example, String s; s = "Hello World!"; s += " Isn't it a beautiful morning?"; This compiles to this sequence of statements: StringBuffer sb = new StringBuffer("Hello World!"); sb.append(" Isn' it a beautiful morning?"); s = sb.toString(); Note that the string itself is never changed. However, in general, Java compilers are fairly smart about optimizing out unnecessary transformations to String objects. If you actually did something with the string between the second and third lines, then the compiler would be forced to actually create the String objects. For example, consider this code fragment: String s; s = "Hello World!"; System.err.println(s); s += " Isn't it a beautiful morning?"; This compiles to this sequence of statements: String s1 = new String("Hello World!"); System.out.println(s1); StringBuffer sb = new StringBuffer(); sb.append(s1); String s2 = new String(" Isn't it a beautiful morning?"); sb.append(s2); String s3 = sb.toString(); Three separate strings are created while this program runs. In the source code, however, it looks like one string is being changed. This is an illusion supported by the compiler.
|
![]() |
|