Skip to content

内部类(重点)


底层源码涉及大量的内部类,务必掌握

基本介绍

(1)一个类的内部又完整的嵌套了另一个类结构

1. 被嵌套的类称为内部类(inner class)

2. 嵌套其他类的类称为外部类(outer class)

(2)内部类最大的特点就是可以直接访问私有属性,并且可以体现==类与类之间的包含关系

具体类别

1. 定义在外部类的局部位置

(1)局部内部类

(2)匿名内部类(重点)

2. 定义在外部类的成员位置

(1)成员内部类

(2)静态内部类

类的完整结构

结构层面

外部类

    内部类

外部其他类

一个类拥有的完整内容如下

属性、代码块、构造器、方法、内部类

java
// 外部类
class outer_class{
    // 内部类
    class inner_class{

    }
}

// 外部其他类(与外部类呈并列关系)
class other_outer_class{

}

局部内部类

基本介绍

(1)局部内部类的本质是一个类

(2)由于是局部,可以看作是一个局部变量(成员),只是这个变量(成员)是一个类,其特性大同小异

使用细节

(1)局部内部类是定义在外部类的局部位置,并且有类名

(2)可以直接访问外部类的所有成员,包含私有

(3)局部内部类不能添加访问修饰符,但是可以使用 final 修饰

(4)作用域:仅仅在定义它的方法或代码块中(抓住局部的特性)

(5)成员的访问

局部内部类访问外部类的成员:直接访问

外部访问局部内部类的成员:创建对象,再访问(注意:必须在作用域内)

(6)外部其他不能访问局部内部类(局部内部类地位是一个局部变量)

(7)如果外部类和局部内部类的成员重名

1. 默认遵循就近原则

2. 如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

对于 this 的理解

(1) 外部类 . this:本质是外部类对象,哪个对象调用了局部内部类所在的方法或代码块,外部类.this 就是哪个对象

(2) this . n1:this 指向的是调用的当前对象,显然就是局部内部类这个对象的属性

代码示例

java
package inner;

public class main {
    public static void main(String[] args) {
        System.out.println("你创建了外部类的一个对象,接下来是构造器的初始化\n");
        outer_class outer_class = new outer_class();
        System.out.println("接下来调用外部类的 test() 方法\n");
        outer_class.test();
    }
}

// 外部类
class outer_class{

    {
        class inner_class_code_block{
            public void hi(){
                System.out.println("调用了 外部类 代码块中的 局部内部类 的 hi() 方法");
            }
        }
        inner_class_code_block inner_class_code_blockblock = new inner_class_code_block();
        inner_class_code_blockblock.hi();
    }

    int n1 = 10;
    private final int n2 = 20;

    // 构造器
    public outer_class(){
        // super()  调用父类的无参构造器,这里的父类是 Object()
        // 类的属性初始化
        System.out.println("调用了 外部类 的 无参构造器\n");
    }

    public void test(){

        System.out.println("进入了外部类的 test() 方法\n");

        // 局部内部类
        class inner_class{
            final int n1 = 30;
            public void test(){
                System.out.println("进入了局部内部类的 test() 方法");
                System.out.println("1. 访问外部类的成员 n1= " + outer_class.this.n1 + "\n(访问方法:类名.this.n1;注意:当方法名重名的时候,遵循就近原则)" + "\n" );
                System.out.println("2. 访问外部类的 私有 成员 n2=" + n2 + "\n");
                System.out.println("3. 访问局部内部类的成员 n1=" + n1 + "\n");
            }
        }

        // 外部类想要访问内部类的成员或者方法:创建对象,然后访问
        inner_class inner_class = new inner_class();

        System.out.println("通过创建对象的方法\n\n一、外部类 调用 局部内部类的 成员 n1=" + inner_class.n1 + "\n");
        System.out.println("二、外部类 调用 局部内部类的 test()方法\n");
        inner_class.test();
    }
}

// 输出结果
你创建了外部类的一个对象,接下来是构造器的初始化

调用了 外部类 代码块中的 局部内部类 的 hi() 方法
调用了 外部类 的 无参构造器

接下来调用外部类的 test() 方法
进入了外部类的 test() 方法

通过创建对象的方法

一、外部类 调用 局部内部类的 成员 n1=30

