Say i have the following line in my program:
jobSetupErrors.append("abc");
In the case above where jobSetupErrors is a StringBuilder(), what i see happen is:
New String Object is created and assigned value "abc"
value of that String object is assigned to the existing StringBuilder object
If that is correct, and I add 1 more line ...
jobSetupErrors.append("abc");
logger.info("abc");
In the above example are we creating String object separately 2 times?
If so, would it be more proper to do something like this?
String a = "abc";
jobSetupErrors.append(a);
logger.info(a);
Is this a better approach? Please advise
In the above example are we creating
String object separately 2 times?
No, because in Java String literals (anything in double-quotes) are interned. What this means is that both of those lines are referring to the same String, so no further optimization is necessary.
In your second example, you are only creating an extra reference to the same String, but this is what Java has already done for you by placing a reference to it in something called the string pool. This happens the first time it sees "abc"; the second time, it checks the pool and finds that "abc" already exists, so it is replaced with the same reference as the first one.
See http://en.wikipedia.org/wiki/String_interning for more information on String interning.
To help find out, I wrote a class like the following:
class Test {
String a = "abc" ;
StringBuilder buffer = new StringBuilder() ;
public void normal() {
buffer.append( "abc" ) ;
buffer.append( "abc" ) ;
}
public void clever() {
buffer.append( a ) ;
buffer.append( a ) ;
}
}
If we compile this, and then run javap over it to extract the bytecode:
14:09:58 :: javap $ javap -c Test
Compiled from "Test.java"
class Test extends java.lang.Object{
java.lang.String a;
java.lang.StringBuilder buffer;
Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2; //String abc
7: putfield #3; //Field a:Ljava/lang/String;
10: aload_0
11: new #4; //class java/lang/StringBuilder
14: dup
15: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
18: putfield #6; //Field buffer:Ljava/lang/StringBuilder;
21: return
public void normal();
Code:
0: aload_0
1: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
4: ldc #2; //String abc
6: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
9: pop
10: aload_0
11: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
14: ldc #2; //String abc
16: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: pop
20: return
public void clever();
Code:
0: aload_0
1: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
4: aload_0
5: getfield #3; //Field a:Ljava/lang/String;
8: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: pop
12: aload_0
13: getfield #6; //Field buffer:Ljava/lang/StringBuilder;
16: aload_0
17: getfield #3; //Field a:Ljava/lang/String;
20: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: return
}
We can see 2 things.
First, the normal method is using the same String instance for both of those calls (indeed it is the same literal as is set to the a member variable of this class in the initialisation block)
And secondly, the clever method is longer than the normal one. This is because extra steps are required to fetch the property out of the class.
So the moral of the story is that 99% of the time, Java does things the right way on it's own, and theres no need in trying to be clever ;-) (and javap is a really cool tool for when you want to know exactly what's going on)
Related
I have the following code:
StringBuilder str = new StringBuilder("foo");
for(Field f : fields){
str.append("|" + f);
}
str.append("|" + bar);
String result = str.toString();
I know compiler will optimize string concatenation "|" + f and replace it with StringBuilder. However will a new StringBuilder be created or the existing str will be used in Java 8? How about Java 9?
By default in java-9 there will be no StringBuilder for string concatenation; it is a runtime decision how it's made via the invokedynamic. And the default policy is not a StringBuilder::append one.
You can also read more here.
Under java-8 a new one will be created (really easy to spot two occurrences of invokespecial // Method java/lang/StringBuilder."<init>":()V in the de-compiled bytecode.
Also, you have a suggestion about append.append...; just notice that this is much better than sb.append ... sb.append, and here is why.
As String concatenation optimization is performed by the Java compiler, you can see what it does by decompiling the byte code:
$ cat Test.java
interface Field {}
public class Test {
static String toString(Field[] fields, Object bar) {
StringBuilder str = new StringBuilder("foo");
for(Field f : fields){
str.append("|" + f);
}
str.append("|" + bar);
return str.toString();
}
}
$ javac Test.java
$ javap -c Test.class
Compiled from "Test.java"
public class stackoverflow.Test {
public stackoverflow.Test();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
static java.lang.String toString(stackoverflow.Field[], java.lang.Object);
Code:
0: new #16 // class java/lang/StringBuilder
3: dup
4: ldc #18 // String foo
6: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
9: astore_2
10: aload_0
11: dup
12: astore 6
14: arraylength
15: istore 5
17: iconst_0
18: istore 4
20: goto 53
23: aload 6
25: iload 4
27: aaload
28: astore_3
29: aload_2
30: new #16 // class java/lang/StringBuilder
33: dup
34: ldc #23 // String |
36: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
39: aload_3
40: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
43: invokevirtual #29 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
46: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
49: pop
50: iinc 4, 1
53: iload 4
55: iload 5
57: if_icmplt 23
60: aload_2
61: new #16 // class java/lang/StringBuilder
64: dup
65: ldc #23 // String |
67: invokespecial #20 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
70: aload_1
71: invokevirtual #25 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
74: invokevirtual #29 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
77: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
80: pop
81: aload_2
82: invokevirtual #29 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
85: areturn
}
As you can see, the code invokes StringBuilder constructors (Method java/lang/StringBuilder."<init>":) in 3 places, so new StringBuilders would be created in each iteration (unless the just-in-time compiler performs fancy optimization).
This is very unlikely to be a significant performance problem, but in the unlikely case it is you can easily fix this by rewriting to
str.append("|").append(f);
As per the Java 9 API documentation
Implementation Note:
The implementation of the string concatenation operator is left to the discretion of a Java compiler, as long as the compiler ultimately conforms to The Java™ Language Specification. For example, the javac compiler may implement the operator with StringBuffer, StringBuilder, or java.lang.invoke.StringConcatFactory depending on the JDK version. The implementation of string conversion is typically through the method toString, defined by Object and inherited by all classes in Java.
According to this it will create a new String builder each iteration in your case. So, as mentioned by several people here, using the below code is more optimized
append("|").append(f)
You can find API Documentation here
I have a simple question about strings in Java. The following segment of simple code just concatenates two strings and then compares them with ==.
String str1="str";
String str2="ing";
String concat=str1+str2;
System.out.println(concat=="string");
The comparison expression concat=="string" returns false as obvious (I understand the difference between equals() and ==).
When these two strings are declared final like so,
final String str1="str";
final String str2="ing";
String concat=str1+str2;
System.out.println(concat=="string");
The comparison expression concat=="string", in this case returns true. Why does final make a difference? Does it have to do something with the intern pool or I'm just being misled?
When you declare a String (which is immutable) variable as final, and initialize it with a compile-time constant expression, it also becomes a compile-time constant expression, and its value is inlined by the compiler where it is used. So, in your second code example, after inlining the values, the string concatenation is translated by the compiler to:
String concat = "str" + "ing"; // which then becomes `String concat = "string";`
which when compared to "string" will give you true, because string literals are interned.
From JLS §4.12.4 - final Variables:
A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.
Also from JLS §15.28 - Constant Expression:
Compile-time constant expressions of type String are always "interned" so as to share unique instances, using the method String#intern().
This is not the case in your first code example, where the String variables are not final. So, they are not a compile-time constant expressions. The concatenation operation there will be delayed till runtime, thus leading to the creation of a new String object. You can verify this by comparing byte code of both pieces of code.
The first code example (non-final version) is compiled to the following byte code:
Code:
0: ldc #2; //String str
2: astore_1
3: ldc #3; //String ing
5: astore_2
6: new #4; //class java/lang/StringBuilder
9: dup
10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_2
18: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9; //String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10; //Method java/io/PrintStream.println:(Z)V
42: return
Clearly it is storing str and ing in two separate variables, and using StringBuilder to perform the concatenation operation.
Whereas, your second code example (final version) looks like this:
Code:
0: ldc #2; //String string
2: astore_3
3: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2; //String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
20: return
So it directly inlines the final variable to create String string at compile time, which is loaded by ldc operation in step 0. Then the second string literal is loaded by ldc operation in step 7. It doesn't involve creation of any new String object at runtime. The String is already known at compile time, and they are interned.
As per my research, all the final String are interned in Java. From one of the blog post:
So, if you really need to compare two String using == or != make sure you call String.intern() method before making comparison. Otherwise, always prefer String.equals(String) for String comparison.
So it means if you call String.intern() you can compare two strings using == operator. But here String.intern() is not necessary because in Java final String are internally interned.
You can find more information String comparision using == operator and Javadoc for String.intern() method.
Also refer this Stackoverflow post for more information.
If you take a look at this methods
public void noFinal() {
String str1 = "str";
String str2 = "ing";
String concat = str1 + str2;
System.out.println(concat == "string");
}
public void withFinal() {
final String str1 = "str";
final String str2 = "ing";
String concat = str1 + str2;
System.out.println(concat == "string");
}
and its decompiled with javap -c ClassWithTheseMethods
versions you will see
public void noFinal();
Code:
0: ldc #15 // String str
2: astore_1
3: ldc #17 // String ing
5: astore_2
6: new #19 // class java/lang/StringBuilder
9: dup
10: aload_1
11: invokestatic #21 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
14: invokespecial #27 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
17: aload_2
18: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
...
and
public void withFinal();
Code:
0: ldc #15 // String str
2: astore_1
3: ldc #17 // String ing
5: astore_2
6: ldc #44 // String string
8: astore_3
...
So if Strings are not final compiler will have to use StringBuilder to concatenate str1 and str2 so
String concat=str1+str2;
will be compiled to
String concat = new StringBuilder(str1).append(str2).toString();
which means that concat will be created at runtime so will not come from String pool.
Also if Strings are final then compiler can assume that they will never change so instead of using StringBuilder it can safely concatenate its values so
String concat = str1 + str2;
can be changed to
String concat = "str" + "ing";
and concatenated into
String concat = "string";
which means that concate will become sting literal which will be interned in string pool and then compared with same string literal from that pool in if statement.
Stack and string conts pool concept
Let's see some byte code for the final example
Compiled from "Main.java"
public class Main {
public Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: ldc #2 // String string
2: astore_3
3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_3
7: ldc #2 // String string
9: if_acmpne 16
12: iconst_1
13: goto 17
16: iconst_0
17: invokevirtual #4 // Method java/io/PrintStream.println:(Z)V
20: return
}
At 0: and 2:, the String "string" is pushed onto the stack (from the constant pool) and stored into the local variable concat directly. You can deduce that the compiler is creating (concatenating) the String "string" itself at compilation time.
The non final byte code
Compiled from "Main2.java"
public class Main2 {
public Main2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: ldc #2 // String str
2: astore_1
3: ldc #3 // String ing
5: astore_2
6: new #4 // class java/lang/StringBuilder
9: dup
10: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
13: aload_1
14: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
17: aload_2
18: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
21: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore_3
25: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_3
29: ldc #9 // String string
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #10 // Method java/io/PrintStream.println:(Z)V
42: return
}
Here you have two String constants, "str" and "ing" which need to be concatenated at runtime with a StringBuilder.
Though, when you create using String literal notation of Java, it automatically call intern() method to put that object into String pool, provided it was not present in the pool already.
Why does final make a difference?
Compiler knows the final variable never gonna change, when we add these final variables the output goes to String Pool because of str1 + str2 expression output also never gonna change, So finally compiler calls inter method after output of the above two final variables. In case of non-final variable compiler do not call intern method.
I was wondering would there be a performance differences while i use logical operators instead of several if statements. I saw a nice link, does this apply to java also?
I just created class like
class Test{
static java.util.Random r=new java.util.Random();
boolean test(){
return r.nextBoolean();
}
void test1(){
if (test() && test() && test())
System.out.println("3x yes");
}
void test2(){
if (test())
if (test())
if (test())
System.out.println("3x yes");
}
}
compiled it then decompiled by javap -c Test and got these result
class Test {
static java.util.Random r;
Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return
boolean test();
Code:
0: getstatic #2 // Field r:Ljava/util/Random;
3: invokevirtual #3 // Method java/util/Random.nextBoole
an:()Z
6: ireturn
void test1();
Code:
0: aload_0
1: invokevirtual #4 // Method test:()Z
4: ifeq 29
7: aload_0
8: invokevirtual #4 // Method test:()Z
11: ifeq 29
14: aload_0
15: invokevirtual #4 // Method test:()Z
18: ifeq 29
21: getstatic #5 // Field java/lang/System.out:Ljava/
io/PrintStream;
24: ldc #6 // String 3x yes
26: invokevirtual #7 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
29: return
void test2();
Code:
0: aload_0
1: invokevirtual #4 // Method test:()Z
4: ifeq 29
7: aload_0
8: invokevirtual #4 // Method test:()Z
11: ifeq 29
14: aload_0
15: invokevirtual #4 // Method test:()Z
18: ifeq 29
21: getstatic #5 // Field java/lang/System.out:Ljava/
io/PrintStream;
24: ldc #6 // String 3x yes
26: invokevirtual #7 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
29: return
static {};
Code:
0: new #8 // class java/util/Random
3: dup
4: invokespecial #9 // Method java/util/Random."<init>":
()V
7: putstatic #2 // Field r:Ljava/util/Random;
10: return
}
As you can see bytecodes of test1 and test2 are same, so there is no difference in using
if (test() && test() && test())
or
if (test())
if (test())
if (test())
It's implementation dependent - so you'll need to benchmark to be sure.
Having said that, most JIT compilers are smart enough to optimise boolean comparisons very effectively so you are unlikely to see any difference.
The only area where logical operators are likely to offer a substantial advantage are in cases where you are using them to perform bitwise computations. This can be very efficient since it can result in branchless code that exploits hardware instructions.
Both forms compile to the same code. Contrary to the suggestions in other answers, this is not an 'optimization', and it would be astonishing if different compilers did different things. There is only one sensible way to compile && and that is by treating it the same as another 'if'. I can't even think of a non-sensible way.
I was curious about how the JVM works. Does the JVM acknowledge method accesibility rules like 'private' protected or is that only done at compile time?
For example, is it possible at around line37 to do some bytecode manipulation and call a protected method, say test3? Normally the compiler would not let me call that method because it is declared protected. But I was curious if that protected rule is enforced at runtime?
u.test1();
// Is it possible at runtime, to call 'test3' through bytecode manipulation
// #line37
package org.berlin.algo.basic.test;
public class RunX {
private String zzz = "rrrrr";
public void test1() {
// Note: I am intentionally use 'new' here as part of my test, not a
// good practice I know but allowed by the language.
Object x = new String("Test1 -----[1.1] " + zzz);
x = new String("Test1 --- [1.2]" + x.toString());
System.out.println(x);
this.test2();
this.test3();
}
/**
* Here, I noticed that the compiler removed my 'test2' code block.
* Does that always happen?
*/
private void test2() {
Object x = new String("Test2#line21--->>> [2.1]");
System.out.println(x);
}
protected void test3() {
Object x = new String("Test3#line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1]");
x = new String("Test3#line28--->>> [3.2]");
System.out.println(x);
}
public static void main(final String [] args) {
System.out.println("Running");
RunX u = new RunX();
u.test1();
// Is it possible at runtime, to call 'test3' through bytecode manipulation
// #line37
System.out.println("Done");
}
} // End of the Class //
/*
JVM bytecode: javap -v RunX
Compiled from "RunX.java"
public class org.berlin.algo.basic.test.RunX extends java.lang.Object
SourceFile: "RunX.java"
minor version: 0
major version: 50
Constant pool:
const #1 = class #2; // org/berlin/algo/basic/test/RunX
const #2 = Asciz org/berlin/algo/basic/test/RunX;
...
...
const #84 = Asciz SourceFile;
const #85 = Asciz RunX.java;
{
public org.berlin.algo.basic.test.RunX();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: invokespecial #10; //Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #12; //String rrrrr
7: putfield #14; //Field zzz:Ljava/lang/String;
10: return
LineNumberTable:
line 3: 0
line 5: 4
line 3: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lorg/berlin/algo/basic/test/RunX;
public void test1();
Code:
Stack=5, Locals=2, Args_size=1
0: new #21; //class java/lang/String
3: dup
4: new #23; //class java/lang/StringBuilder
7: dup
8: ldc #25; //String Test1 -----[1.1]
10: invokespecial #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
13: aload_0
14: getfield #14; //Field zzz:Ljava/lang/String;
17: invokevirtual #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
23: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
26: astore_1
27: new #21; //class java/lang/String
30: dup
31: new #23; //class java/lang/StringBuilder
34: dup
35: ldc #39; //String Test1 --- [1.2]
37: invokespecial #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
40: aload_1
41: invokevirtual #41; //Method java/lang/Object.toString:()Ljava/lang/String;
44: invokevirtual #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
47: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
50: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
53: astore_1
54: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
57: aload_1
58: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
61: aload_0
62: invokespecial #54; //Method test2:()V
65: aload_0
66: invokevirtual #57; //Method test3:()V
69: return
LocalVariableTable:
Start Length Slot Name Signature
0 70 0 this Lorg/berlin/algo/basic/test/RunX;
27 43 1 x Ljava/lang/Object;
protected void test3();
Code:
Stack=3, Locals=2, Args_size=1
0: new #21; //class java/lang/String
3: dup
4: ldc #66; //String Test3#line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1]
6: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: new #21; //class java/lang/String
13: dup
14: ldc #68; //String Test3#line28--->>> [3.2]
16: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V
19: astore_1
20: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_1
24: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: return
LocalVariableTable:
Start Length Slot Name Signature
0 28 0 this Lorg/berlin/algo/basic/test/RunX;
10 18 1 x Ljava/lang/Object;
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=2, Args_size=1
0: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #72; //String Running
5: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: new #1; //class org/berlin/algo/basic/test/RunX
11: dup
12: invokespecial #76; //Method "<init>":()V
15: astore_1
16: aload_1
17: invokevirtual #77; //Method test1:()V
20: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #79; //String Done
25: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
LocalVariableTable:
Start Length Slot Name Signature
0 29 0 args [Ljava/lang/String;
16 13 1 u Lorg/berlin/algo/basic/test/RunX;
}
*/
To the JLS!
15.12.4 Runtime Evaluation of Method Invocation
At run time, method invocation requires five steps. First, a target reference may be computed. Second, the argument expressions are evaluated. Third, the accessibility of the method to be invoked is checked. Fourth, the actual code for the method to be executed is located. Fifth, a new activation frame is created, synchronization is performed if necessary, and control is transferred to the method code.
The wording of the JLS indicates that the accessibility would be checked at runtime.
The JVM does acknowledge these. They can be overridden, by calling setAccessible(true) as Prashant Bhate does, but by default they are enforced. (See http://download.oracle.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible%28boolean%29.)
By the way, you write that "the compiler doesn't encode type method visibility rules into the Java bytecde file"; but it does. In addition to the above, it has to encode these, for a number of reasons. For example:
you can compile a class A that references class B even if you only have the compiled version of class B.
you can inspect a method's visibility via reflection (the getModifiers() method).
private methods aren't virtual -slash- can't be overridden by subclasses.
If you want to call this method from outside current class you could call private & protected methods using reflection.
Method m = RunX.class.getDeclaredMethod("test3");
m.setAccesible(true);
m.invoke(u);
however you can call this protected (and also private) method directly from main() without any issues.
Oli mentioned it rightly that ultimately you can do anything if you come to extent of byte code manipulation (if done correctly !!!).
Although I will like answer your question of accessibility honor at runtime in Java. If you have any doubts then please go ahead and use reflection to call the private method of one class from other class and you will get your answer. Java creates the function table of class at runtime when loading it and allow the refererence to the functions in limit of accessibility rule. However Java provides facility where you can call the private methods via reflection using setAccessible(true) on the method reference before invoking it.
1.
static final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
2.
System.out.println("Efficiently stored String");
Will Java compiler treat both (1 and 2) of these in the same manner?
FYI: By efficiently I am referring to runtime memory utilization as well as code execution time. e.g. can the 1st case take more time on stack loading the variable memFriendly?
This is covered in the Java Language Spec:
Each string literal is a reference
(§4.3) to an instance (§4.3.1, §12.5)
of class String (§4.3.3). String
objects have a constant value. String
literals-or, more generally, strings
that are the values of constant
expressions (§15.28)-are "interned" so
as to share unique instances, using
the method String.intern.
You can also see for yourself using the javap tool.
For this code:
System.out.println("Efficiently stored String");
final String memFriendly = "Efficiently stored String";
System.out.println(memFriendly);
javap gives the following:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String Efficiently stored String
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
11: ldc #3; //String Efficiently stored String
13: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
public static void main(String[] args) {
System.out.println("Hello world!");
String hola = "Hola, mundo!";
System.out.println(hola);
}
Here is what javap shows as the disassembly for this code:
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String Hello world!
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //String Hola, mundo!
10: astore_1
11: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
14: aload_1
15: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
18: return
Looks like the second string is being stored, whereas the first one is simply passed to the method directly.
This was built with Eclipse's compiler, which may explain differences in my answer and McDowell's.
Update: Here are the results if hola is declared as final (results in no aload_1, if I'm reading this right then it means this String is both stored and inlined, as you might expect):
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String Hello world!
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30; //String Hola, mundo!
10: astore_1
11: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
14: ldc #30; //String Hola, mundo!
16: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
19: return
In this case, the compiler will handle both the same.
Anytime a String is defined at compile time, Java will optimize the storage of Strings.
If a string is defined at runtime, Java has no way of doing the same optomization.
The code you have is equivilant because string literals are automatically interned by the compiler.
If you are really concerned about String performance and will be reusing the same strings over and over you should take a look at the intern method on the string class.
http://java.sun.com/javase/6/docs/api/java/lang/String.html#intern()