Java内部类详解

内部类的定义:
将一个类定义在另一个给类里面或者方法里面,这样的类就被称为内部类。
内部类可以分为四种:成员内部类、局部内部类、匿名内部类、静态内部类,下面我们逐一介绍这四种内部类。

成员内部类

他定义在另一个类中。一般定义格式如下

class C{
 class D{
 }
}

因为类C相对与类D在外面,我们且称类C为外部类。
成员内部类可以无条件访问外部类的属性和方法,但是外部类想要访问内部类属性或方法时,必须要创建一个内部类对象,然后通过该对象访问内部类的属性或方法

成员内部类无条件访问外部类的属性和方法

class C{
 private String name = “外部类”;
 public void run(){
 System.out.println(“外部类奔跑”);
 }
 class D{
 public void say(){
 System.out.println(name);
 run();
 }
 }
 }

外部类访问内部类属性和方法

class C{
 private String name = “外部类”;
 public void run(){
 System.out.println(“外部类奔跑”);
 }
 /使用内部类的属性和方法/
 public void eat(){
 D d = new D();
 System.out.println(d.value);
 d.say();
 }
 class D{
 private String value = “DDD”;
 public void say(){
 System.out.println(name);
 run();
 }
 }
 }

外部类属性或方法隐藏

如果成员内部类的属性或者方法与外部类的同名,将导致外部类的这些属性与方法在内部类被隐藏,也可按照该格式调用,外部类.this.属性/方法。

class C{
 private String name = “外部类”;
 public void run(){
 System.out.println(“外部类奔跑”);
 }
 /使用内部类的属性和方法/
 public void eat(){
 D d = new D();
 System.out.println(d.value);
 d.say();
 }
 class D{
 private String value = “DDD”;
 private String name = “内部类”;
 public void say(){
 System.out.println(C.this.name);
 System.out.println(name);
 run();
 }
 }
 }

创建内部类对象

显然成员内部类是寄生于外部类,创建内部类对象就必须先创造外部类对象。之后创建内部类有两种方式。

public class Test10 {
 public static void main(String[] args) {
 /方式1创建成员内部类对象/
 C c = new C();
 C.D d = c.new D();
 /方式2创建成员内部类对象/
 C.D d1 = c.getClassD();
 }
 }
 class C{
 private String name = “外部类”;
 public void run(){
 System.out.println(“外部类奔跑”);
 }
 /创建一个返回D对象的方法/
 public D getClassD(){
 return new D();
 }
 /使用内部类的属性和方法/
 public void eat(){
 D d = new D();
 System.out.println(d.value);
 d.say();
 }
 class D{
 private String value = “DDD”;
 private String name = “内部类”;
 public void say(){
 System.out.println(C.this.name);
 System.out.println(name);
 run();
 }
 }
 }

成员内部类的访问权限

成员内部类前可加上四种访问修饰符。
private:仅外部类可访问。
protected:同包下或继承类可访问。
default:同包下可访问。
public:所有类可访问。

局部内部类

局部内部类存在于方法中。
他和成员内部类的区别在于局部内部类的访问权限仅限于方法或作用域内。

class K{
 public void say(){
 class J{
 public void fn(){};
 }
 J j=new J();
 j.fn();
 }
 }

注意事项:局部内部类就像局部变量一样,前面不能访问修饰符以及static修饰符。因为函数内部不能再定义函数,所以可以通过局部内部类的方法,在函数内部定义函数,并且调用。

匿名内部类

下面我们先通过一段代码初步了解一下匿名内部类。

public class Test13 {
 public static void main(String[] args) {
 driveCar(new Car(){
 @Override
 public void drive() {
 System.out.println(“驾驶着BMW汽车”);
 }
 });
 }
 public static void driveCar(Car car){
 car.drive();
 }
 }interface Car {
 public abstract void drive();
 public static final int a=3;
 }

分析以上代码知道静态方法driveCar需要一个Car对象,我们通过实现接口创建一个匿名类对象传递过去。事实上还可以通过继承类来创建一个匿名内部类对象。所以匿名内部类实际上是生成了一个子类的对象。
注意事项:匿名内部类没有构造方法。(因为匿名内部类大多用于抽象类,接口的实现中,而抽象类和接口是不能进行实例化的。)也是唯一没有构造方法的内部类。匿名内部类和局部内部类只能访问外部类的final变量。

静态内部类

静态内部类和成员内部类相比多了一个static修饰符。它与类的静态成员变量一般,是不依赖于外部类的。同时静态内部类也有它的特殊性。因为外部类加载时只会加载静态域,所以静态内部类不能使用外部类的非静态变量与方法。但是可以自己在类里面定义实例方法或者静态方法或者静态属性。
同时可以知道成员内部类里面是不能定义静态属性或方法的。(成员内部类并不随外部类一起加载,只有在实例化外部类之后才会加载。但是静态属性和方法必须在类加载时就加载,前后产生了矛盾。

小点:

成员方法中定义的变量都是局部变量,只能在方法体内访问。而静态变量则是全局变量,(这里暂不考虑private修饰的静态变量)。
不光不能在静态方法中定义静态变量,在非静态方法中更不能。注意区分定义和调用,不能定义是因为方法内变量都是局部的,但是可以调用,成员方法可以调用静态变量,但是静态方法中不能直接调用成员变量!! 因为成员变量必须依附于对象,只能通过创建对象来调用。)

class U {
 static class I {}
}

内部类的好处
完善了Java多继承机制,由于每一个内部类都可以独立的继承接口或类,所以无论外部类是否继承或实现了某个类或接口,对于内部类没有影响。
方便写事件驱动程序。
总结

public class Test15 {
 public static void main(String[] args) {
 //初始化bean1
 Test15.Bean1 bean1 = new Test15().new Bean1();
 bean1.i++;
 //初始化bean2
 Test15.Bean2 bean2 = new Test15.Bean2();
 bean2.j++;
 //初始化3
 Bean bean = new Bean();
 Bean.Bean3 bean3 = bean.new Bean3();
 bean3.k++;
 }
 class Bean1 {
 public int i = 0;
 }
 static class Bean2 {
 public int j = 0;
 }
 }
 class Bean {
 class Bean3 {
 public int k = 0;
 }}

静态内部类对象的创建一般是外部类.内部类 类名 = new 外部类.内部类();

Outer.Inner in=new Outer.Inner();
Outer.Inner.InnerFn();//调用内部类的静态方法
in.InnerFn1();//调用静态内部类的成员方法
成员内部类对象的创建一般是外部类.内部类 类名 = 外部类对象名.new 内部类();
Outer.this.Fn()//同名了
Outer o=new Outer();
Outer.Inner in=o.new Inner();

综上只有 : 局部内部类没有权限修饰符,只有匿名内部类没有构造方法。