二、外部类 调用 局部内部类的 test()方法

进入了局部内部类的 test() 方法
1. 访问外部类的成员 n1= 10
(访问方法:类名.this.n1;注意:当方法名重名的时候,遵循就近原则)

2. 访问外部类的 私有 成员 n2=20

3. 访问局部内部类的成员 n1=30

⭐ 匿名内部类

需求引入

创建一个类实现接口方法,然后在外部类中使用实现了接口的类对象调用类对象实现的接口方法

java
package anonymous;

public class main {
    public static void main(String[] args) {
        outer_class outer_class = new outer_class();
        outer_class.test();
    }
}

interface ia{
    public void run();
}

// 单独创建tiger类,在outer_class中调用实现接口的方法
class tiger implements ia{
    public void run(){
        System.out.println("利用接口,实现了run()方法");
    }
}

class outer_class{
    public void test(){
        tiger tiger = new tiger();
        System.out.println("在outer_class中调用tiger中的test()方法\n");
        tiger.run();
    }
}

如果要求 tiger 类只使用一次,代码存在的问题

(1)单独创建类会使得代码冗余,代码不够简洁

(2)不利于维护,如果需要修改某个成员,那该类的所有对象都会受到影响,不够灵活

基本介绍

(1)本质是类,同时还是一个对象

(2)是内部类

(3)该类没有名字

(1)基本语法

java
new 类 或 接口(参数列表){
        类体
};

(2)特点

匿名内部类即是一个类的定义,同时它本身也是一个对象,因此从语法上看,他既有定义类的特征,也有创建对象的特征,因此可以调用匿名内部类方法

使用细节

匿名内部类和局部内部类都是定义在局部位置上,具有的特性大同小异

(1)可以直接访问外部类的所有成员,包含私有

(2)匿名内部类不能添加访问修饰符,但是可以使用 final 修饰

(3)作用域:仅仅在定义它的方法或代码块中

(4)成员的访问

1. 匿名内部类访问外部类成员:直接访问

2. 外部不能直接访问匿名内部类的成员,匿名内部类没有名字,无法通过创建类对象的方式访问

(6)外部其他不能访问匿名内部类(匿名内部类地位是一个局部变量)

(7)如果外部类和局部内部类的成员重名

1. 默认遵循就近原则

2. 如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

应用场景

(1)基于接口的匿名内部类

(2)基于的匿名内部类

(3)基于抽象类的匿名内部类

(4)某个类只使用一次,后续不再使用

(5)类可以作为实参传递

匿名内部类的本质可以理解为 new 接口或类,在底层就会分配一个类(这个类就是匿名内部类)去实现接口或继承一个类,返回这个类的对象实例地址,然后可以用一个对象实例接收,实现方法和成员的调用

基于接口的应用

java
package anonymous;

public class main {
    public static void main(String[] args) {
        outer_class outer_class = new outer_class();
        outer_class.test();
    }
}

interface ia{
    public void run();
}


class outer_class{
    public void test(){

        ia tiger = new ia() {
            @Override
            public void run() {
                System.out.println("在匿名内部类中,实现了接口方法run()");
            }
        };

        tiger.run();
        System.out.println("tiger的运行的运行类型是:" + tiger.getClass());
    }
}

// 运行结果
在匿名内部类中,实现了接口方法run()
tiger的运行的运行类型是:class anonymous.outer_class$1

代码分析

(1)匿名内部类没有类名,其实是在底层分配了一个类名(名称为:外部类的类名 + $1(按照使用的个数依次编号))

(2)底层源码分析

java
class outer_class$1 implements ia{
    @Override
    public void run() {
        System.out.println("在匿名内部类中,实现了接口方法run()");
    }
}

(3)当执行 new ia ( ) 的时候就表示创建了 outer_class$1 对象实例,把地址返回,通过 tiger 来接收,即相当于创建了 ia 类的 tiger 实例,在匿名内部类中重写了 run()方法(实现了接口方法)

(4)tiger 的运行类型就是匿名内部类

(5)匿名内部类(outer_class$1)使用一次后就不能再使用,但是接收的对象实例 tiger 是可以不断使用的

(6)对比之前的方法

先创建 tiger 类

实现接口

