java实例化对象后面添加花括号的理解分析

java实例化对象后面添加花括号的理解分析

昨天在看MyBatis官方文档时看到这么一段代码
  return new SQL() {{
    SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
    FROM("PERSON P");
    if (id != null) {
      WHERE("P.ID like #{id}");
    }
    if (firstName != null) {
      WHERE("P.FIRST_NAME like #{firstName}");
    }
    if (lastName != null) {
      WHERE("P.LAST_NAME like #{lastName}");
    }
    ORDER_BY("P.LAST_NAME");
  }}.toString();
在类构造器后面加两对花括号{{}},这是我第一次见到这种写法,加一对{}我知道这是用来创建匿名子类,一般是用来实例化接口或实例化抽象类,但是里面还有一对{}是怎么个意思呢?通过自己判断以及问人和百度,得到答案是这是代码块,和普通类里定义代码块一样,但真的是这样吗?先附上主体代码,接着一步步分析解读

public class AppTest {
    int num; //声明AppTest成员属性

    //静态打印方法
    public static void staticPrint(String msg) {
        System.out.println(msg);
    }

    //成员打印方法
    public void memberPrint(String msg) {
        System.out.println(msg);
    }

    public static void main(String[] args) {
        AppTest test = new AppTest(); //创建AppTest实例对象
        test.num = 5;
        test.run(); //调用成员方法
        Person staticPerson = new Person("静态张三") {
            @Override
            public void printName() {
                System.out.println("静态子类打印name:" + super.name);
            }
            {
                staticPrint("继承了Person的AppTest静态内部类构造器调用外部类的静态方法");
                System.out.println("继承了Person的AppTest静态内部类构造器调用父类的方法输出name:");
                printName();
            }
        };
        Class clzz = staticPerson.getClass();
        System.out.println("实例化对象person的全限定类名:" + clzz.getName());
        Class superClzz = clzz.getSuperclass();
        System.out.println("实例化对象person的全限定父类类名:" + superClzz.getName());
    }

    public void run() {
        Person memberPerson = new Person("张三") {
            @Override
            public void printName() {
                System.out.println("成员子类打印name:" + super.name);
            }

            {
                System.out.println("上下文中AppTest成员对象的num属性值:"+AppTest.this.num);
                staticPrint("继承了Person的AppTest成员内部类构造器中调用外部类AppTest的静态方法");
                memberPrint("继承了Person的AppTest成员内部类构造器中调用外部类AppTest的成员方法");
                printName();
            }
        };
        Class clzz = memberPerson.getClass();
        System.out.println("实例化对象person的全限定类名:" + clzz.getName());
        Class superClzz = clzz.getSuperclass();
        System.out.println("实例化对象person的全限定父类类名:" + superClzz.getName());
    }
}

class Person {
    protected String name;

    {
        System.out.println("Person实例初始化...");
    }

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }
    
    void printName() {
        System.out.println("name:"+name);
    }
}

打印结果

Person实例初始化...
上下文中AppTest成员对象的num属性值:5
继承了Person的AppTest成员内部类构造器中调用外部类AppTest的静态方法
继承了Person的AppTest成员内部类构造器中调用外部类AppTest的成员方法
成员子类打印name:张三
实例化对象person的全限定类名:com.farmlay.modules.blog.test.AppTest$2
实例化对象person的全限定父类类名:com.farmlay.modules.blog.test.Person
Person实例初始化...
继承了Person的AppTest静态内部类构造器调用外部类的静态方法
继承了Person的AppTest静态内部类构造器调用父类的方法输出name:
静态子类打印name:静态张三
实例化对象person的全限定类名:com.farmlay.modules.blog.test.AppTest$1
实例化对象person的全限定父类类名:com.farmlay.modules.blog.test.Person
一共创建了2个Person实例对象,分别是在静态main方法中和成员方法run中创建,通过打印对象的 Class.getName()我们发现2个对象的className分别是在这里插入图片描述、,className中有美元符号一般表示这是内部类(java命名不建议含有$),继续看他们的父类是Person

