内部类(嵌套类)

Posted joe-go

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内部类(嵌套类)相关的知识,希望对你有一定的参考价值。

嵌套类是指被定义在另一个类的内部的类。

嵌套类存在的目的是:只是为它的外部类提供服务;

outer.java里面定义了一个内部类inner,运行时,一旦编译成功,就会生成两个完全不同的.class文件,分别是outer.class和outer$inner.class。所以嵌套类的名字完全可以和它的外部类名字相同。

嵌套类分为四种:静态成员类,非静态成员类(成员内部类),匿名类,局部类。

内部类:非静态成员类(成员内部类),匿名类,局部类。

1.静态内部类

 1 public class Outer {
 2 
 3     public static String name = "Joe";
 4     private String password = "0806";
 5 
 6     //静态内部类
 7     public static class inner{
 8         public static void print1(){
 9             System.out.println(name);
10             //调用外部类的静态方法
11             outerPrint();
12         }
13         public void print2(){
14             System.out.println(name);
15         }
16     }
17 
18     public static void outerPrint(){
19         System.out.println("Outer static method!");
20     }
21 
22     public static void main(String[] args){
23        //静态内部类的静态方法调用
24         Outer.inner.print1();
25         //静态内部类的非静态方法调用
26         Outer.inner inner = new Outer.inner();
27         inner.print2();
28     }
29 }

输出结果:

Joe
Outer static method!
Joe

通过这个例子可以看出:

  ? 静态内部类中可以有静态方法,也可以有非静态方法;

  ? 静态内部类只能访问其外围类的静态成员和静态方法;

  ? 和普通的类一样,要访问静态内部类的静态方法,可以直接“.”出来,不需要一个实例;

  ? 要访问静态内部类的非静态方法,必须拿到一个静态内部类的实例对象;

  ? 实例化静态内部类:外围类.内部类  xxx = new 外围类.内部类();

可以把静态内部类看作普通的类,只是碰巧被声明在另一个类的内部而已;如果静态内部类被声明为私有的,那么它就只能在外围类的内部才可以访问。

非静态成员类(成员内部类)

成员内部类是最常见的内部类,就是在外部类的基础上按照一般定义类的方式定义类,举个例子:

 1 public class Outer {
 2 
 3     public static String name = "Joe";
 4     private String password = "0806";
 5 
 6     //私有成员内部类
 7     private class PrivateInner{
 8         public void print1(){
 9             System.out.println("private " + name);
10             System.out.println("public " + password);
11             //调用外部类的静态方法
12             outerPrint();
13         }
14     }
15     //公有的成员内部类
16     public class PublicInner{
17         public void print2(){
18             String password = "0810";
19             System.out.println("public " + name);
20             System.out.println("public " + password);
21             //调用外部类的静态方法
22             outerPrint();
23         }
24     }
25     public static void outerPrint(){
26         System.out.println("Outer static method!");
27     }
28 
29     public static void main(String[] args){
30         Outer outer = new Outer();
31         Outer.outerPrint();
32         //实例化私有成员内部类
33         Outer.PrivateInner privateInner = outer.new PrivateInner();
34         privateInner.print1();
35         //实例化公有成员内部类
36         Outer.PublicInner publicInner = outer.new PublicInner();
37         publicInner.print2();
38     }
39 }

输出结果:

Outer static method!
private Joe
public 0806
Outer static method!
public Joe
public 0810
Outer static method!

通过这个例子可以看出:

  ? 成员内部类是依附其外围类而存在的,如果要产生一个成员内部类,必须有一个其外围类的实例;

  ? 成员内部类不可以定义静态方法和静态属性;

  ? 声明为private的成员内部类,只对其外围类可见;声明为public的成员内部类,其他非外围类对其可见;

  ? 成员内部类可以访问外围类的私有属性,如果成员内部类的属性和其外围类的属性重名,则以成员内部类的属性值为准;

  ? 实例化成员内部类:外围类.内部类 xxx = 外围类.new 内部类();

匿名内部类

在多线程的模块中代码,大量使用了匿名内部类,如下:

 1 public class Outer {
 2     //匿名接口
 3     interface Inner{
 4         int getNumber();
 5     }
 6     //使用匿名接口
 7     public Inner getInner(final int num,String str){
 8         return new Inner() {
 9             @Override
10             public int getNumber() {
11                 System.out.println(str);
12                 return num;
13             }
14         }; /* 注意:分号不能省 */
15     }
16     //测试
17     public static void main(String[] args){
18         Outer outer = new Outer();
19         Inner inner = outer.getInner(4,"nihao");
20         System.out.println(inner.getNumber());
21     }
22 }

输出结果:

nihao
4

 通过这个例子可以看出:

  ? 匿名内部类没有修饰符;

  ? 当所在方法的形参需要被匿名内部类使用时,该形参必须为final,因为:内部类在编译时会生成一个独立的.class文件,改文件并不在它的外围类中,内部类将传过来的参数通过自己的构造器备份到了自己的内部,这样自己内部方法的调用实际上是自己的属性,而不是外围类方法的参数;简单理解就是:拷贝引用,为了避免引用值发生改变,例如被外围类的方法修改等,而导致内部类得到的值不一致,于是用final修饰让该引用不可变;

  ? 匿名内部类没有构造方法,因为它连名字都没有;

  ? new 匿名内部类;这个类必须先存在;

局部内部类

局部内部类:是指内部类定义在方法和作用域内。

看个例子:

 1 public class Outer {
 2     private void internalTracking(boolean b) {
 3         if (b) {
 4             //局部内部类
 5             class TrackingSlip {
 6                 private String id;
 7                 TrackingSlip(String s) {
 8                     id = s;
 9                 }
10                 String getSlip() {
11                     return id;
12                 }
13             }
14             TrackingSlip ts = new TrackingSlip("slip");
15             String s = ts.getSlip();
16         }
17     }
18 
19     public void track() {
20         //调用方法(含有局部内部类)
21         internalTracking(true);
22         System.out.println(".......");
23     }
24 
25     public static void main(String[] args) {
26         Outer p = new Outer();
27         p.track();
28     }
29 }

局部内部类也会像其他类一样编译,只是作用域不同而已,只有在该方法或者作用域内才能用,超出作用域或者方法就不可引用。

  ? 局部内部类没有访问修饰符;

  ? 局部内部类要访问外围类的对象或者变量,那么这个变量或者对象必须是final修饰的;

内部类的好处

  ? Java运行实现多个接口,但不允许继承多个类,使用内部类可以解决Java不允许多个继承的问题。在一个类的内部定义一个内部类,让这个内部类继承某个原有的类,而这个内部类又可以访问外围类的属性和方法,这样就相当于多个继承了;

  ? 有效的对外隐藏了自己,增加了自己的私密性;

  ? 使用内部类可以让类与类之间的联系更加紧密;

  ? 有些类知道只会在某个地方使用只使用一次,为这种类创建一个外部类显然没有必要,所以这种就写个内部类用用就可以了;









以上是关于内部类(嵌套类)的主要内容,如果未能解决你的问题,请参考以下文章

这个嵌套类构造函数片段可以应用于泛型类吗?

内部嵌套类的 Kotlin 工厂

Kotlin基础(十三) 嵌套类内部类和匿名内部类

PHP中的嵌套或内部类

Kotlin基础(十三) 嵌套类内部类和匿名内部类

java嵌套类和内部类详解