Java¶
A collection of Java Internals insides.
Inner classes¶
Question
How are inner classes handled by the compiler?
Let's define an outer class OuterClass
and an inner class InnerClass
, which will be a nested class with respect to
OuterClass
:
OuterClass.java | |
---|---|
Compile it:
Notice that the compiler creates two .class files:
OuterClass.class
OuterClass$InnerClass.class
Let’s analyze the bytecode of OuterClass.class
:
Output, excluding meta-information:
public final class OuterClass
minor version: 0
major version: 67
flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER
this_class: #7 // OuterClass
super_class: #2 // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 3
Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "<init>":()V
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Class #8 // OuterClass
#8 = Utf8 OuterClass
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 SourceFile
#12 = Utf8 OuterClass.java
#13 = Utf8 NestMembers
#14 = Class #15 // OuterClass$InnerClass
#15 = Utf8 OuterClass$InnerClass
#16 = Utf8 InnerClasses
#17 = Utf8 InnerClass
{
OuterClass();
descriptor: ()V
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
line 3: 4
}
SourceFile: "OuterClass.java"
NestMembers:
OuterClass$InnerClass
InnerClasses:
public final #17= #14 of #7; // InnerClass=class OuterClass$InnerClass of class OuterClass
Now let’s analyze the bytecode of OuterClass$InnerClass.class
:
public final class OuterClass$InnerClass
minor version: 0
major version: 67
flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER
this_class: #7 // OuterClass$InnerClass
super_class: #2 // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 3
Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "<init>":()V
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Class #8 // OuterClass$InnerClass
#8 = Utf8 OuterClass$InnerClass
#9 = Utf8 (LOuterClass;)V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 MethodParameters
#13 = Utf8 SourceFile
#14 = Utf8 OuterClass.java
#15 = Utf8 NestHost
#16 = Class #17 // OuterClass
#17 = Utf8 OuterClass
#18 = Utf8 InnerClasses
#19 = Utf8 InnerClass
{
OuterClass$InnerClass(OuterClass);
descriptor: (LOuterClass;)V
flags: (0x0000)
Code:
stack=1, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
line 7: 4
MethodParameters:
Name Flags
<no name> final mandated
}
SourceFile: "OuterClass.java"
NestHost: class OuterClass
InnerClasses:
public final #19= #7 of #16; // InnerClass=class OuterClass$InnerClass of class OuterClass
Default interface methods¶
Question
Where are default and non-default interface methods included during compilation?
Only default method¶
Assume we have an interface with a default method:
Now, let’s declare a class that implements this interface:
Let’s compile it:
As a result, we get two .class
files:
public interface IContract
minor version: 0
major version: 67
flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
this_class: #1 // IContract
super_class: #3 // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 1
Constant pool:
#1 = Class #2 // IContract
#2 = Utf8 IContract
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 nothing
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 SourceFile
#10 = Utf8 IContract.java
{
public default void nothing();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 4: 0
}
public final class ContractImpl implements IContract
minor version: 0
major version: 67
flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER
this_class: #7 // ContractImpl
super_class: #2 // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 1
Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "<init>":()V
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Class #8 // ContractImpl
#8 = Utf8 ContractImpl
#9 = Class #10 // IContract
#10 = Utf8 IContract
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 SourceFile
#14 = Utf8 ContractImpl.java
{
ContractImpl();
descriptor: ()V
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
line 4: 4
}
As we can see, ContractImpl.class
does not have a default implementation of the nothing()
method from the
IContract
interface, but it has a reference to it.
Default and non-default methods¶
Now let's add a non-default method to IContract
:
IContract.java | |
---|---|
And implement it in ContractImpl.java
:
ContractImpl.java | |
---|---|
Let's compile it and see the javap -v
output:
public interface IContract
minor version: 0
major version: 67
flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
this_class: #1 // IContract
super_class: #3 // java/lang/Object
interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
#1 = Class #2 // IContract
#2 = Utf8 IContract
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 nothing
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 notDefault
#10 = Utf8 SourceFile
#11 = Utf8 IContract.java
{
public default void nothing();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 4: 0
public abstract void notDefault();
descriptor: ()V
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
}
public final class ContractImpl implements IContract
minor version: 0
major version: 67
flags: (0x0031) ACC_PUBLIC, ACC_FINAL, ACC_SUPER
this_class: #7 // ContractImpl
super_class: #2 // java/lang/Object
interfaces: 1, fields: 0, methods: 2, attributes: 1
Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "<init>":()V
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Class #8 // ContractImpl
#8 = Utf8 ContractImpl
#9 = Class #10 // IContract
#10 = Utf8 IContract
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 notDefault
#14 = Utf8 SourceFile
#15 = Utf8 ContractImpl.java
{
ContractImpl();
descriptor: ()V
flags: (0x0000)
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
line 3: 4
public void notDefault();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 8: 0
}
As expected, the non-default method is included in ContractImpl.class
, while the default one is not.
Package name¶
Question
Why can’t we create a package that contains a directory named class
or interface
?
Here is the complete set of keywords
that cannot be used as source directory names:
abstract | continue | for | new | switch |
assert | default | if | package | synchronized |
boolean | do | goto | private | this |
break | double | implements | protected | throw |
byte | else | import | public | throws |
case | enum | instanceof | return | transient |
catch | extends | int | short | try |
char | final | interface | static | void |
class | finally | long | strictfp | volatile |
const | float | native | super | while |
Also, here are the non-keyword
words that cannot be used as source directory names:
true | false | null |
Let’s create a package named test.public
with a simple Main.java
file inside:
Main.java | |
---|---|
Now try compiling it:
Output:
[parsing started SimpleFileObject[/test/public/Main.java]]
Main.java:1: error: <identifier> expected
package test.public
^
Main.java:2: error: reached end of file while parsing
[parsing completed 12ms]
[loading /modules/java.base/module-info.class]
...
Result
As we can see, the compiler cannot compile the .java
file into a .class
file because it cannot process a
package name that contains a reserved keyword.
Static interface method¶
Question
How are static interface methods handled by the compiler?
Starting from Java 8
, the Java compiler allows us to declare static methods in interfaces, which must be implemented
directly within the interface. In contrast to default interface methods, static methods cannot be overridden in classes
that implement the interface.
In terms of Java bytecode, a static interface method is:
public interface IContract
minor version: 0
major version: 67
flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
this_class: #1 // IContract
super_class: #3 // java/lang/Object
interfaces: 0, fields: 0, methods: 1, attributes: 1
Constant pool:
#1 = Class #2 // IContract
#2 = Utf8 IContract
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 nothing
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 SourceFile
#10 = Utf8 IContract.java
{
public static void nothing();
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=0, args_size=0
0: return
LineNumberTable:
line 7: 0
}
To call this method, you must use the following notation:
Result
Defining a static method within an interface is identical to defining one in a class.
Object's Class¶
Question
What is .class
and what is the difference between it and the getClass()
method?
final class Referencable {
Referencable() {
}
}
public final class Main {
public static void main(String[] args) {
final Class<? extends Referencable> clazz0 =
Referencable.class; // (1)!
final Class<? extends Referencable> clazz1 =
new Referencable().getClass(); // (2)!
System.out.println(clazz0 == clazz1); // true
}
}
-
.class
is a language keyword -
getClass()
is a method on anObject
's class
Let's compile it and look only at the main(String[] args)
part:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: ldc #7 // class Referencable
2: astore_1
3: new #7 // class Referencable
6: dup
7: invokespecial #9 // Method Referencable."<init>":()V
10: invokevirtual #10 // Method java/lang/Object.getClass:()Ljava/lang/Class;
13: astore_2
14: return
}
Result
Calling .class
on a type is equivalent to calling getClass()
on an instance of that type.