也就是说这两个Person对象其实是2个继承了Person类的AppTest内部类的实例化对象

通过编译可以看到确实是有2个AppTest内部类
java实例化对象后面添加花括号的理解分析_第1张图片
然后我们再回过头来看打印信息

继承了Person的AppTest成员内部类构造器中调用外部类AppTest的静态方法
继承了Person的AppTest成员内部类构造器中调用外部类AppTest的成员方法

继承了Person的AppTest静态内部类构造器调用外部类的静态方法

仔细看看2个对象打印出来的信息有什么不一样,成员方法中打印出来的是成员内部类,而静态方法中打印出来的是静态内部类,等等。。为什么明明是在{{}}代码块中调用的方法却打印“构造器中调用”?开始不是说和普通类定义代码块是一样的吗?我们可以通过jad反编译工具看看这到底是怎么回事

AppTest$1

static class AppTest$1 extends Person
{

    public void printName()
    {
        System.out.println((new StringBuilder()).append("\u9759\u6001\u5B50\u7C7B\u6253\u5370name\uFF1A").append(super.name).toString());
    }

    AppTest$1(String s)
    {
        super(s);
        AppTest.staticPrint("\u7EE7\u627F\u4E86Person\u7684AppTest\u9759\u6001\u5185\u90E8\u7C7B\u6784\u9020\u5668\u8C03\u7528\u5916\u90E8\u7C7B\u7684\u9759\u6001\u65B9\u6CD5");
        System.out.println("\u7EE7\u627F\u4E86Person\u7684AppTest\u9759\u6001\u5185\u90E8\u7C7B\u6784\u9020\u5668\u8C03\u7528\u7236\u7C7B\u7684\u65B9\u6CD5\u8F93\u51FAname\uFF1A");
        printName();
    }
}

AppTest$2

class AppTest$2 extends Person
{

    public void printName()
    {
        System.out.println((new StringBuilder()).append("\u6210\u5458\u5B50\u7C7B\u6253\u5370name\uFF1A").append(super.name).toString());
    }

    final AppTest this$0;

    AppTest$2(String s)
    {
        this$0 = AppTest.this;
        super(s);
        System.out.println((new StringBuilder()).append("\u4E0A\u4E0B\u6587\u4E2DAppTest\u6210\u5458\u5BF9\u8C61\u7684num\u5C5E\u6027\u503C\uFF1A").append(num).toString());
        AppTest.staticPrint("\u7EE7\u627F\u4E86Person\u7684AppTest\u6210\u5458\u5185\u90E8\u7C7B\u4EE3\u7801\u5757\u4E2D\u8C03\u7528\u5916\u90E8\u7C7BAppTest\u7684\u9759\u6001\u65B9\u6CD5");
        memberPrint("\u7EE7\u627F\u4E86Person\u7684AppTest\u6210\u5458\u5185\u90E8\u7C7B\u4EE3\u7801\u5757\u4E2D\u8C03\u7528\u5916\u90E8\u7C7BAppTest\u7684\u6210\u5458\u65B9\u6CD5");
        printName();
    }
}

AppTest

public class AppTest
{

    public AppTest()
    {
    }

    public static void staticPrint(String s)
    {
        System.out.println(s);
    }

    public void memberPrint(String s)
    {
        System.out.println(s);
    }

