java new(创建)对象时结尾带上{}和不带的区别
定义一个对象
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