【JavaSE】匿名内部类

举报
兮动人 发表于 2022/03/29 21:29:11 2022/03/29
【摘要】 1. 匿名内部类的使用 2. 匿名内部类发注意事项 3. 匿名内部类的最佳实践 1. 匿名内部类的使用(1)本质是类(2)内部类(3)该类没有名字(名字不是能直接看到的,实际上是系统取的)(4)同时还是一个对象说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名匿名内部类的基本语法new 类或接口(参数列表) { 类体}传统方法实现 ,写一个类,实现该接口,并创建对象publ...

1. 匿名内部类的使用

(1)本质是类
(2)内部类
(3)该类没有名字(名字不是能直接看到的,实际上是系统取的
(4)同时还是一个对象

  • 说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
  1. 匿名内部类的基本语法
new 类或接口(参数列表) {
	类体
}
  • 传统方法实现 ,写一个类,实现该接口,并创建对象
public class AnonymouseInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}


class Outer04 {//外部类
    private int n1 = 10;

    public void method() {
        //基于接口的匿名内部类
        //解读:
        //1.需求:使用IA接口,并创建对象
        //2.传统方式,写一个类,实现该接口,并创建对象
        IA tiger = new Tiger();
        tiger.cry();
    }
}

interface IA {//接口
    public void cry();
}

class Tiger implements IA {

    @Override
    public void cry() {
        System.out.println("老虎叫唤...");
    }
}

class Father {
    public Father(String name) {

    }
    public void test() {

    }
}

在这里插入图片描述

  • 如果 Tiger 这个对象只用一次,后面不再使用了,如果再定义一个 Dog 类,而且也只用一次,这种情况下就会定义很多类,这种情况有可能很多只用一次的情况,创建对象浪费资源

  • 解决方案:这个时候就可以使用 匿名内部类 来简化开发

  • 需求:既不去创建 Tiger 对象,又能去调用 Tiger 类中的方法

  • 接口是不能直接 new 的,但是后面重写的方法相当于在 Tiger 类中重写的方法
    在这里插入图片描述
    在这里插入图片描述

  • 匿名内部类实现

public class AnonymouseInnerClass {
    public static void main(String[] args) {
        Outer04 outer04 = new Outer04();
        outer04.method();
    }
}


class Outer04 {//外部类
    private int n1 = 10;

    public void method() {
        //1.可以使用匿名内部类来开发
        //2.tiger的编译类型是 IA
        //3.tiger的运行类型是 匿名内部类
        /*
         * 看底层 类名
         *  class XXX implements IA {
         *      @Override
                public void cry() {
                    System.out.println("老虎叫唤...");
                }
         * }
         * XXX = Outer04$1
         * 
         * 系统会分配 类名 Outer04$1
         *
         */
        // 4. jdk底层在创建匿名内部类 Outer04$1 ,马上就创建了 Outer04$1 实例,并且把地址返回给 tiger 
        // 5. 匿名内部类使用一次,就不能再使用了
        IA tiger = new IA(){
            @Override
            public void cry() {
                System.out.println("老虎叫唤...");
            }
        };
        tiger.cry();

        System.out.println("tiger运行类型=" + tiger.getClass());

    }

}

interface IA {//接口
    public void cry();
}
  • 可以看到使用匿名内部类也能达到同样的效果,并且不会创建该类,而是以匿名的方式创建的
  • 可以看底层系统给匿名内部类分配的类名,jdk底层在创建匿名内部类 Outer04$1 ,马上就创建了 Outer04$1 实例,并且把地址返回给 tiger ,匿名内部类使用一次,就不能再使用了。但是 tiger 对象可以使用。
class XXX implements IA {
	@Override
	public void cry() {
	      System.out.println("老虎叫唤...");
	  }
	}
	
XXX 类名 = Outer04$1
就是等于在外部类的基础上 加上 $1

在这里插入图片描述

  • 查看匿名内部类分配的名字
class XXX implements IA {

	@Override
	public void cry() {
	    System.out.println("老虎叫唤...");
	}
}
System.out.println("tiger运行类型=" + tiger.getClass());
  • 由上述可知,XXX 类名为 Outer04$1,是系统分配的类名。jdk底层在创建匿名内部类 Outer04$1 ,马上就创建了 Outer04$1 实例,并且把地址返回给 tiger
  • 上面是基于接口的匿名内部类实现。

案例演示:基于类的匿名内部类的实现

//分析
//1.father编译类型 Father
//2.father运行类型 Outer04$2
//3.底层会创建匿名内部类
/*
    class Outer04$2 extends Father{
        @Override
        public void test() {
            System.out.println("匿名内部类重写了test()");
        }
    }
 */
//4,同时也直接返回了 匿名内部类 Outer04$2 的对象
Father father = new Father("jack"){
    @Override
    public void test() {
        System.out.println("匿名内部类重写了test()");
    }
};

System.out.println("father运行类型=" + father.getClass());
father.test();

class Father {
    public Father(String name) {

    }
    public void test() {
    }
}
  • 也可以直接查看的到匿名内部类的类名
    在这里插入图片描述

  • 基于抽象类的匿名内部类,编译类型是 Animal,运行类型是匿名内部类