    public static void main(String args[])
    {
        AppTest apptest = new AppTest();
        apptest.num = 5;
        apptest.run();
        Person person = new Person("\u9759\u6001\u5F20\u4E09") {

            public void printName()
            {
                System.out.println((new StringBuilder()).append("\u9759\u6001\u5B50\u7C7B\u6253\u5370name\uFF1A").append(super.name).toString());
            }

            
            {
                AppTest.staticPrint("\u7EE7\u627F\u4E86Person\u7684AppTest\u9759\u6001\u5185\u90E8\u7C7B\u6784\u9020\u5668\u8C03\u7528\u5916\u90E8\u7C7B\u7684\u9759\u6001\u65B9\u6CD5");
                System.out.println("\u7EE7\u627F\u4E86Person\u7684AppTest\u9759\u6001\u5185\u90E8\u7C7B\u6784\u9020\u5668\u8C03\u7528\u7236\u7C7B\u7684\u65B9\u6CD5\u8F93\u51FAname\uFF1A");
                printName();
            }
        }
;
        Class class1 = person.getClass();
        System.out.println((new StringBuilder()).append("\u5B9E\u4F8B\u5316\u5BF9\u8C61person\u7684\u5168\u9650\u5B9A\u7C7B\u540D\uFF1A").append(class1.getName()).toString());
        Class class2 = class1.getSuperclass();
        System.out.println((new StringBuilder()).append("\u5B9E\u4F8B\u5316\u5BF9\u8C61person\u7684\u5168\u9650\u5B9A\u7236\u7C7B\u7C7B\u540D\uFF1A").append(class2.getName()).toString());
    }

    public void run()
    {
        Person person = new Person("\u5F20\u4E09") {

            public void printName()
            {
                System.out.println((new StringBuilder()).append("\u6210\u5458\u5B50\u7C7B\u6253\u5370name\uFF1A").append(super.name).toString());
            }

            final AppTest this$0;

            
            {
                this$0 = AppTest.this;
                super(s);
                System.out.println((new StringBuilder()).append("\u4E0A\u4E0B\u6587\u4E2DAppTest\u6210\u5458\u5BF9\u8C61\u7684num\u5C5E\u6027\u503C\uFF1A").append(num).toString());
                AppTest.staticPrint("\u7EE7\u627F\u4E86Person\u7684AppTest\u6210\u5458\u5185\u90E8\u7C7B\u4EE3\u7801\u5757\u4E2D\u8C03\u7528\u5916\u90E8\u7C7BAppTest\u7684\u9759\u6001\u65B9\u6CD5");
                memberPrint("\u7EE7\u627F\u4E86Person\u7684AppTest\u6210\u5458\u5185\u90E8\u7C7B\u4EE3\u7801\u5757\u4E2D\u8C03\u7528\u5916\u90E8\u7C7BAppTest\u7684\u6210\u5458\u65B9\u6CD5");
                printName();
            }
        }
;
        Class class1 = person.getClass();
        System.out.println((new StringBuilder()).append("\u5B9E\u4F8B\u5316\u5BF9\u8C61person\u7684\u5168\u9650\u5B9A\u7C7B\u540D\uFF1A").append(class1.getName()).toString());
        Class class2 = class1.getSuperclass();
        System.out.println((new StringBuilder()).append("\u5B9E\u4F8B\u5316\u5BF9\u8C61person\u7684\u5168\u9650\u5B9A\u7236\u7C7B\u7C7B\u540D\uFF1A").append(class2.getName()).toString());
    }

    int num;
}

可以看出来成员方法中通过new Person(“张三”){{}}会创建成员内部类,静态方法中通过new Person(“静态张三”){{}}会创建静态内部类,在{{}}定义的行为被定义在了构造器中,这是因为编译器会将构造代码块的内容添加到每个未调用其它构造器的方法体的最前面,但是构造器会先执行super构造器,成员类比静态类多个 final AppTest this$0 成员对象、构造方法中有 this$0 = AppTest.this;这样就可以持有外部类的引用,我们编码时需要这样写AppTest.this.num。

总结

new Object(){{}} 意思是在当前类下创建一个继承至Object的内部类;外层{}中可重写或实现或定义新方法(不能定义静态方法);内层{}最终是构造函数,由Object()指定重写具体哪个构造函数。

----1:静态方法中是创建一个静态内部类,在{{}}里可以调用外部类的静态方法、父类的方法
----2:成员方法中是创建一个成员内部类,在{{}}里可以调用外部类的方法、父类的方法,持有外部类的引用

你可能感兴趣的:(java基础)