【JavaSE】内部类

简介: 【JavaSE】内部类

内部类概念

可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件。

public class OutClass {//外部类
  class InnerClass{ //内部类
  }
}

上面的代码中,OutClass是外部类,InnerClass就是内部类。它与普通外部类最大的不同,在于其实例对象不能单独存在,必须依附于一个外部类的实例对象。

局部内部类

局部内部类是定义在外部类的局部位置,通常在方法里。它拥有外部类中所有元素的访问权限。不能添加访问修饰符,因为它就相当于是一个局部变量,但是可以使用final修饰。作用域仅仅只能在定义它的方法或代码块中。

class Outer{ //外部类
    private int a = 1;//私有属性
    private void fun2(){ //私有方法
        System.out.println("Outer fun2()");
    }
    public void fun1(){ 
        System.out.println("Outer fun1()");
        final class Inner{ //局部内部类
            private int a = 2;
            public void funInner(){
                System.out.println(a); // 1 外部变量名重名 就近原则
                //Outer.this本质上就是外部类的对象,即哪个对象调用了fun1,Outer.this就指向哪个对象
                System.out.println(Outer.this.a); // 2
                fun2();
            }
        }
        Inner inner = new Inner();
        inner.funInner();
    }
}
public class InnerClass {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.fun1();
    }
}

如果外部类和局部内部类成员重名时,默认遵循就近原则,如果想要访问外部类成员可以使用 外部类名.this.成员名。

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

匿名内部类就是指没有类名的内部类,必须在创建时使用 new 语句来声明。通常情况下,如果一个方法的参数是接口类型,且该接口只需要实现一次,那么我们就可以通过匿名内部类的形式来进行定义。

基于接口的匿名内部类实例:

class Outer1 {
    private int a = 10;
    public void method() {
        //基于接口的匿名内部类
        IA person = new IA() {
            @Override
            public void eat() {
                System.out.println("正在吃大餐");
            }
        };
        //查看person的运行类型
        System.out.println("person的运行类型:" + person.getClass()); // Outer1$1
        person.eat();
    }
}
//接口
interface IA {
    void eat();
}
class Person implements IA {
    @Override
    public void eat() {
        System.out.println("吃");
    }
}
public class AnonInter {
    public static void main(String[] args) {
        Outer1 outer1 = new Outer1();
        outer1.method();
    }
}
IA person = new IA() {
  @Override
  public void eat() {
    System.out.println("正在吃大餐");
  }
};
//上面这段代码其实就相当于
class Outer1$1 implements IA {
  @Override
  public void eat() {
    System.out.println("正在吃大餐");
  }
}

jdk底层在创建匿名内部类 Outer1$1 时,立即创建了 Outer1$1 实例,并且把地址返回给了person,匿名内部类只能使用一次就不能再使用了。

基于类的匿名内部类和抽象内部类实例:

class Outer2 {
    public void method() {
        //编译类型:Animal
        //运行类型:Outer2$1
        Animal animal = new Animal("小白"){ //基于类的匿名内部类
            @Override
            public void eat() {
                System.out.println("匿名内部类重写了eat()");;
            }
        };
        animal.eat();
        System.out.println(animal.getClass()); //animal的运行类型 Outer2$1
        //编译类型:Robot
        //运行类型:Outer2$2
        Robot robot = new Robot(){ //基于抽象类的匿名内部类
            @Override
            void run() {
                System.out.println("正在奔跑");
            }
        };
        robot.run();
        System.out.println(robot.getClass());// robot的运行类型 Outer2$2
    }
}
class Animal implements IC {
    String name;
    public Animal(String name) {
        this.name = name;
    }
    public void eat(){
        System.out.println("Animal 在吃东西");
    }
    @Override
    public void run() {
        System.out.println("重写的run()");
    }
}
abstract class Robot { //抽象类
    abstract void run();
}
interface IC { //接口
    void run();
}
//测试
public class InterClass {
    public static void main(String[] args) {
        Outer2 outer2 = new Outer2();
        outer2.method();
    }
}

匿名内部类细节

匿名内部类既是一个类的定义,同时也是一个对象,从语法上看,它即有定义类的特征,也有创建对象的特征。

public class AnonClassDatil {
    public static void main(String[] args) {
        Outer3 outer3 = new Outer3();
        outer3.fun();
    }
}
class Outer3 {
    public void fun(){
        Car car = new Car(){ // 运行类型 Outer3$1
            @Override
            public void speed() {
                System.out.println("重写了speed()");;
            }
        };
        car.speed(); //动态绑定
        //也可以直接调用
        new Car(){
            @Override
            public void speed() {
                System.out.println("直接调用speed()");
            }
        }.speed();
    }
}
class Car {
    public void speed() {
        System.out.println("Car speed()");
    }
}

请看下面的代码

public class InnerExcise {
    public static void main(String[] args) {
        fun(new IQ() { //当做实参直接传递 简洁高效
            @Override
            public void show() {
                System.out.println("正在学习Java内部类");
            }
        });
    }
    public static void fun(IQ iq) { //静态方法 形参是接口类型
        iq.show();
    }
}
interface IQ {
    void show();
}

练习:

