class MyOuterClass { // outer class class MyInnerClass { // inner class } }Notes:
class MyOuterClass { // outer class class MyInnerClass { // inner class } MyInnerClass myInnerClass_1 = new MyInnerClass(); // declare a variable and create an instance of the inner class void createInstanceOfMyInnerClass() { MyInnerClass myInnerClass_2; // declare variable myInnerClass_2 = new MyInnerClass(); // create instance } }It is not possible to instantiate the inner class directly from a static method of the outer class. The compiler will show an error:
class MyOuterClass { // outer class class MyInnerClass { // inner class } static void createInstanceOfMyInnerClass() { MyInnerClass myInnerClass; // OK: declaration is fine myInnerClass = new MyInnerClass(); // Compiler error: No enclosing instance of type MyOuterClass is accessible. // Must qualify the allocation with an enclosing instance of type MyOuterClass (e.g. x.new A() where x is an instance of MyOuterClass). } }As indicated in the compiler error, you must go through an instance of the outer class to instantiate the inner class:
class MyOuterClass { // outer class class MyInnerClass { // inner class } static void createInstanceOfMyInnerClass() { MyInnerClass myInnerClass; // OK: declaration is fine MyOuterClass myOuterClass = new MyOuterClass(); myInnerClass = myOuterClass.new MyInnerClass(); // OK myInnerClass = new MyOuterClass().new MyInnerClass(); // OK: using anonymous outer instance } }
public class MyOuterClass { class MyInnerClass { // inner class private static final int CONSTANT = 0; // OK: compile-time constant private static int var = 0; // OK: The field var can be declared static public static int getVar() { // OK: The method getVar can be declared static return var; } public void setVar(int var) { this.var = var; } } public static void main(String[] args) { MyInnerClass myInnerClass = new MyOuterClass().new MyInnerClass(); System.out.println(MyInnerClass.CONSTANT); System.out.println(MyInnerClass.var); myInnerClass.setVar(1); System.out.println(MyInnerClass.getVar()); } }
class MyOuterClass { // outer class class MyInnerClass { // inner class } } class MainClass { MyInnerClass myInnerClass1; // Compiler error: MyInnerClass cannot be resolved to a type Object obj1 = new MyInnerClass(); // Compiler error: MyInnerClass cannot be resolved to a type MyOuterClass.MyInnerClass myInnerClass2; // OK: declare variable of inner class type Object obj2 = new MyOuterClass().new MyInnerClass(); // OK: using anonymous outer class instance { MyOuterClass myOuterClass = new MyOuterClass(); Object obj3 = myOuterClass.new MyInnerClass(); // OK: using MyOuterClass instance } }
public
, protected
, private
,
or have no modifier at all (in which case it has package-private
access).class MyOuterClass { // outer class /*[public|protected|private]*/ class MyInnerClass { // inner class } }Visibility rules apply when the inner class is declared as
protected
or private
.private
.class MyOuterClass { // outer class private class MyInnerClass { // private inner class public void doSomething() { System.out.println("MyInnerClass doing something ..."); } } public MyInnerClass initMyInnerClass() { return new MyInnerClass(); // OK: within outer class } public void doSomething() { new MyInnerClass().doSomething(); // OK: within outer class } } class MainClass { public static void main(String[] args) { MyOuterClass myOuterClass = new MyOuterClass(); myOuterClass.doSomething(); // OK myOuterClass.initMyInnerClass().doSomething(); // Compiler error: The type MyOuterClass.MyInnerClass is not visible MyOuterClass.MyInnerClass myInnerClass; // Compiler error: The type MyOuterClass.MyInnerClass is not visible myInnerClass = myOuterClass.new MyInnerClass(); // Compiler error: The type MyOuterClass.MyInnerClass is not visible } }
abstract
or final
modifiers (one or the other, but not both at the same time!).class MyOuterClass { // outer class /*[abstract|final]*/ class MyInnerClass { // inner class } }
OuterClassName.this
to reference the outer class members from within the inner class.
Otherwise, the inner class's members will be used by default.this
always refers to the instance of the currently executing class (whether it's the inner or the outer class).class MyOuterClass { // outer class public class MyInnerClass { // inner class private Integer step = 2; // shadows outer class's step field public void setNextNumber() { var = var + step; // uses inner class's step (2), outer class's var (1) // equivalent to: MyOuterClass.this.var = MyOuterClass.this.var + this.step; } public void setNextNumberUsingOuterStep() { var = var + MyOuterClass.this.step; // explicitly uses outer class's step (1) } } private Integer var = 0; private Integer step = 1; public Integer getVar() { return var; // equivalent to: return this.var; } } class MainClass { public static void main(String[] args) { MyOuterClass myOuterClass = new MyOuterClass(); MyOuterClass.MyInnerClass myInnerClass = myOuterClass.new MyInnerClass(); myInnerClass.setNextNumber(); System.out.println(myOuterClass.getVar()); myInnerClass.setNextNumberUsingOuterStep(); System.out.println(myOuterClass.getVar()); } }
class MyOuterClass { // outer class public static class MyInnerClass { // static inner class static Integer var = 0; Integer step = 0; void doSomething() { } static void doSomethingElse() { } } }
class MyOuterClass { // outer class public static class MyInnerClass { // static inner class static Integer var = 0; Integer step = 1; void doSomething() { } static void doSomethingElse() { } } } class MainClass { public static void main(String[] args) { MyOuterClass.MyInnerClass.var = 1; MyOuterClass.MyInnerClass.doSomethingElse(); } }
class MyOuterClass { // outer class public static class MyInnerClass { // static inner class } } class MainClass { public static void main(String[] args) { MyOuterClass.MyInnerClass myInnerClass = new MyOuterClass.MyInnerClass(); } }
class MyOuterClass { // outer class public static class MyInnerClass { // static inner class void doSomething() { MyOuterClass.var = 1; // OK: accessing static member // Cannot make a static reference to the non-static field MyOuterClass.this.step = 1; // Compiler error: No enclosing instance of type MyOuterClass is accessible MyOuterClass.initVar(); // OK: calling static method // Cannot make a static reference to the non-static method MyOuterClass.this.initStep(); // Compiler error: No enclosing instance of the type MyOuterClass is accessible in scope } static void doSomethingElse() { MyOuterClass.var = 1; // OK: accessing static member // Cannot make a static reference to the non-static field step = 1; // Compiler error: Cannot make a static reference to the non-static field step MyOuterClass.initVar(); // OK: calling static method // Cannot make a static reference to the non-static method initStep(); // Compiler error: Cannot make a static reference to the non-static method initStep() from the type MyOuterClass } } static Integer var = 0; Integer step = 1; static void initVar() { var = 1; } void initStep() { step = 1; } }
class MainClass { public static void main(String[] args) { class MyLocalInnerClass { // local inner class } MyLocalInnerClass myLocalInnerClass = new MyLocalInnerClass(); } }Notes:
class MainClass { public static void main(String[] args) { class MyLocalInnerClass1 { // local inner class } class MyLocalInnerClass2 { // local inner class } } }In this example, the compiler will generate the following .class files:
abstract
or final
(mutually exclusive).
Access modifiers like public
, private
, or protected
are not allowed:class MainClass { public void doSomething() { public class MyLocalInnerClass1 { // Compiler error: Illegal modifier for the local class MyLocalInnerClass; only abstract or final is permitted } final class MyLocalInnerClass2 { // OK } } }
class MainClass { public void doSomething() { MyLocalInnerClass myLocalInnerClass1 = new MyLocalInnerClass(); // Compiler error: MyLocalInnerClass cannot be resolved to a type class MyLocalInnerClass { // local inner class } MyLocalInnerClass myLocalInnerClass2 = new MyLocalInnerClass(); // OK: after declaration } }
class MainClass { public void doSomething() { class MyLocalInnerClass { // local inner class private static final String CONSTANT = "OK"; // OK: compile-time constant private static Integer var = 0; // Compiler error: static fields only allowed in static or top-level types public void instanceMethod() { // OK } public static void staticMethod() { // Compiler error: static methods only allowed in static or top-level types } } } }
class MainClass { private static Integer var1 = 2; private Integer var2 = 2; public static void foo1() { } public void bar1() { } public static void doSomething() { class MyLocalInnerClass { // local inner class public void foo() { Integer localVar1 = var1; // OK: static field Integer localVar2 = var2; // Compiler error: Cannot make a static reference to the non-static field var2 foo1(); // OK: static method bar1(); // Compiler error: Cannot make a static reference to the non-static method bar1() from the type MainClass } } } }However, local classes defined in non-static methods can access both static and non-static members of the outer class:
class MainClass { private static Integer var1 = 2; private Integer var2 = 2; public static void foo1() { } public void bar1() { } public void doSomething() { class MyLocalInnerClass { // local inner class public void foo() { Integer localVar1 = var1; // OK: static field Integer localVar2 = var2; // OK: instance field foo1(); // OK: static method bar1(); // OK: instance method } } } }
class MainClass { public void doSomething() { final Integer var1 = 2; // explicitly final Integer var2 = 2; // effectively final (never modified) Integer var3 = 3; var3 = 4; // not effectively final class MyLocalInnerClass { // local inner class public void foo() { Integer localVar1 = var1; // OK: final Integer localVar2 = var2; // OK: effectively final Integer localVar3 = var3; // Compiler error: Local variable var3 defined in an enclosing scope must be final or effectively final } } } }
class MainClass { Object object = new Object() { // anonymous inner class extending Object @Override public String toString() { return "anonymous inner class: toString"; } }; }In this example, a new anonymous class is created that extends the
Object
class.class MainClass { public static void main(String[] args) { Object object = new Object() { // anonymous inner class @Override public String toString() { return toStringAnonymous(); // OK: calling internal method } public String toStringAnonymous() { return "anonymous inner class"; } }; System.out.println(object.toString()); // OK: Object method object.toStringAnonymous(); // Compiler error: The method toStringAnonymous() is undefined for the type Object } }Anonymous classes can be used as method arguments for more concise code:
class MainClass { public static void main(String[] args) { processObject(new Object() { // anonymous inner class as argument @Override public String toString() { return "anonymous inner class"; } }); } public static void processObject(Object obj) { System.out.println(obj.toString()); } }Notes:
class MainClass { Object object1 = new Object() { // first anonymous inner class }; Object object2 = new Object() { // second anonymous inner class }; }Generated .class files:
abstract class MyAbstractClass { abstract void foo(); // must be implemented void doSomething() { // concrete method - can be overridden System.out.println("Concrete method"); } } class MainClass { static MyAbstractClass myAbstractClass = new MyAbstractClass() { // anonymous implementation @Override public void foo() { System.out.println("foo implementation"); } }; public static void main(String[] args) { MainClass.myAbstractClass.foo(); MainClass.myAbstractClass.doSomething(); // inherited and can be used without override } }The compiler throws an error if the implementation is incomplete:
class MainClass { MyAbstractClass incomplete = new MyAbstractClass() { // Compiler error: The type new MyAbstractClass(){} must implement the inherited abstract method MyAbstractClass.foo() }; }
interface MyInterface { void foo(); default void defaultMethod() { // default method System.out.println("Default implementation"); } } class MainClass { public static void main(String[] args) { MyInterface myInterface = new MyInterface() { // anonymous implementation @Override public void foo() { System.out.println("Interface method implementation"); } }; myInterface.foo(); myInterface.defaultMethod(); // defaultMethod() is inherited and can be used or overridden } }Functional interfaces and lambda expressions:
class MainClass { public static void main(String[] args) { // Anonymous class Runnable runnable1 = new Runnable() { @Override public void run() { System.out.println("Runnable 1 Running..."); } }; // Lambda expression Runnable runnable2 = () -> System.out.println("Runnable 2 Running..."); new Thread(runnable1, "Runnable1").start(); new Thread(runnable2, "Runnable2").start(); } }