在 tiger 类中实现接口方法

在外部类中创建 tiger 对象实例,调用 tiger 中的方法

基于类的应用

java
package anonymous;

public class main {
    public static void main(String[] args) {
        outer_class outer_class = new outer_class();
        outer_class.test();
    }
}

class father{

    String name;

    public father(){

    }

    public father(String name){
        this.name = name;
    }

    public void hi(){
        System.out.println("调用了father的hi()方法");
    }

}
class outer_class{

    public void test(){
        father father = new father() {
            @Override
            public void hi(){
                System.out.println("匿名内部类重写了father类的hi()方法");
            }
        };

        father.hi();
        System.out.println("father的运行类型是:" + father.getClass());
    }
}
// 运行结果
匿名内部类重写了father类的hi()方法
father的运行类型是:class anonymous.outer_class$1

代码分析

与基于接口的应用类似,底层源码如下

java
class outer_class$1 extends father{
    @Override
    public void hi(){
        System.out.println("匿名内部类重写了father类的hi()方法");
    }
}

基于抽象类的应用

java
package anonymous;

public class main {
    public static void main(String[] args) {
        outer_class outer_class = new outer_class();
        outer_class.test();
    }
}

abstract class A {
    public abstract void hi();
}

class outer_class {

    public void test() {
        A a = new A() {
            @Override
            public void hi(){
                System.out.println("匿名内部类中重写了抽象类中的hi()方法");
            }
        };

        a.hi();
        System.out.println("匿名内部类的运行类型是:" + a.getClass());
    }
}

// 运行结果
匿名内部类中重写了抽象类中的hi()方法
匿名内部类的运行类型是:class anonymous.outer_class$1

底层源码分析

java
class outer_class$1 extends A{
  @Overide
  public void hi(){
     System.out.println("匿名内部类中重写了抽象类中的hi()方法");
  }
}

作为参数传递

应用场景:写一个类实现接口,在类中重写接口方法,在主类中调用接口方法

第一种:传统方法

java
package anonymous;

public class main {
    public static void main(String[] args) {
        animal animal = new animal();
        tool.interface_implement(animal);
    }
}

interface A{
    void hi();  // 默认是 public ,可以不写
}

class animal implements A{
    @Override
    public void hi() {
        System.out.println("animal类实现了接口,并重写了接口中的hi()方法");
    }
}

class tool{
    public static void interface_implement(A interface_member){
        interface_member.hi();
    }
}

// 运行结果
animal类实现了接口,并重写了接口中的hi()方法

问题分析

需要单独创建 animal 类实现接口,并重写接口中的方法,过于繁琐,代码冗余

第二种:匿名内部类解决

java
package anonymous;

public class main {
    public static void main(String[] args) {
        tool.interface_implement(new A() {
            @Override
            public void hi() {
                System.out.println("animal类实现了接口,并重写了接口中的hi()方法");
            }
        });
    }
}

interface A{
    void hi();  // 默认是 public ,可以不写
}

class tool{
    public static void interface_implement(A interface_member){
        interface_member.hi();
    }
}

// 运行结果
animal类实现了接口,并重写了接口中的hi()方法

代码分析

(1)将匿名内部类作为实参传递,代码简洁

(2)灵活性好:对比传统写法,若需要修改某些内容不会影响到实现了接口 A 的不同的类的所有对象实例

成员内部类

基本介绍

定义在外部类的成员位置,并且没有 static 修饰

使用细节

(1)可以直接访问外部类的所有成员,包含私有的

(2)可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员

(3)作用域和外部类的其他成员一样,为整个类体

(4)关于访问

1. 成员内部访问外部类成员:直接访问

2. 外部访问成员内部类:创建对象,再访问

(5)如果外部类和内部类的成员重名

1. 内部类访问的话,默认遵循就近原则

2. 如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问

(6)外部其他类访问成员内部类

理解:首先成员内部类的本质是成员,即可以用通过对象去访问,然而访问的是一个类,需要创建对象实例

方法一:访问成员时创建对象实例

java
package anonymous;

public class main {
    public static void main(String[] args) {
        other_class other_class = new other_class();
        other_class.hi();
    }
}

class outer_class{

