首页 > 编程笔记 > Java笔记 阅读:20

Java内部类的4种用法(成员内部类、局部内部类、静态内部类和匿名内部类)

大多数情况下,Java 中的类被定义为一个独立的程序单元。但在某些情况下,也可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类(也称嵌套类),包含内部类的类也被称为外部类。

内部类包括 4 种,分别是成员内部类、局部内部类、静态内部类和匿名内部类。一般情况下,内部类有如下几个属性:

Java成员内部类

成员内部类是最普通的内部类,它定义于另一个类的内部,与外部类的成员变量、成员方法同级。

成员内部类可以访问外部类的所有成员,外部类同样可以访问其成员内部类的所有成员。但是,成员内部类是依附外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

在外部类外创建一个内部类对象的语法格式如下:
外部类名.内部类名 引用变量名 = new 外部类名().new 内部类名()
接下来,通过案例来演示成员内部类的使用:
class Outer { // 定义外部类
    private String name = "外部类Outer";
    private int num = 666;

    class Inner { // 定义内部类
        private String name = "内部类Inner";
        public void accessOuter() {
            System.out.println("在成员内部类中访问内部类的name:" + name);
            // Outer.this表示外部类对象
            System.out.println("在成员内部类中访问外部类的name:" + Outer.this.name);
            System.out.println("在成员内部类中访问外部类的num:" + this.num);
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().new Inner();
        inner.accessOuter();
    }
}
程序的运行结果如下:

在成员内部类中访问内部类的name:内部类Inner
在成员内部类中访问外部类的name:外部类Outer
在成员内部类中访问外部类的num:666

程序中,外部类 Outer 中定义了一个成员内部类 Inner,在 Inner 类的成员方法 accessOuter() 中访问其自身的成员变量 name 以及其外部类 Outer 的成员变量 name 和 num,由于内部类和外部类的成员变量 name 重名,所以不能直接访问,只能用“Other.this.name”的形式进行访问,其中“Outer.this”表示外部类对象,而 num 只存在于外部类,内部类可以直接访问。

注意,成员内部类中不能定义静态变量、静态方法和静态内部类。

Java局部内部类

局部内部类是指在成员方法中定义的类,这种类是局部的,和局部变量类似,只能在该方法或条件的作用域内使用,超出这些作用域就无法引用。

局部内部类的优势是,对于外部类完全隐藏,即使是包含它的外部类也是不可见的,是不能直接访问的,只有在方法中才可以创建内部类的实例并访问其中的方法和属性。

局部内部类的特点如下:
接下来,通过案例来演示局部内部类的使用:
class Outer { // 定义外部类
    private static String name = "外部类Outer";
    private int num = 666;
    public void display() {
        int count = 5;
        // 局部内部类嵌套在方法里面
        class Inner {
            public void accessOuter() {
                System.out.println("在局部内部类中访问外部方法的变量:" + (count));
                System.out.println("在局部内部类中访问外部类的name:" + Outer.name);
                System.out.println("在局部内部类中访问外部类的num:" + num);
            }
        }
        // 局部内部类在方法内部调用
        new Inner().accessOuter();
    }
}

public class Demo {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.display();
    }
}
程序的运行结果如下:
在局部内部类中访问外部方法的变量:5
在局部内部类中访问外部类的name:外部类Outer
在局部内部类中访问外部类的num:666
程序中,外部类 Outer 的 display() 方法定义了一个内部类 Inner,Inner 类只能在 display() 方法中创建其实例对象并调用自身方法 accessOuter(),该方法调用了外部类 Outer 的成员变量 name 和 num 以及 display() 方法内的局部变量 count。

从运行结果中发现,都可以正常输出,但是如果把第 9 行代码中的“count”后面加上“++”之后,会编译报错,因为局部变量是随着方法的调用而调用,随着调用结束而消失,但是我们调用局部内部类时创建的对象依旧在堆内存中,并没有被回收,如果访问的局部变量不是用 final 修饰的,当方法调用完毕后,依然存在于堆内存中的对象就会出现找不到局部变量的问题,而被 final 修饰的变量可以看成是一个常量,存在于常量池中,不会被立刻回收。所以,针对局部内部类来说,它可以访问方法中的局部变量,但不能进行修改。

注意,JDK 8 之后,即使不加 final 修饰符,系统也会默认加上。

Java静态内部类

静态内部类是指用 static 关键字修饰的成员内部类。

静态内部类可以包含静态成员和非静态成员(实例成员),根据静态成员不能访问非静态成员的规则,静态内部类不能直接访问外部类的非静态成员,只能访问外部类的静态成员(即类成员)。

创建静态内部类对象的语法格式如下:
外部类名.内部类名 引用变量名 = new 外部类名.内部类名()
接下来,通过案例来演示静态内部类的使用:
class Outer {
    private static String name = "外部类Outer"; // 定义类静态成员
    private static int num = 666;
   
    static class Inner { // 定义静态内部类
        public static String name = "内部类Inner"; // 定义类静态成员
       
        public void accessOuter() {
            // 静态内部类成员方法中访问外部类私有成员变量
            System.out.println("在静态内部类中访问外部类的name: " + Outer.name);
            System.out.println("在静态内部类中访问外部类的num:" + num);
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        System.out.println("静态内部类:" + Outer.Inner.name);
        Outer.Inner obj = new Outer.Inner(); // 创建静态内部类对象
        obj.accessOuter();
    }
}
程序的运行结果如下:

静态内部类:内部类Inner
在静态内部类中访问外部类的name:外部类Outer
在静态内部类中访问外部类的num:666

程序中外部类 Outer 中定义了一个静态内部类 Inner,Inner 类包含了静态成员变量 name 和成员方法 accessOuter():
如果将第 5 行代码的 static 去掉,则在第 11 行代码调用时会报错,因为 num 属于外部类的非静态变量,不可以被其静态内部类直接访问。

注意,静态内部类不需要依赖外部类就可以直接创建;静态内部类不可以使用任何外部类的非 static 成员(包括变量和方法)。

Java匿名内部类

匿名内部类是一个没有显式名字的内部类。本质上看,它会隐式地继承一个类或者实现一个接口。换句话说,匿名内部类是一个继承了某个类或者实现了某接口的子类匿名对象。

创建匿名内部类的语法格式如下:
new 类名/接口名/抽象类名() {
    …             // 匿名内部类实现部分
}
匿名内部类具有局部内部类的所有特点,同时它还具有如下特点:
匿名内部类是我们平时编写代码时用得比较多的内部类,在编写事件监听的代码时使用匿名内部类不但可简化程序,而且可使代码更加容易维护。

接下来,通过案例来演示匿名内部类的使用:
interface Inner { // 定义接口
    void getName(String name); // 定义接口方法
}

public class Demo {
    public static void main(String[] args) {
        new Inner() {
            // 定义匿名类,并实现Inner接口
            public void getName(String name) { // 重写getName()方法
                System.out.println("我是匿名类的方法,获取name为:" + name);
            }
        }.getName("张三"); // 调用方法
    }
}
程序的运行结果如下:

我是匿名类的方法,获取name为:张三

在外部类 Demo 的 main() 方法中创建了匿名内部类 Inner 的对象,并调用该类的成员方法 getName(),传入参数“张三”,在创建 Inner 对象时,并没有给对象赋予名称,即“匿名”之意。

相关文章