• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
火磷
Memory will fade,but not notes.
博客园    首页    新随笔    联系   管理    订阅  订阅
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         //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

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

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

!!!

posted on 2019-09-29 18:46  火磷  阅读(227)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3