1. 简介html
在 Java 中能够将一个类定义在另外一个类里面或者一个方法里面,这样的类称为内部类。普遍意义上的内部类通常来讲包括这四种:java
成员内部类、局部内部类、匿名内部类和静态内部类。ide
2. 优势this
在程序设计中有时会存在一些使用接口很难解决的问题,此时能够利用内部类提供的、能够继承多个具体的或者抽象的类的能力来解决。spa
能够这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。.net
使用内部类可使程序拥有如下特性:设计
1)内部类能够用多个实例,每一个实例都有本身的状态信息,而且与其余外围对象的信息相互独立;code
2)在单个外部类中,可让多个内部类以不一样的方式实现同一个接口,或者继承同一个类;htm
3)建立内部类对象的时刻并不依赖于外部类对象的建立;对象
4)内部类并无使人迷惑的“is-a”关系,它就是一个独立的实体;
5)内部类提供了更好的封装,除了该外部类,其余类都不能访问;
3. 示例
3.1 成员内部类
3.1.1 成员内部类的修饰符和实例化
成员内部类能够看做是外部类的一个成员,它有如下注意点:
1)成员内部类不能使用static关键字;
2)成员内部类的实例化:成员内部类依赖于外部类,所以必须在外部类实例化后内部类才能实例化。
注:上述条件说明在外部类的非静态方法中能够实例化内部类(要访问外部类的实例方法,先要有外部类对象,知足上述条件);
或者在外部类的静态方法中先实例化外部类,再实例化内部类。
1 public class OuterClass1 { 2 3 class InnerClass{ 4 //private static int innerVar = 1; // 成员内部类不能使用静态成员变量 5 //private static void innerMethod(){ } // 成员内部类不能使用静态方法 6 } 7 8 public void outMethod(){ 9 InnerClass in = new InnerClass(); // 在外部类的非静态方法中直接实例化内部类 10 } 11 12 public static void main(String[] args){ 13 //InnerClass in = new InnerClass(); // 在外部类的静态方法中不能直接实例化内部类 14 15 // 先建立外部类对象后才能建立内部类对象 16 OuterClass1 out = new OuterClass1(); 17 OuterClass1.InnerClass in = out.new InnerClass(); 18 // 外部类的非静态方法之因此能够建立内部类对象,是因为要访问外部类的非静态方法,必须经过外部类的对象访问, 19 // 此时已经建立了外部类对象,知足了先外部对象,再内部对象的条件 20 out.outMethod(); 21 } 22 }
3.1.2 成员内部类访问外部类
成员内部类在访问外部类时,它有如下注意事项:
1)成员内部类访问外部类的非同名成员变量和方法:直接调用便可;
2)成员内部类访问外部类的同名成员变量和方法:外部类.this.成员变量 / 外部类.this.成员方法;
注:不管外部类的成员变量和方法是否使用private修饰,皆可访问。
1 public class OuterClass2 { 2 private String outVar1 = "outVar1"; 3 private static String outVar2 = "outVar2"; 4 private String outVar3 = "outVar3"; 5 6 private void outerMethod(){ 7 System.out.println("outerMethod with same name of OuterClass"); 8 } 9 10 private void outerMethod1(){ 11 System.out.println("outerMethod of OuterClass"); 12 } 13 14 private static void outerMethod2(){ 15 System.out.println("static outerMethod of OuterClass"); 16 } 17 18 class InnerClass{ 19 private String outVar3 = "innerVar3"; 20 21 private void outerMethod(){ 22 System.out.println("outerMethod with same name of InnerClass"); 23 System.out.println(outVar1); // 访问外部类成员变量 24 System.out.println(outVar2); // 访问外部类静态成员变量 25 System.out.println(OuterClass2.this.outVar3); // 访问外部类同名成员变量 26 } 27 28 public void innerMethod(){ 29 outerMethod(); // 访问自身的同名方法 30 OuterClass2.this.outerMethod(); // 访问外部类的同名方法 31 outerMethod1(); // 访问外部类的实例方法 32 outerMethod2(); // 访问外部类的静态方法 33 } 34 } 35 36 public static void main(String[] args){ 37 OuterClass2 out = new OuterClass2(); 38 OuterClass2.InnerClass in = out.new InnerClass(); 39 in.innerMethod(); 40 } 41 }
运行结果以下:
1 outerMethod with same name of InnerClass 2 outVar1 3 outVar2 4 outVar3 5 outerMethod with same name of OuterClass 6 outerMethod of OuterClass 7 static outerMethod of OuterClass
3.1.3 外部类访问成员内部类
外部类在访问成员内部类时,它有如下注意事项:
1)外部类访问成员内部类时必须经过内部类的对象访问;
1 public class OuterClass3 { 2 3 class InnerClass{ 4 private String innerVar1 = "innerVar1"; 5 6 private void outerMethod1(){ 7 System.out.println("outerMethod with same name of InnerClass"); 8 } 9 } 10 11 private void outerMethod1(){ 12 System.out.println("outerMethod with same name of OuterClass"); 13 InnerClass in = new InnerClass(); // 经过内部类对象访问内部类的成员变量和方法 14 System.out.println(in.innerVar1); 15 in.outerMethod1(); 16 } 17 18 private static void outerMethod2(){ 19 System.out.println("static method with same name of OuterClass"); 20 // InnerClass in = new InnerClass(); // error 21 OuterClass3 out = new OuterClass3(); // 经过内部类对象访问内部类的成员变量和方法 22 OuterClass3.InnerClass in = out.new InnerClass(); 23 in.outerMethod1(); 24 } 25 26 public static void main(String[] args){ 27 OuterClass3 out = new OuterClass3(); 28 out.outerMethod1(); 29 outerMethod2(); 30 } 31 }
运行结果以下:
1 outerMethod with same name of OuterClass 2 innerVar1 3 outerMethod with same name of InnerClass 4 static method with same name of OuterClass 5 outerMethod with same name of InnerClass
3.2 静态内部类
3.2.1 静态内部类的说明和使用
静态内部类指使用static关键字修饰的内部类。非静态内部类在编译完成以后会隐含地保存着一个引用,该引用是指向建立它的外部类,
静态内部类却没有该引用,这是由于静态内部类是类级别的属性,不须要对象的引用(this)来调用。
它的特色以下:
0)加载外部类时不会直接加载静态内部类,当且仅当静态内部类的静态成员(静态域、构造器、静态方法等)被调用时才会加载;
1)静态内部类的对象建立不依赖于外部类;
2)静态内部类不能使用外部类的任何非静态成员变量和方法,只能访问静态成员变量和方法;
3)外部类能够经过类名.xx直接访问静态内部类的静态方法;
1 public class OuterClass4 { 2 private String outVar1 = "outVar1"; 3 private static String outVar2 = "outVar2"; 4 private static String outVar3 = "outVar3"; 5 6 public void outMethod1(){ 7 InnerClass in = new InnerClass(); 8 System.out.println(in.outVar3); 9 } 10 11 private static void outMethod2(){ 12 } 13 14 private static void outMethod3(){ 15 System.out.println(InnerClass.outVar4); // 能够直接访问静态内部类的静态变量和方法 16 InnerClass in = new InnerClass(); 17 in.innerMethod(); 18 System.out.println(in.outVar3); // 能够经过内部类对象访问实例变量和方法 19 } 20 21 static class InnerClass { 22 private String outVar3 = "innerVar3"; 23 private static String outVar4 = "innerVar4"; 24 25 public InnerClass(){ 26 // System.out.println(outVar1); // 不能访问外部类的非静态变量 27 System.out.println(outVar2); // 能够访问外部类的静态变量 28 System.out.println(OuterClass4.outVar3); // 能够访问外部类的同名静态变量 29 30 //outMethod1(); // 不能访问外部类的非静态方法 31 outMethod2(); // 能够访问外部类的静态方法 32 } 33 34 public void innerMethod(){ 35 } 36 } 37 38 public static void main(String[] args){ 39 InnerClass in = new InnerClass(); // 能够直接建立内部类对象 40 System.out.println(in.outVar3); 41 42 OuterClass4 out = new OuterClass4(); 43 out.outMethod1(); 44 outMethod3(); 45 } 46 }
运行结果以下:
1 outVar2 2 outVar3 3 innerVar3 4 outVar2 5 outVar3 6 innerVar3 7 innerVar4 8 outVar2 9 outVar3 10 innerVar3
3.3 局部内部类
3.3.1局部内部类的说明和使用
局部内部类是定义在一个方法或者做用域中的类,它的使用仅限于其方法或者做用域内,出了方法和做用域就会失效,相似于局部变量。其特色以下:
1)局部内部类是定义在一个方法或者做用域中的类,它的访问权限仅限于其方法或者做用域内;
2)局部内部类相似方法和做用域中的局部变量,不能使用权限访问修饰符和static关键字修饰;
1 class Animal{ } 2 3 public class OuterClass5 { 4 5 // 在方法中使用局部内部类 6 private Animal getDog(){ 7 class Dog extends Animal{ 8 } 9 return new Dog(); 10 } 11 12 // 在做用域中使用局部内部类 13 private Animal getCat(boolean flag){ 14 if(flag){ 15 class Cat extends Animal{ 16 } 17 return new Cat(); 18 } 19 return null; 20 } 21 22 public static void main(String[] args){ 23 OuterClass5 out = new OuterClass5(); 24 Animal a1 = out.getDog(); 25 Animal a2 = out.getCat(true); 26 System.out.println(a1); 27 System.out.println(a2); 28 } 29 }
运行结果以下:
1 InnerClass.OuterClass5$1Dog@6d6f6e28 2 InnerClass.OuterClass5$1Cat@135fbaa4
3.4 匿名内部类
3.4.1 匿名内部类的说明
匿名内部类便是没有名称的内部类,它的使用前提和特色以下:
1)使用匿名内部类须要继承父类或者实现一个接口;
2)匿名内部类不能使用访问修饰符修饰;
3)匿名内部类不能是抽象类,由于在使用它时会直接建立该类的对象;
4)匿名内部类不能定义构造器,由于该类没有类名;
3.4.2 未在抽象类和接口上使用匿名内部类
对于一个抽象类和接口,一般须要使用一个类继承或实现它们,而后再实现其内部的方法,最后使用它。例如:
1 abstract class Parent{ 2 abstract int getNumber(int n); 3 } 4 5 class Child extends Parent{ 6 @Override 7 int getNumber(int n) { 8 return n; 9 } 10 } 11 12 public class Demo { 13 public static void main(String[] args){ 14 Parent p = new Child(); 15 System.out.println(p.getNumber(2)); 16 } 17 }
3.4.3 在抽象类上使用匿名内部类
对于上述抽象类Parent,咱们显示地定义了一个Child类继承它,而且重写了其方法,有什么方法能够不写这个Child类呢?
这里引入匿名内部类便可,例如如下示例:
1 abstract class Parent { 2 abstract int getNumber(int n); 3 } 4 5 public class Demo1 { 6 public static void main(String[] args){ 7 Parent p = new Parent() { // 注意,这里使用了匿名内部类 8 @Override 9 public int getNumber(int n) { 10 return n; 11 } 12 }; 13 System.out.println(p.getNumber(2)); 14 } 15 }
3.4.4 在接口上使用匿名内部类
1 interface Parent { 2 int getNumber(int n); 3 } 4 5 public class Demo2 { 6 public static void main(String[] args){ 7 // 直接使用 8 Parent p1 = new Parent() { // 没有出现类名 9 @Override 10 public int getNumber(int n) { 11 return n; 12 } 13 }; 14 System.out.println(p1.getNumber(2)); 15 16 // 使用Lambda表达式 17 Parent1 p2 = n -> n; 18 System.out.println(p2.getNumber(2)); 19 } 20 }
4. 参考文献
https://www.runoob.com/w3cnote/java-inner-class-intro.html
https://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html
http://www.javashuo.com/article/p-zhxupjja-y.html
http://www.javashuo.com/article/p-qxqvuwlq-eb.html
!!!