java new(创建)对象时结尾带上{}和不带的区别

发布时间 2023-11-01 19:41:29作者: 雨落寒沙

定义一个对象

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

熟悉(正常)的创建对象方式

Person p1 = new Person();

不熟悉的创建方式

Person p2 = new Person(){};

那二者有什么区别?

我们可以先打印出类的信息看看

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person(){};
        System.out.println("类信息:"+p1.getClass());
        System.out.println("类信息:"+p2.getClass());
    }
}
类信息:class Person
类信息:class Main$1

发现同样new了一个person对象,但p2的class信息居然不是person,说明p2并没有真正意义上的new了一个person对象,那这个所谓的Main$1又是个什么东西呢?

其实可以通过另一个更为常见的案例来理解清楚

 

定义一个接口

public interface HelloService {
    void say();
}

然后main方法里执行如下代码

public class Main {
    public static void main(String[] args) {
        HelloService service = new HelloService() {
            @Override
            public void say() {

            }
        };
        System.out.println("类信息:"+service.getClass());
    }
}

得到结果

类信息:class Main$1

上面的代码都很熟悉,其实就是创建了一个匿名类来实现了定义的接口。那其实我们可以间接的推导出Person p2 = new Person(){};这种方式创建的实际上是一个匿名类继承了Person类

通过以下方式可以证明上述结论

public class Main {
    public static void main(String[] args) {
        Person p2 = new Person(){};
        System.out.println("类信息:"+p2.getClass());
        System.out.println("父类信息:"+p2.getClass().getSuperclass());
    }
}
类信息:class Main$1
父类信息:class Person

同时也可以重写父类方法,例如下面的代码

public class Main {
    public static void main(String[] args) {
        Person p2 = new Person(){

            {
                System.out.println("对象初始化");
            }
            static {
                System.out.println("类初始化");
            }
            @Override
            public void say() {
                super.say();
                System.out.println("重写hello");
            }
        };
       p2.say();
    }
}
类初始化
对象初始化
hello
重写hello

 

使用场景:泛型处理

泛型实际上最终会处理为object,我们并不能直接获取到其类型,但是可以通过指定的泛型的对象的父类获取。

public class Person<E> {
    private E e;
}
public class PersonS extends Person<Integer> {
   
}
public class Main {
    public static void main(String[] args) {
        PersonS p1 = new PersonS();
        System.out.println(((ParameterizedType)p1.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }
}
class java.lang.Integer

 

而通过匿名类的方式处理可以更为优雅而不需要写专门的继承类

public class Main {
    public static void main(String[] args) {
        Person<Integer> p1 = new Person<>(){};
        System.out.println(((ParameterizedType)p1.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    }
}
class java.lang.Integer