Java 匿名类(匿名内部类)

Java 匿名类(匿名内部类)

学习的参考博文:无恨之都

1. 初识 匿名类

标准说法: 内部类包括:成员类、局部类、匿名类(匿名内部类)。

匿名类概念:

  • 匿名类可以使你的代码更加简洁 (JDK8之后Lambda更简洁)。
  • 你可以定义一个类的同时对其进行实例化
  • 它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要使用一次,就可以使用匿名类代替局部类
  • 匿名类是表达式,而非常规的类

匿名类的使用场景:

  • 一个局部类只需要使用一次的时候
  • 由于匿名类没有类名,那么除了定义它的地方,其他地方无法调用,所以匿名类也可以叫匿名内部类

2. 通过示例分析局部类和匿名类区别

sayHello方法中有局部类和匿名类分别实现HelloWorld接口的方法

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        /**
         * 1、局部类:EnglishGreeting实现了HelloWorld接口
         */
        class EnglishGreeting implements HelloWorld {
            String name = "无参";
            @Override
            public void greet() {
                greetSomeone(name);
            }
            @Override
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("局部类:" + name);
            }
        }
        // 创建局部类EnglishGreeting的实例化对象,使用接口类型接收
        HelloWorld englishGreeting = new EnglishGreeting();
        // 局部类:无参方法
        englishGreeting.greet();
        // 局部类:带参方法
        englishGreeting.greetSomeone("带参");


        /**
         * 2、匿名类实现HelloWorld接口并创建了实例化对象:frenchGreeting
         */
        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "无参";
            @Override
            public void greet() {
                greetSomeone(name);
            }
            @Override
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("匿名类:" + name);
            }
        };

        // 匿名类:无参方法
        frenchGreeting.greet();
        // 匿名类:带参方法
        frenchGreeting.greetSomeone("带参");
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }

【输出】

局部类:无参
局部类:带参
匿名类:无参
匿名类:带参

【分析】
  代码里局部类和匿名类实现的功能是一样的,内部的方法实现的代码是也一样的,区别只在实现HelloWorld接口的地方

局部类的格式是:

  1. 创建局部类并且实现接口:class EnglishGreeting implements HelloWorld {...}
  2. 创建局部类的实例化对象并用接口类型接收:HelloWorld englishGreeting = new EnglishGreeting();
  3. 调用实例化对象的方法

匿名类的格式是:

  1. 创建匿名类实现接口同时对其进行实例化:HelloWorld frenchGreeting = new HelloWorld() {...}
  2. 调用实例化对象的方法

【区别】

  1. 局部类EnglishGreeting实现HelloWorld接口,有自己的类名:EnglishGreeting,定义完成后需要再对其实例化对象:englishGreeting才能可以使用方法
  2. 匿名类在定义时就已经实例化成对象:frenchGreeting,定义完了就可以直接使用方法
  3. 匿名类是一个表达式,因此在定义的最后用分号结束

3. 匿名内部类的语法

3.1 匿名类实现接口

其实上面的示例中的匿名类就是实现接口的方式,这个示例将实现更复杂的功能

public class InterfaceTest {
    public static void main(String[] args) {
        TomInterface tif = new TomInterface() {
            String name = "汤姆";
            @Override
            public void getName() {
                System.out.println(name);
            }

            TomInterface setName(String name){
                this.name = name;
                return this;
            }
        }.setName("杰瑞");
        tif.getName();
    }
}

interface TomInterface{
    void getName();
}

【结果】

杰瑞

【分析】

  1. main方法创建匿名类实现TomInterface接口并实例化:new TomInterface{...}
  2. 调用匿名类对象的setName方法,将杰瑞赋值给匿名类的成员变量name,并返回当前实例this给接口变量tif
  3. main方法调用匿名类对象的方法tif.getName(),而此时的匿名类的成员变量name的值已经被替换成杰瑞,所以最后输出杰瑞而不是汤姆

3.2 匿名类继承父类 (匿名子类)

匿名类继承父类,调用父类构造,重写父类方法

public class ExtendTest {

    public static void main(String[] args) {
        String name = "李四";
        // 创建父类对象,打印原始name值
        PartherClass partherClass = new PartherClass();
        System.out.println("父类的getName方法=" + partherClass.getName());
        // 使用匿名类继承父类,并打印name值
        PartherClass pc = new PartherClass(name){
            @Override
            public String getName(){
                return "匿名类 - "+super.getName();
            }
        };
        System.out.println(pc.getName());
    }
}

class PartherClass{
    private String name = "张三";
    public PartherClass(){}
    public PartherClass(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
}

【结果】

父类的getName方法=张三
匿名类 - 李四

【分析】

  1. 创建父类对象并调用getName方法,这个不用细说
  2. 创建匿名类继承父类并实例化对象:pc,本次匿名类调用的是父类的带参构造,将参数赋值给了父类的name
  3. 调用匿名类重写的getName方法,得到新的name

3.3 区别

Demo demo = new Demo(xxx){...}
  1. 操作符:new
  2. 一个要实现的接口或要继承的类,示例3.1 是实现接口,示例3.2 是继承类
  3. 一对括号,如果是匿名子类,那么父类有构造参数就填,不带参就空着;如果匿名类是实现接口,那么括号里需要空着
  4. {...},括号里括着的是匿名类的声明主体
  5. 末尾的;号,因为匿名类的声明是一个表达式,是语句的一部分,所以需要分号结尾
  6. 表面上看匿名类没有类名,没有构造参数。但其实在编译的时候,编译器会给匿名类分配类名和构造器,只是我们无法操作也不能复用。如需验证,可以看编译后的class文件,多出一个命名格式:匿名类定义类$?.class的文件。例如示例3.2,匿名类的class文件就是:ExtendTest$1.class

你可能感兴趣的:(Java,java,类,匿名内部类,匿名类)