一、基本介绍
一个类的内部完整的嵌套了另一个类结构,被嵌套的类称为内部类。内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。下面就先来了解一下这四种内部类的用法。
二、内部类分类
定义在外部类局部位置上(例如方法或者代码块):
- 局部内部类(有类名)
- 匿名内部类(无类名)
定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
三、内部类演示与细节
局部内部类的使用
- 局部内部类定义在外部类的局部位置上,例如方法或者代码块,并且有类名
- 局部内部类可以直接访问外部类的所有成员,包括私有的
package Innerclass; public class Innerclass01 { //外部其他类 public static void main(String[] args) { Outer outer = new Outer(); outer.z(); } } class Outer{ //外部类 private int x = 10; //私有属性 private void y(){ //私有方法 System.out.println("哈哈..."); } public void z(){ class Inner{ //局部内部类,写在方法z里面 public void print(){ y(); //在他的方法里面可以调用外部的私有属性和方法 System.out.println(x); } } Inner inner = new Inner(); inner.print(); } }
- 局部内部类不能添加访问修饰符,但是可以使用 final 修饰,他的地位与局部变量类似,局部变量不能使用修饰符
- 局部内部类作用域仅仅在定义它的方法或代码块中
- 外部类访问局部内部类的成员方式为:创建对象,在访问(必须在作用域内)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员(使用 外部类名.this.成员)去访问
class Outer{ //外部类 private int x = 10; public void z(){ private int x=100; public void print(){ System.out.println(x); System.out.println(Outer.this.x); //此时这个打印出才是Outer的属性 10 } } }
小结:
- 局部内部类定义在方法中或代码块
- 作用域在方法体或者代码块中
- 本质还是一个类
匿名内部类的使用
- 在实际开发中,我们常常遇到这样的情况:一个接口/类的方法的某个实现方式在程序中只会执行一次,但为了使用它,我们需要创建它的实现类/子类去实现/重写。此时可以使用匿名内部类的方式,可以无需创建新的类,减少代码冗余。
- 匿名内部类定义在外部类的局部位置上,并且没有类名,基本语法为:new 类或者接口(惨数列表){ 类体 };
new Bell(){ 类体 }
- 匿名内部类不能添加访问修饰符,因为它的地位就是一个局部变量(与上面类似)
- 匿名内部类作用域 : 仅仅在定义它的方法或代码块(与上面类似)
- 匿名内部类可以直接访问外部类的所有成员,包含私有的(与上面类似)
- 匿名内部类如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问(与上面类似)
匿名内部类的实现:
package Innerclass; public class InnerClassExercise { public static void main(String[] args) { //在main函数中编写两个匿名内部类,将他作为一个接口对象传递给alarmclock方法 Cellphone.alarmclock(new Bell(){ @Override public void ring() { System.out.println("上课了...."); //由于涉及到动态绑定机制,会在这里执行 } }); Cellphone.alarmclock(new Bell(){ @Override public void ring() { System.out.println("下课了...."); //同理 } }); } } //编写一个类,在里面创建一个带接口参数的方法 class Cellphone{ public static void alarmclock(Bell bell){ System.out.println(bell.getClass()); //打印bell的运行类型 bell.ring(); //调用方法 } } public interface Bell { //编写一个beLL方法 public void ring(); }
由输出结果可知,bell的编译类型为Bell,但是运行类型是他的外部类+$+序号
成员内部类的使用
- 成员内部类是定义在外部类的成员位置,并且没有static修饰
- 可以添加任何访问修饰符(public,protected,默认,private),他本质是一个成员
- 成员内部类作用域为整个类体
- 成员内部类访问外部类成员,直接访问
- 外部类访问成员内部类,先创建对象,再访问
- 外部其他类访问成员内部类的方法
第一种:
第二种:
在其他类中调用
- 如果外部类与内部类成员时,内部类访问的话,默认是遵循就近原则,如果访问外部成员时,则使用(外部类名.this.成员) 去访问
静态内部类的使用
- 静态内部类是定义在外部类的成员位置,并且有static修饰
- 可以添加任何访问修饰符(public,protected,默认,private),他本质是一个成员
- 静态内部类作用域为整个类体
- 静态内部类访问外部类所有静态成员,直接访问,但无法访问非静态成员
- 外部类访问静态内部类,先创建对象,再访问 (与成员内部类相似)
- 外部其他类访问静态内部类的方法 (与成员内部类相似)
- 如果外部类与静态内部类重名时,内部类访问的话,默认是遵循就近原则,如果访问外部成员时,则使用(外部类名.成员) 去访问