文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【JavaSE】内部类

2023-09-14 15:36

关注

文章目录

可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类。内部类也是封装的一种体现。内部类和外部类共用同一个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() {@Overridepublic void eat() {System.out.println("正在吃大餐");}};//上面这段代码其实就相当于class Outer1$1 implements IA {@Overridepublic 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();    }}

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

来源地址:https://blog.csdn.net/qq_58032742/article/details/132490956

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