Skip to content

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
1
2
3
4
5
6
7
8
9
public final class OuterClass {
    OuterClass() {
    }

    public final class InnerClass {
        InnerClass() {
        }
    }
}

Compile it:

javac OuterClass.java

Notice that the compiler creates two .class files:

  1. OuterClass.class
  2. OuterClass$InnerClass.class

Let’s analyze the bytecode of OuterClass.class:

javap -v OuterClass.class

Output, excluding meta-information:

OuterClass.class
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:

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:

IContract.java
1
2
3
4
5
public interface IContract {
    default void nothing() {
        // do nothing
    }
}

Now, let’s declare a class that implements this interface:

ContractImpl.java
1
2
3
4
public final class ContractImpl implements IContract {
    ContractImpl() {
    }
}

Let’s compile it:

javac ContractImpl.java

As a result, we get two .class files:

IContract.class
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
}
ContractImpl.class
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
1
2
3
4
5
6
7
public interface IContract {
    default void nothing() {
        // do nothing
    }

    void notDefault();
}

And implement it in ContractImpl.java:

ContractImpl.java
1
2
3
4
5
6
7
8
9
public final class ContractImpl implements IContract {
    ContractImpl() {
    }

    @Override
    public void notDefault() {
        // nothing
    }
}

Let's compile it and see the javap -v output:

IContract.class
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
}
ContractImpl.class
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
package test.public

Now try compiling it:

javac -verbose Main.java

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.

IContract.java
1
2
3
4
5
interface IContract {
    static void nothing() {
        // do nothing 
    }
}

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:

IContract.nothing()

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
    }
}
  1. .class is a language keyword

  2. getClass() is a method on an Object's class

Let's compile it and look only at the main(String[] args) part:

Main.class
  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.

Comments