class MyOuterClass { // outer class class MyInnerClass { // inner class } }Notes :
class MyOuterClass { // outer class class MyInnerClass { // inner class private static int var = 0; // compiler error: The field var cannot be declared static; static fields can only be declared in static or top level types public static int getVar() { // compiler error: The method getVar cannot be declared static; static methods can only be declared in a static or top level type return var; } public void setVar(int var) { // OK this.var = var; } } }La classe interne est un membre non-statique de la classe externe, donc le seul moyen d'y accéder est à travers une instance de la classe externe. Ça ne fait pas de sens, donc, de déclarer des membres (attributs et méthodes) statiques pour la classe interne.
class MyOuterClass { // outer class MyInnerClass myInnerClass_1 = new MyInnerClass(); // déclarer la variable de type de la classe interne + créer une instance de la classe interne void CreateInstanceOfMyInnerClass() { MyInnerClass myInnerClass_2; // déclarer la variable de type de la classe interne myInnerClass_2 = new MyInnerClass(); // créer une instance de la classe interne } class MyInnerClass { // inner class } }Il n'est pas possible d'instancier directement la classe interne dans une méthode statique de la classe externe. Le compilateur va afficher une erreur :
class MyOuterClass { // outer class static void CreateInstanceOfMyInnerClass() { MyInnerClass myInnerClass; // OK 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). */ } class MyInnerClass { // inner class } }Comme indiquer dans le message d'erreur du compilateur, il faut passer par une instance de la classe externe pour pouvoir instancier la classe interne :
class MyOuterClass { // outer class static void CreateInstanceOfMyInnerClass() { MyInnerClass myInnerClass; // OK MyOuterClass myOuterClass = new MyOuterClass(); myInnerClass = myOuterClass.new MyInnerClass(); // OK myInnerClass = new MyOuterClass().new MyInnerClass(); // OK } class MyInnerClass { // inner class } }
class MyOuterClass { // outer class class MyInnerClass { // inner class } } public class MyTest1 { public static void main(String[] args) { MyInnerClass myInnerClass; // compiler error: MyInnerClass cannot be resolved to a type myInnerClass = new MyInnerClass(); // compiler error: MyInnerClass cannot be resolved to a type } }
class MyOuterClass { // outer class class MyInnerClass { // inner class } } public class MyTest1 { public static void main(String[] args) { MyOuterClass.MyInnerClass myInnerClass; // création de la variable de type de la classe interne } }
class MyOuterClass { // outer class class MyInnerClass { // inner class } } public class MyTest1 { public static void main(String[] args) { MyOuterClass.MyInnerClass myInnerClass; MyOuterClass myOuterClass = new MyOuterClass(); myInnerClass = myOuterClass.new MyInnerClass(); myInnerClass = new MyOuterClass().new MyInnerClass(); // instance anonyme de la clase externe } }
public
, protected
, private
,
ou eventuellement n'avoir aucun de ces modificateurs d'accès (dans ce cas elle aura l'accès default
).class MyOuterClass { // outer class /*[public|protected|private]*/ class MyInnerClass { // inner class } }Les règles de visibilités s'appliquent lorsque la classe interne est déclarée
protected
et private
.class MyOuterClass { // outer class private Integer var = 0; public Integer getVar() { return var; } public MyInnerClass initMyInnerClass() { MyInnerClass myInnerClass = new MyInnerClass(); return myInnerClass; } public void setNextNumberFromOuterClass() { MyInnerClass myInnerClass = new MyInnerClass(); // OK myInnerClass.setNextNumberFromInnerClass(); } private class MyInnerClass { // inner class public void setNextNumberFromInnerClass() { ++var; } } } public class MyTest1 { public static void main(String[] args) { MyOuterClass myOuterClass = new MyOuterClass(); myOuterClass.setNextNumberFromOuterClass(); System.out.println(myOuterClass.getVar()); myOuterClass.initMyInnerClass().setNextNumberFromInnerClass(); // compiler error: The type MyOuterClass.MyInnerClass is not visible System.out.println(myOuterClass.getVar()); 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 myInnerClass.setNextNumberFromInnerClass(); // compiler error: The type MyOuterClass.MyInnerClass is not visible System.out.println(myOuterClass.getVar()); } }
abstract
et final
(l'un ou l'autre, mais pas les deux au même temps !).class MyOuterClass { // outer class /*[abstract|final]*/ class MyInnerClass { // inner class } }
MyOuterClass.this
pour référencer les attributs (et les méthodes) de la classe externe à partir de la classe interne.
Au cas contraire, les attributs et les méthodes de la classe interne seront utilisées par la JVM.this
référence toujours l'instance du code en cours d'exécution (peu importe que ce soit le code de la classe interne ou externe).class MyOuterClass { // outer class private Integer var = 0; private Integer step = 1; public Integer getVar() { return var; // ~ return this.var; } public class MyInnerClass { // inner class private Integer step = 2; public void setNextNumber() { var = var + step; // ~ MyOuterClass.this.var = MyOuterClass.this.var + this.step; // ~ MyOuterClass.this.var = MyOuterClass.this.var + MyInnerClass.this.step; } } } public class MyTest1 { public static void main(String[] args) { MyOuterClass myOuterClass = new MyOuterClass(); MyOuterClass.MyInnerClass myInnerClass = myOuterClass.new MyInnerClass(); myInnerClass.setNextNumber(); System.out.println(myOuterClass.getVar()); } }
class MyOuterClass { // outer class public static class MyNestedClass { // inner class static Integer var = 0; Integer step = 0; void doSomeThing() { } static void doSomeThingElse() { } } }
class MyOuterClass { // outer class public static class MyNestedClass { // inner class static Integer var = 0; Integer step = 1; void doSomeThing() { } static void doSomeThingElse() { } } } public class MyTest2 { public static void main(String[] args) { MyOuterClass.MyNestedClass.var = 1; MyOuterClass.MyNestedClass.doSomeThingElse(); } }
class MyOuterClass { // outer class public static class MyNestedClass { // inner class } } public class MyTest2 { public static void main(String[] args) { MyOuterClass.MyNestedClass myNestedClass = new MyOuterClass.MyNestedClass(); } }
class MyOuterClass { // outer class static Integer var = 0; Integer step = 1; static void initVar() { var = 1; } void initStep() { step = 1; } public static class MyNestedClass { // inner class void doSomeThing() { MyOuterClass.var = 1; // OK MyOuterClass.this.step = 1; // compiler error: No enclosing instance of the type MyOuterClass is accessible in scope MyOuterClass.initVar(); // OK MyOuterClass.initStep(); // compiler error: Cannot make a static reference to the non-static method initStep() from the type MyOuterClass } static void doSomeThingElse() { MyOuterClass.var = 1; // OK MyOuterClass.this.step = 1; // compiler error: No enclosing instance of the type MyOuterClass is accessible in scope MyOuterClass.initVar(); // OK MyOuterClass.initStep(); // compiler error: Cannot make a static reference to the non-static method initStep() from the type MyOuterClass } } }
public class MyTest3 { public static void main(String[] args) { class MyLocalInnerClass { // local inner class } MyLocalInnerClass myLocalInnerClass = new MyLocalInnerClass(); } }Notes :
public class MyTest3 { public static void main(String[] args) { class MyLocalInnerClass1 { // local inner class } class MyLocalInnerClass2 { // local inner class } } }Dans cet exemple le compilateur va créer les fichiers ".class" suivants :
abstract
ou final
(l'un ou l'autre, mais pas les deux au même temps !).
Le compilateur va afficher une erreur si la déclaration de la classe contient, par exemple, le mot clé public
:public class MyTest3 { public void doSomeThing() { public class MyLocalInnerClass { // compiler error: Illegal modifier for the local class MyLocalInnerClass; only abstract or final is permitted } } }
public class MyTest3 { public void doSomeThing() { MyLocalInnerClass myLocalInnerClass = new MyLocalInnerClass(); // compiler error: MyLocalInnerClass cannot be resolved to a type class MyLocalInnerClass { // local inner class } } }
public class MyTest3 { public void doSomeThing() { class MyLocalInnerClass { // local inner class private static Integer var = 0; // compiler error: The field var cannot be declared static; static fields can only be declared in static or top level types public static void foo() { // compiler error: The method foo cannot be declared static; static methods can only be declared in a static or top level type } } } }
public class MyTest3 { 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 Integer localVar2 = var2; // compiler error: Cannot make a static reference to the non-static field var2 foo1(); // OK bar1(); // compiler error: Cannot make a static reference to the non-static method bar1() from the type MyTest3 } } } }Par contre, les classes locales définies dans des méthodes non-statiques peuvent accéder aux membres statiques et non-statiques des classes externes.
public class MyTest3 { 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 Integer localVar2 = var2; // OK foo1(); // OK bar1(); // OK } } } }
final
.
Le compilateur va afficher une erreur si ce n'est pas le cas :public class MyTest3 { public void doSomeThing() { final Integer var1 = 2; Integer var2 = 2; class MyLocalInnerClass { // local inner class public void foo() { Integer localVar1 = var1; // OK Integer localVar2 = var2; // compiler error: Cannot refer to a non-final variable var2 inside an inner class defined in a different method } } } }
public class MyTest4 { Object object = new Object() { // anonymous inner class @Override public String toString() { return "anonymous inner class:toString"; } }; }Dans cet exemple, une nouvelle classe anonyme est créée à partir de la classe
Object
:Object
et peut ainsi redéfinir ses méthodes
et peut aussi définir de nouvelles méthodes mais ces nouvelles méthodes seront visibles uniquement dans le code de la classe anonyme.Object
et donc le compilateur va se plaindre si vous essayer d'appeler les nouvelles méthodes définies dans la classe anonyme :public class MyTest4 { public static void main(String[] args) { Object object = new Object() { // anonymous inner class @Override public String toString() { return toStringAnonymous(); // OK } public String toStringAnonymous() { return "anonymes inner classes"; } }; object.toString(); object.toStringAnonymous(); // compiler error: The method toStringAnonymous() is undefined for the type Object } }Il est possible de définir une classe anonyme comme argument d'une méthode :
public class MyTest4 { public static void main(String[] args) { foo( new Object() { // anonymous inner class @Override public String toString() { return "anonymes inner classes"; } } ); } public static void foo(Object object) { object.toString(); } }Notes :
public class MyTest4 { Object object1 = new Object() { // anonymous inner class }; Object object2 = new Object() { // anonymous inner class }; }Dans cet exemple le compilateur va créer les fichiers ".class" suivants :
abstract class MyAbstractClass { abstract void foo(); // the compiler will throw an error if not implemented abstract void bar(); // the compiler will throw an error if not implemented void doSomeThing() { // OK } } public class MyTest4 { MyAbstractClass myAbstractClass = new MyAbstractClass() { // compiler error: The type new MyAbstractClass(){} must implement the inherited abstract method MyAbstractClass.bar() @Override public void foo() { } }; }
interface MyInterface { void foo(); } public class MyTest4 { public static void main(String[] args) { MyInterface myInterface = new MyInterface() { // anonymous inner class @Override public void foo() { } }; myInterface.foo(); } }