有一个铃声接口Bell,里面有一个ring方法,有一个手机类 CellPhone,具有闹钟的功能alarmClock,参数是Bell类型,测试手机类的闹钟功能,通过匿名内部类作为参数,打印 “起床了要迟到了”,再传入另一个匿名内部类,打印 “已经迟到了”。

public class InnerExcise1 {
    public static void main(String[] args) {
        CallPhone callPhone = new CallPhone();
        callPhone.alarmClock(new Bell() { //传递的是实现了Bell接口的匿名内部类
            @Override
            public void ring() {
                System.out.println("起床了要迟到了");
            }
        });
        callPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("已经迟到了");
            }
        });
    }
}
interface Bell {
    void ring();
}
class CallPhone {
    public void alarmClock(Bell bell) {
        bell.ring(); // 动态绑定
    }
}

成员内部类

成员内部类是定义在外部类的成员位置,并且没有static修饰,可以访问外部类的所以成员,包括私有成员。可以添加任意访问修饰符,因为它本质上就是一个成员。简而言之,成员内部类就是指没有被static修饰的内部类,也可以称为非静态内部类。

public class InnerExcise2 {
    public static void main(String[] args) {
        Outer5 outer5 = new Outer5();
        outer5.fun();
    }
}
class Outer5 {
    private int a = 10;
    private class Inner { // 可以添加任意访问修饰符
        public void say() {
            System.out.println(a); //可以访问外部类的所有成员,包括私有成员
        }
    }
    public void fun() {
        Inner inner = new Inner();
        inner.say();
    }
}
public class InnerExcise2 {
    public static void main(String[] args) {
        Outer5 outer5 = new Outer5();
        outer5.fun();
        //外部其他类 使用成员内部类的几种方式
        // 第一种 outer5.new Inner() 相当于是把new Inner()当成一个成员
        Outer5.Inner outer51 = outer5.new Inner(); 
        outer51.say();
        Outer5.Inner outer52 = outer5.shawOuter5();
        outer52.say();
    }
}
class Outer5 {
    private int a = 10;
    public class Inner { // 可以添加任意访问修饰符
        public void say() {
            System.out.println(a); //可以访问外部类的所有成员,包括私有成员
        }
    }
    //第二种 定义一个方法 返回一个Inner对象
    public Inner shawOuter5() {
        return new Inner();
    }
    public void fun() {
        Inner inner = new Inner();
        inner.say();
    }
}

如果有重名的成员,会遵守就近原则,如果要访问外部类成员,访问方法和上面的一样,外部类名.this.成员名。

静态内部类

静态内部类和成员内部类的定义类似,但要使用static修饰,所以称为静态内部类。静态内部类不再依附于Outer的实例,而是一个完全独立的类,因此无法引用Outer.this的方式调用。但它可以访问Outer类的private静态字段和静态方法,如果我们把静态内部类移到Outer类之外,就失去了访问private的权限。

public class StaticInnerClass {
    public static void main(String[] args) {
        Outer6 outer6 = new Outer6();
        outer6.fun1();
        //外部其他类访问静态内部类
        //静态内部类可以直接通过类名访问
        Outer6.Fun fun1 = new Outer6.Fun();
        fun1.show();
        //通过定义一个方法返回静态内部类
        Outer6.Fun fun2 = outer6.getFun();
        fun2.show();
    }
}
class Outer6 {
    private static int a = 99;
    private static String str = "java";
    static class Fun {
        public static int a = 999;
        public void show() {
            System.out.println(str);
            System.out.println(a); //同名成员遵循就近原则
            System.out.println(Outer6.a); //通过 外部类名.成员名访问
        }
    }
    public void fun1() {
        Fun fun = new Fun();
        fun.show();
    }
    public Fun getFun() {
        return new Fun();
    }
}

静态内部类中只能访问静态外部类的静态属性和方法

相关文章
|
前端开发 Python
模板继承
模板继承。
259 1
|
机器学习/深度学习 缓存 数据挖掘
Python性能优化:提升你的代码效率
【10月更文挑战第22天】 Python性能优化:提升你的代码效率
435 1
|
自然语言处理 Java
AviatorScript轻量级高性能脚本语言
在 5.0 版本以前,它的名字是叫 Aviator ,定位一直只是一个表达式引擎,不支持 if/else 条件语句(仅有三元运算符支持 ?: ),没有内置的 for/while 循环支持(虽然你可以用 seq 库类似函数式的方式来处理集合),也没有赋值(后来在 4.0 引入),没有作用域的概念(也在 4.0 引入 lambda 函数后部分实现)等等一般语言常见的能力。在 5.0 版本后,它变成了一门脚本语言,叫:AviatorScript 。
3046 0
|
消息中间件 人工智能 Dragonfly
|
10天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
7786 13
|
9天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1687 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
5天前
|
人工智能 JavaScript 芯片
DeepSeek 官方偷偷上传 Harness 桌面端安装包,我已经用上了。。附最新下载地址
DeepSeek Harness 官方的桌面端安装包被网友扒出来了,2 分钟讲明白如何使用,体验如何,适合作为 AI 编程工具么?附最新 Windows 和 Mac 双端的下载地址
1466 1
|
9天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
1405 11

热门文章

最新文章