Java 之旅

初级11 - 接口与抽象类(下)

2019-08-06  本文已影响0人  晓风残月1994

1. 内部类

用来实现更加精细的封装,可以和外部类之间访问更方便,包括:

内部类和静态内部类的区别:

public class Outer {
    private void log() {
        System.out.println("ok");
    }

    private class InnerA {
        // 编译器会偷偷注入一个外部类的实例/对象
        // final Outer this$0;
        log(); // ok
    }

    private static class InnerB {
        log(); // 不 ok
    }
}

原则:永远使用静态内部类,除非编译报错(参考 《Effective Java》)

如果因为内部类中访问外部类的实例方法时编译报错了,则有两种做法:

public class Outer {
    private void log() {
        System.out.println("ok");
    }

    private static class Inner {
        private Outer outer;
        public Inner(Outer outer) {
            this.outer = outer;
        }
        outer.log(); // 这次 ok 了
    }
}

2. 匿名内部类

直接通过 new 的方式创建的无名类

class XXX implements Predicate<Object> {
    @Override
    public boolean test(Object obj) {
        return false;
    }
}

new XXX() 进行实例化时,等价于直接使用匿名类:

public class Outer {
    // ...
    new Predicate<Object>() {
        @Override
        public boolean test(Object obj) {
            return true;
        }
    }
}

注意这种语法形式!可以简单理解为语法糖,要记住接口是不能被实例化的,只是被实现了。
编译成字节码后,上面的匿名内部类会用Outer$1.class来表示文件名。

来看下面的例子:

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class NameCollector implements Consumer<User> {
    private final List<String> names = new ArrayList<>();

    @Override
    public void accept(User user) {
        names.add(user.getName());
    }

    public List<String> getNames() {
        return names;
    }
}

使用匿名内部类进行优化后,就不需要上面具名的实现类了:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class User {
    /** 用户ID,数据库主键,全局唯一 */
    private final Integer id;

    /** 用户名 */
    private final String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    // 这里不再使用 NameCollector 类,而是改写成匿名内部类
    // 使得代码更加集中,更加容易阅读
    public static List<String> collectNames(List<User> users) {
        // NameCollector collector = new NameCollector();
        // users.forEach(collector);
        // return collector.getNames();

        final List<String> names = new ArrayList<>();
        users.forEach(new Consumer<User>(){
            @Override
            public void accept(User user) {
                names.add(user.getName());
            }
        });
        return names;
    }

    public static void main(String[] args) {
        List<User> users = Arrays.asList(new User(1, "a"), new User(2, "b"));
        System.out.println(collectNames(users));
    }
}

参考:
Java 内部类与外部类的互访使用小结

上一篇 下一篇

猜你喜欢

热点阅读