来看一个例子:
- class A{
- public B f() {
- return new B() {
- {
- setName("annoyInner"); // 非静态初始块, 等同于构造方法
- }
- //...
- // 可以自定义成员变量, 成员方法
- // 可以重写父类方法
- };
- }
- public static void main(String[] args) {
- A a = new A();
- System.out.println(a.f().getName());
- }
- }
- class B{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public B() {
- System.out.println("B 的无参构造");
- }
- }
打印结果:
B 的无参构造
annoyInner
在匿名类中, 可用花括号括起来进行一些必要的初始化操作, 表示非静态初始化块, 等同于构造方法. 由于没有方法名, 此构造方法不区分有参无参, 那么怎么在匿名构造方法中使用参数呢?
- class A{
- public B f() {
- String name = "annoyInner";
- return new B() {
- {
- setName(name); // 直接使用局部变量即可
- }
- //...
- // 可以自定义成员变量, 成员方法
- // 可以重写父类方法
- };
- }
- public static void main(String[] args) {
- A a = new A();
- System.out.println(a.f().getName());
- }
- }
- class B{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public B() {
- System.out.println("B 的无参构造");
- }
- }
打印结果同上. 匿名类中直接使用局部变量或成员变量即可, 相当于匿名类的有参构造器 (Java 中局部内部类和匿名内部类访问的局部变量必须由 final 修饰, 以保证内部类和外部类的数据一致性. 但从 Java 8 开始, 添加了 Effectively final 功能, 我们可以不加 final 修饰符, 由系统默认添加. 详情可点击《Java8 新特性之 Effectively final》进行学习.)
接下来又有个问题, 匿名类的构造器能不能重载呢?
答案是不能, 还是因为匿名类没有名字, 连赋予参数的地方都没有, 但是你可以这样写:
- class A{
- public B f() {
- return new B() {
- {
- setName("annoyInner1");
- }
- {
- setName("annoyInner2");
- }
- {
- setName("annoyInner3");
- }
- //...
- };
- }
- public static void main(String[] args) {
- A a = new A();
- System.out.println(a.f().getName());
- }
- }
打印结果是 annoyInner3, 这相当于是多个初始化块, 会依次执行, 并不是构造器的重载, 但是这样写跟写在一个初始化块中没有什么区别.
我们都知道匿名类实例化时会默认调用父类的无参构造, 如何调用父类的有参构造? 加上 super(name) 是不行的:
- class A{
- public B f() {
- return new B("annoyInner") {
- {
- //super(name); // 编译报错
- }
- };
- }
- public static void main(String[] args) {
- A a = new A();
- System.out.println(a.f().getName());
- }
- }
- class B{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public B() {
- System.out.println("B 的无参构造");
- }
- public B(String name) {
- this.name = name;
- System.out.println("B 的有参构造");
- }
- }
打印结果如下, 直接在匿名类的表达式中使用父类的有参构造即可
B 的有参构造
annoyInner
下面是一个很常见的匿名类的运用, 经常看见有人这么写:
- ArrayList<String> list = new ArrayList<String>() {{
- add("A");
- add("B");
- add("C");
- }};
- Map m = new HashMap() {
- {
- put("name","zhangsan");
- put("age",18);
- }
- };
看到这个, 我只想说:
花里胡哨!!!
拿 arrayList 为例, 外层的花括号创建了一个继承于 ArrayList 的匿名类, 里层的花括号表示在这个匿名类的初始化块中调用了继承而来的 add 方法, 实际上这个匿名类和 ArrayList 没有什么区别. 这样写好像是简洁了一些, 但是可读性也要差一些, 也并不会带来多少性能上的优化, 目前本人还不知道会不会引发什么问题. 不过取决于个人喜好, 用用也无妨.
来源: http://www.bubuko.com/infodetail-3344920.html