    class inner_class{
        public void hi(){
            System.out.println("调用了outer_class中inner_class的hi()方法");
        }
    }
}

class other_class{
    // 在外部其他类中访问成员内部类

    public void hi(){
        System.out.println("调用了other_class的hi()方法");
        outer_class outer_class = new outer_class();
        // 访问成员的时候创建成员内部类对象实例
        outer_class.inner_class inner_class = outer_class.new inner_class();
        inner_class.hi();
    }
}

// 输出结果
调用了other_class的hi()方法
调用了outer_class中inner_class的hi()方法

方法二:写一个方法返回对象实例

java
package anonymous;

public class main {
    public static void main(String[] args) {
        other_class other_class = new other_class();
        other_class.hi();
    }
}

class outer_class{

    class inner_class{
        public void hi(){
            System.out.println("调用了outer_class中inner_class的hi()方法");
        }
    }

    public inner_class get_inner_class_instance(){
        return new inner_class();
    }
}

class other_class{
    // 在外部其他类中访问成员内部类

    public void hi(){
        System.out.println("调用了other_class的hi()方法");
        outer_class outer_class = new outer_class();
        // 访问成员的时候创建成员内部类对象实例
        outer_class.inner_class inner_class_instance = outer_class.get_inner_class_instance();
        inner_class_instance.hi();
    }
}

// 输出结果
调用了other_class的hi()方法
调用了outer_class中inner_class的hi()方法

静态内部类

基本介绍

静态内部类是定义在外部类的成员位置,并且有 static 修饰

使用细节

(1)可以直接访问外部类的所有静态成员,包含私有的,但不能访问非静态成员

(2)可以添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员

(3)作用域:同其他成员,为整个类体

(4)如果外部类和静态内部类的成员重名

1. 静态内部类访问时,默认遵循就近原则

2.如果想访问外部类的成员,则可以使用(外部类名.成员)去访问

(5)区别静态内部类和局部内部类

1. 静态只能访问静态的

2. 普通的能访问静态和非静态的

(6)关于访问

1. 静态内部类访问外部类:直接访问所有静态成员

2. 外部类访问静态内部类:创建对象,再访问

(7) 外部其他类访问静态内部类

1. 内部类是静态的,可以通过类名访问,无需先创建外部类对象

2. 可以直接通过类名访问到静态内部类然后创建对象实例

方法一:类名访问静态内部类,创建对象实例

java
package anonymous;

public class main {
    public static void main(String[] args) {
        other_class other_class = new other_class();
        other_class.hi();
    }
}

class outer_class{

    static class inner_class{
        public void hi(){
            System.out.println("调用了outer_class中inner_class的hi()方法");
        }
    }
}

class other_class{
    // 在外部其他类中访问成员内部类

    public void hi(){
        System.out.println("调用了other_class的hi()方法");
        // 注意:这里是静态内部类,直接通过类名访问
        outer_class.inner_class inner_class = new outer_class.inner_class();
        inner_class.hi();
    }
}

// 输出结果
调用了other_class的hi()方法
调用了outer_class中inner_class的hi()方法

代码分析

由于是静态的,直接用通过类名访问到静态内部类,之后创建静态内部类对象实例,调用相关的方法即可

方法二:编写一个方法,可以返回静态内部类的对象实例

java
package anonymous;

public class main {
    public static void main(String[] args) {
        other_class other_class = new other_class();
        other_class.hi();
    }
}

class outer_class {

    static class inner_class {
        public void hi() {
            System.out.println("调用了outer_class中inner_class的hi()方法");
        }
    }

    public static outer_class.inner_class get_inner_class_instance() {
        return new outer_class.inner_class();
    }
}

class other_class {
    // 在外部其他类中访问成员内部类

    public void hi() {
        System.out.println("调用了other_class的hi()方法");
        // 注意:这里是静态内部类,直接通过类名访问
        outer_class.inner_class inner_class_instance = outer_class.get_inner_class_instance();
        inner_class_instance.hi();
    }
}

// 输出结果
调用了other_class的hi()方法
调用了outer_class中inner_class的hi()方法

代码分析

编写一个方法返回静态内部类实例对象,由于是静态的,直接通过外部类的类名访问静态内部类,用一个变量接收返回的静态内部类实例,通过对象调用相关的方法