Java 内部类

1. 简介

在 Java 中可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:

成员内部类、局部内部类、匿名内部类和静态内部类。

 

2. 优点

在程序设计中有时会存在一些使用接口很难解决的问题,此时可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决。

可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

使用内部类可以时程序拥有以下特性:

1)内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立;

2)在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类;

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 
 6 //        private static void innerMethod(){ }     // 成员内部类不能使用静态方法
 7     }
 8 
 9     public void outMethod(){
10         InnerClass in = new InnerClass();      // 在外部类的非静态方法中直接实例化内部类
11     }
12 
13     public static void main(String[] args){
14         //InnerClass in = new InnerClass();       // 在外部类的静态方法中不能直接实例化内部类
15 
16         // 先创建外部类对象后才能创建内部类对象
17         OuterClass1 out = new OuterClass1();
18         OuterClass1.InnerClass in = out.new InnerClass();
19     }
20 }

3.1.2 成员内部类访问外部类

 成员内部类在访问外部类时,它有以下注意事项:

1)成员内部类访问外部类的非同名成员变量和方法:直接调用即可;

2)成员内部类访问外部类的同名成员变量和方法:外部类.this.成员变量 / 外部类.this.成员方法;

 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关键字修饰的内部类。非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外部类,

但是静态内部类却没有该引用。它的特点如下:

1)静态内部类的创建不依赖于外部类;

2)静态内部类不能使用外部类的任何非静态成员变量和方法;

 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     }
 8 
 9     private static void outMethod2(){
10     }
11 
12     static class InnerClass {
13         private String outVar3 = "innerVar3";
14 
15         public InnerClass(){
16 //            System.out.println(outVar1);              // 不能访问外部类的非静态变量
17             System.out.println(outVar2);                // 可以访问外部类的静态变量
18             System.out.println(OuterClass4.outVar3);   //  可以访问外部类的同名静态变量
19 
20             //outMethod1();            // 不能访问外部类的非静态方法
21             outMethod2();              // 可以访问外部类的
22         }
23     }
24 
25     public static void main(String[] args){
26         InnerClass in = new InnerClass();       // 可以直接创建内部类对象
27         System.out.println(in.outVar3);
28     }
29 }

运行结果如下:

1 outVar2
2 outVar3
3 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

https://blog.csdn.net/guyuealian/article/details/51981163

https://www.cnblogs.com/chenssy/p/3388487.html

!!!

上一篇:Java中的内部类


下一篇:【转】java提高篇(七)-----详解内部类