//基于抽象类的匿名内部类
Animal animal = new Animal(){
    @Override
    void eat() {
        System.out.println("小狗吃骨头...");
    }
};
animal.eat();
//查看系统分配给匿名内部类的 类名


abstract class Animal {
    abstract void eat();
}

在这里插入图片描述

2. 匿名内部类发注意事项

  1. 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义,同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。
public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.f1();
    }
}

class  Outer05 {
    private int n1 = 99;
    public void f1() {
        //创建一个基于类的匿名内部类
        Person person = new Person(){
            @Override
            public void hi() {
                System.out.println("匿名内部类重写了 hi 方法");
            }
        };
        person.hi(); //动态绑定,运行类型是 Outer05$1

        //也可以直接调用, 匿名内部类本身也是返回对象
        // class 匿名内部类 extends Person{}
        new Person(){
            @Override
            public void hi() {
                System.out.println("匿名内部类重写了 hi 方法,1111");
            }

            @Override
            public void ok(String str) {
                super.ok(str);
            }
        }.ok("xdr");
    }
}
class Person {
    public void hi() {
        System.out.println("Person hi()");
    }
    public void ok(String str) {
        System.out.println("Person ok()" + str);
    }
}

在这里插入图片描述

  1. 可以直接访问外部类的所有成员,包含私有的
public class AnonymousInnerClassDetail {
    public static void main(String[] args) {
        Outer05 outer05 = new Outer05();
        outer05.f1();
    }
}

class  Outer05 {
    private int n1 = 99;
    public void f1() {
        //创建一个基于类的匿名内部类
        Person person = new Person(){
            @Override
            public void hi() {
                //可以直接访问外部类的所有成员,包含私有的
                System.out.println("匿名内部类重写了 hi 方法 n1=" + n1);
            }
        };
	person.hi(); //动态绑定,运行类型是 Outer05$1

class Person {
    public void hi() {
        System.out.println("Person hi()");
    }
}

在这里插入图片描述

  1. 不能添加访问修饰符,因为它的地位就是一个局部变量。
    在这里插入图片描述

  2. 作用域:仅仅在定义它的方法或代码块中。

  3. 匿名内部类——>访问——>外部类成员【访问方式:直接访问】

  4. 外部其他类——不能访问——>匿名内部类【因为匿名内部类地位是一个局部变量】
    在这里插入图片描述

  5. 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则如果想访问外部类的成员,则可以使用【外部类名.this.成员】去访问
    在这里插入图片描述
    在这里插入图片描述

  • 如果想访问同名外部类的话,可以使用 【外部类名.this.成员】去访问
    在这里插入图片描述
    在这里插入图片描述

  • 上面的 Outer05.this 就是调用 f1 的对象,谁调用 f1 对象,这个 Outer05.this 就是谁

  • 可以看到都是同一个对象,所以对象外部类去访问 n1 ,指的就是外部类的属性
    在这里插入图片描述
    在这里插入图片描述

3. 匿名内部类的最佳实践

  1. 当做实参直接传递,简洁高效。
  • 传统方法实现
public class InnerClassExercise01 {
    public static void main(String[] args) {

        //传统方法
        f1(new Picture());

    }

    //静态方法,形参是接口类型
    public static void f1(IL il) {
        il.show();
    }
}

//类->实现IL => 编程领域 (硬编码)
class Picture implements IL {

    @Override
    public void show() {
        System.out.println("这是一副名画...");
    }
}

在这里插入图片描述

  • 匿名内部类实现
public class InnerClassExercise01 {
    public static void main(String[] args) {

        //当做实参直接传递,简洁高效
        f1(new IL() {
            @Override
            public void show() {
                System.out.println("这是一副名画~~...");
            }
        });

    }

    //静态方法,形参是接口类型
    public static void f1(IL il) {
        il.show();
    }
}
//接口
interface IL {
    void show();
}

在这里插入图片描述

  1. 案例2
1.有一个铃声接口Bell,里面有个ring方法。(右图)
2. 有一个手机类Cellphone,具有闹钟功能alarmclock,参数是Bell类型(如下图)
3. 测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,打印:懒猪起床了
4. 再传入另一个匿名内部类(对象),打印:小伙伴上课了

在这里插入图片描述

  • 思路:匿名内部 (1) 继承 (2) 多态 (3) 动态绑定 (4) 内部类
public class InnerClassExercise02 {
    public static void main(String[] args) {
 
        CellPhone cellPhone = new CellPhone();
        //解读:
        //1. 传递的是实现了 Bell接口的匿名内部类 InnerClassExercise02$1
        //2. 重写了 ring
        //3. Bell bell = new Bell() {
        //            @Override
        //            public void ring() {
        //                System.out.println("懒猪起床了");
        //            }
        //        }
        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("懒猪起床了");
            }
        });

        cellPhone.alarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}
interface Bell{ //接口
    void ring();//方法
}
class CellPhone{//类
    public void alarmClock(Bell bell){//形参是Bell接口类型
        System.out.println(bell.getClass());
        bell.ring();//动态绑定
    }
}

在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。