java 内部类

1. 什么是内部类

类的五大成员:

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

在一个类的里面,再定义一个类。

例如:在A类的内部定义B类,B类就被称为内部类,A就相应的被称为外部类

2. 为什么要学习内部类

内部类表示的事物是外部类的一部分

内部类单独出现没有任何意义

内部类的访问特点:

        ① 内部类可以直接访问外部类的成员,包括私有

        ② 外部类要访问内部类的成员,必须创建对象

3. 内部类的分类

        ① 成员内部类

        ② 静态内部类

        ③ 局部内部类

        ④ 匿名内部类

前三种一般只会在看源代码时看到,自己在通常情况下是不会写的

需要重点掌握的是成员内部类

成员内部类 

写在成员位置的,属于外部类的成员

例如:

public class Car{  // 外部类
    String carName;
    int carAge;
    int carColor;
    class Engine{   // 成员内部类
        String engineName;
        int engineAge;
    }
}

① 成员内部类的代码如何书写

        a. 跟成员一样,可以被权限修饰符和static等修饰

        b. 成员内部类里面在jdk16之前是不能定义静态变量的,在jdk16开始才能定义

② 如何创建成员内部类的对象

        a. 方式一:在外部类中编写方法,对外提供内部类的对象

        b. 方式二:直接创建格式:外部类名.内部类名 对象名 = new 外部类对象.new 内部类对象;

③ 成员内部类如何获取外部类的成员变量

package innerclass;

public class Outer {
    private int a = 10;

    class Inner{
        private int a = 20;

        public void show(){
            int a = 30;
            System.out.println(a);   // 30
            System.out.println(this.a); // 20
            System.out.println(Outer.this.a);  // 10
        }
    }
}

编译后生成的.class文件的内部类:


class Outer$Inner {
    private int a;

    Outer$Inner(Outer var1) {
        this.this$0 = var1;
        this.a = 20;
    }

    public void show() {
        byte var1 = 30;
        System.out.println(var1);
        System.out.println(this.a);
        System.out.println(this.this$0.a);
    }
}

外部类:

public class Outer {
    private int a = 10;

    public Outer() {
    }

    class Inner {
        private int a = 20;

        Inner() {
        }

        public void show() {
            byte var1 = 30;
            System.out.println(var1);
            System.out.println(this.a);
            System.out.println(Outer.this.a);
        }
    }
}

调用外部类属性使用Outer.this.a的原因:

        在非静态内部类的隐藏着final的Outer类型的属性 this$0

        可是隐藏的属性是不能被显示调用的,也就是说不能使用this.this$0这种方式调用

        在官方文档上https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.8.4

        

Any lexically enclosing instance (§8.1.3) can be referred to by explicitly qualifying the keyword this.

任何词法封闭的实例(第 8.1.3 节)都可以通过显式限定关键字 this 来引用。

Let T be the type denoted by TypeName. Let n be an integer such that T is the n'th lexically enclosing type declaration of the class or interface in which the qualified this expression appears.

令 T 为由 TypeName 表示的类型。令 n 为整数,使得 T 是出现限定 this 表达式的类或接口的第 n 个词法封闭类型声明。

The value of an expression of the form TypeName.this is the n'th lexically enclosing instance of this.

TypeName.this 形式的表达式的值是 this 的第 n 个词法封闭实例。

The type of the expression is T.

表达式的类型是 T。

It is a compile-time error if the expression occurs in a class or interface which is not an inner class of class T or T itself.

如果表达式出现在不是类 T 或 T 本身的内部类的类或接口中,则是编译时错误。

代码里的类型是Outer,所以用显示Outer.this来表示Outer

静态内部类  静态内部类使用static修饰

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问外部类中非静态的需要创建外部类对象 

创建内部类对象:

        外部类名.内部类名 对象名 = new 外部类名.内部类名();

        调用非静态方法的格式:先创建对象,用对象调用

        调用静态方法的格式:外部类名.内部类名.方法名();

局部内部类

1. 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量

2. 外界是无法直接使用,需要在方法内部创建对象并使用

2. 该类可以直接访问外部类的成员,也可以访问方法内的局部变量 

匿名内部类

什么是匿名内部类:

        隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置

匿名内部类的语法规则:

new 父类构造器(参数列表)|实现接口() {   
    代码块  重写方法
}

格式细节:
    包含了继承或实现,方法重写,创建对象。
    整体就是一个类的子类对象或者接口的实现类对象。

注意: 

        ① 匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口,且两者不可兼得

        ② 匿名内部类中不能定义构造函数

        ③ 匿名内部类中不能存在任何静态变量成员和静态方法

        ④ 匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效

        ⑤ 匿名内部类不能是抽象的,他必须要实现继承的类或者实现接口中所有的抽象方法

AnonymousInner.java
public class AnonymousInner {
    public int anInt = 1;
    /**
     * 包含两个方法的HelloWorld接口
     *
     */

    interface HelloWord{
        void greet();
    }

    protected HelloWord a = new HelloWord() {
        @Override
        public void greet() {
            System.out.println(anInt);
        }
    };

    public void sayHello(){
        // 1. 局部内部类EnglishGreeting实现了HelloWorld接口
        class EnglishGreeting implements HelloWord{

            @Override
            public void greet() {
                System.out.println("EnglishGreeting");
            }
        }

        HelloWord englishGreeting = new EnglishGreeting();

        // 2. 匿名类实现HelloWold接口
        HelloWord frenchGreeting = new HelloWord() {
            @Override
            public void greet() {
                System.out.println("frenchGreeting");
            }
        };  // 需要分号

        englishGreeting.greet();
        frenchGreeting.greet();
        this.a.greet();
    }


}
AnonymousInnerTest.java
public class AnonymousInnerTest {
    public static void main(String[] args) {
        AnonymousInner anonymousInner = new AnonymousInner();
        anonymousInner.sayHello();
    }
}

执行javac  AnonymousInner命令后生成的.class文件

AnonymousInner.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

public class AnonymousInner {
    public int anInt = 1;
    protected AnonymousInner.HelloWord a = new AnonymousInner.HelloWord() {
        public void greet() {
            System.out.println(AnonymousInner.this.anInt);
        }
    };

    public AnonymousInner() {
    }

    public void sayHello() {
        class EnglishGreeting implements AnonymousInner.HelloWord {
            EnglishGreeting() {
            }

            public void greet() {
                System.out.println("EnglishGreeting");
            }
        }

        new EnglishGreeting();
        AnonymousInner.HelloWord var10000 = new AnonymousInner.HelloWord() {
            public void greet() {
                System.out.println("frenchGreeting");
            }
        };
    }

    interface HelloWord {
        void greet();
    }
}

AnonymousInner$1.class   对标AnonymousInner.java文件中的 属性a指向的内部类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import AnonymousInner.HelloWord;

class AnonymousInner$1 implements HelloWord {
    AnonymousInner$1(AnonymousInner var1) {
        this.this$0 = var1;
    }

    public void greet() {
        System.out.println(this.this$0.anInt);
    }
}

AnonymousInner$1EnglishGreeting.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import AnonymousInner.HelloWord;

class AnonymousInner$1EnglishGreeting implements HelloWord {
    AnonymousInner$1EnglishGreeting(AnonymousInner var1) {
        this.this$0 = var1;
    }

    public void greet() {
        System.out.println("EnglishGreeting");
    }
}

AnonymousInner$2.class  对标 AnonymousInner.java文件中frenchGreeting所指向的匿名内部类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import AnonymousInner.HelloWord;

class AnonymousInner$2 implements HelloWord {
    AnonymousInner$2(AnonymousInner var1) {
        this.this$0 = var1;
    }

    public void greet() {
        System.out.println("frenchGreeting");
    }
}

 AnonymousInner$HelloWord.class

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

interface AnonymousInner$HelloWord {
    void greet();
}

使用场景:

        当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象,如果实现类只要使用一次,就可以用匿名内部类见划代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值