面试阿里,字节跳动,华为必须知道的Java创建对象的5种方式
Java创建对象的5种方式
1.直接new,调用了构造器
2.通过clone(),没有调用构造器
3.通过反射,调用了构造器
4.通过反序列化,没有调用构造器
5.通过Unsafe类的allocateInstance()方法,没有调用构造器
1. 直接new
public class CreateByNew {
public CreateByNew() {
System.out.println("调用了构造...");
}
public static void main(String[] args) {
CreateByNew c1 = new CreateByNew();
CreateByNew c2 = new CreateByNew();
System.out.println(c1 == c2);//false
}
}
输出:
调用了构造...
调用了构造...
false
2. 通过clone()
需要实现Cloneable接口,可分为深克隆和浅克隆。clone()后的新对象会复制原对象的属性,但是并不会调用构造函数。
public class CreateByClone implements Cloneable {
public int temp;
public CreateByClone() {
System.out.println("调用了构造..");
}
public static void main(String[] args) throws CloneNotSupportedException {
CreateByClone c1 = new CreateByClone();
c1.temp = 222;
CreateByClone c2 = (CreateByClone) c1.clone();
System.out.println(c2.temp);
System.out.println(c1 == c2);
}
}
输出:
调用了构造..
222
false
3. 通过反射
反射创建对象:
class.newInstance():调用了无参构造
获取对应的Constructor,调用constructor的newInstance(),调用对应构造函数创建对象
public class CreateByReflection {
private int temp;
public int getTemp() {
return temp;
}
public CreateByReflection() {
System.out.println("调用了空参构造...");
}
public CreateByReflection(int temp) {
this.temp = temp;
System.out.println("调用了带参构造...");
}
public static void main(String[] args) throws Exception {
Class clazz = CreateByReflection.class;
//通过无参构造反射创建
CreateByReflection c1 = (CreateByReflection) clazz.newInstance();
//通过带参构造反射创建
Constructor constructor = clazz.getDeclaredConstructor(int.class);
CreateByReflection c2 = (CreateByReflection) constructor.newInstance(10);
System.out.println(c2.getTemp());
System.out.println(c1 == c2);
}
}
输出:
调用了空参构造...
调用了带参构造...
10
false
4. 反序列化创建对象
需要被序列化的对象实现Serializable接口,不会调用构造,反序列化回来的对象的属性值与序列化之前一致,但是是一个新对象。
public class CreateBySerializable {
public static void main(String[] args) {
Person p1 = new Person("二狗", 18);
writeObject(p1);
Person p2 = readObjcet();
System.out.println(p2);
System.out.println(p1 == p2);
}
public static void writeObject(Person person) {
FileOutputStream fileOut = null;
ObjectOutputStream out = null;
try {
fileOut = new FileOutputStream("person.txt");
out = new ObjectOutputStream(fileOut);
out.writeObject(person);
System.out.println("Serialized data is saved");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static Person readObjcet() {
Person temp = null;
FileInputStream fileIn = null;
ObjectInputStream in = null;
try {
fileIn = new FileInputStream("person.txt");
in = new ObjectInputStream(fileIn);
temp = (Person) in.readObject();
System.out.println("Deserialized Person...");
return temp;
} catch (Exception e) {
e.printStackTrace();
return null;
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fileIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Person implements Serializable {
public Person() {
System.out.println("调用了空参构造...");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("调用了带参构造...");
}
public String name;
public int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
输出:
调用了带参构造...
Serialized data is saved
Deserialized Person...
Person{name='二狗', age=18}
false
5. 通过Unsafe类
Unsafe类通过native方法直接操作内存分配空间,创建对象。此时对象并没有执行构造,只是在内存中分配了空间,所有属性此时都是对应类型的0值。而且该对象并不被JVM管理,需要我们自己回收。
Unsafe类的构造为私有,且通过@CallerSensitive方法保证只有BootStrap类加载器加载的类才可以调用Unsafe类中的方法。
所以只能通过反射获取Unsafe类实例。
public class CreateByUnsafe {
public static void main(String[] args) throws Exception {
//基于反射获取Unsafe实例
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
People p1 = (People) unsafe.allocateInstance(People.class);
People p2 = (People) unsafe.allocateInstance(People.class);
p1.age = 18;
System.out.println(p1);
System.out.println(p1 == p2);
//返回成员变量在内存中的地址相对于对象内存地址的偏移量
Field f = People.class.getDeclaredField("age");
long offset = unsafe.objectFieldOffset(f);
System.out.println(offset);//12
// markword:8bytes(64bits) + class pointer:4bytes(32bits) == 12 bytes
}
}
class People {
public int age;
@Override
public String toString() {
return "People{" +
"age=" + age +
'}';
}
}
输出:
People{age=18}
false
12
面试阿里,字节跳动,华为必须知道的Java创建对象的5种方式的更多相关文章
- 必须知道的Java八大排序算法
冒泡排序.简单选择.直接插入.快速排序.堆排序.希尔排序.归并排序.基数排序. 将其按排序方式分类如下图所示: 1.冒泡排序: 基本思想——在要排序的一组数中,对当前还未排好序的范围内的全部数据,自上 ...
- 从零开始学习jQuery(剧场版) 你必须知道的javascript
原文:从零开始学习jQuery(剧场版) 你必须知道的javascript 一.摘要 本文是jQuery系列教程的剧场版, 即和jQuery这条主线无关, 主要介绍大家平时会忽略的一些javascri ...
- [你必须知道的.NET]第二十五回:认识元数据和IL(中)
发布日期:2009.02.25 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回[第二十四回:认识元数据和IL(上)], ...
- C语言学习书籍推荐《你必须知道的495个C语言问题》
萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...
- c语言学习书籍推荐《C语言学习路线图•C语言必须知道的300个问题》下载
下载地址:点我 <C语言学习路线图•C语言必须知道的300个问题>以基础知识为框架,介绍了c语言各部分知识所对应的常见开发疑难问题,并作了透彻地解析.<C语言学习路线图•C语言必须知 ...
- C#刨根究底:《你必须知道的.NET》读书笔记系列
一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...
- (转)【推荐】初级.NET程序员,你必须知道的EF知识和经验
转自:http://www.cnblogs.com/zhaopei/p/5721789.html [推荐]初级.NET程序员,你必须知道的EF知识和经验 阅读目录 [本文已下咒.先顶后看,会涨 ...
- 《你必须知道的.NET》读书笔记一:小OO有大智慧
此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.对象 (1)出生:系统首先会在内存中分配一定的存储空间,然后初始化其附加成员,调用构造函数执行初 ...
- 《你必须知道的.NET》读书笔记二:小OO有大原则
此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.单一职责原则 (1)核心思想:一个类最好只做一件事,只有一个引起它变化的原因 (2)常用模式:Fa ...
随机推荐
- Vue 过滤器入门
Vue 允许自定义过滤器,可被用于一些常见的文本格式化 过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 过滤器应该被添加在JavaScript表达式的尾部,由"管道" ...
- 线程池SingleThreadPool
只有一个核心线程,当被占用时,其他的任务需要进入队列等待 public class MainActivity extends AppCompatActivity { @Override protect ...
- LinkedHashMap 实现LRU缓存
date: 2020-07-09 13:52:00 updated: 2020-07-21 17:40:00 LinkedHashMap 实现LRU缓存 参考 LinkedHashMap是HashMa ...
- 双非本科拿到阿里腾讯字节,分享Java后端路线
前言 最近有很多小师妹来问我. 师妹:师兄~看了你之前的从腾讯到阿里,最后选择字节,觉得你特别厉害,请问你是怎么进BAT的呀,能不能告诉我你的学习路线呀~ 既然小师妹都这么问了,那我在这篇就如实回答她 ...
- 签到功能,用 MySQL 还是 Redis ?
现在的网站和app开发中,签到是一个很常见的功能,如微博签到送积分,签到排行榜. 如移动app ,签到送流量等活动. 用户签到是提高用户粘性的有效手段,用的好能事半功倍! 下面我们从技术方面看看常 ...
- Learn day6 模块pickle\json\random\os\zipfile\面对对象(类的封装 操作 __init__)
1.模块 1.1 pickle模块 # ### pickle 序列化模块 import pickle """ 序列化: 把不能够直接存储的数据变得可存储 反序列化: 把数 ...
- Java线程池原理及分析
线程池是很常用的并发框架,几乎所有需要异步和并发处理任务的程序都可用到线程池. 使用线程池的好处如下: 降低资源消耗:可重复利用已创建的线程池,降低创建和销毁带来的消耗: 提高响应速度:任务到达时,可 ...
- 排序算法—快速排序(Quick Sort)
快速排序(Quick Sort) 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序. ...
- CF716D Complete The Graph
图论+构造 首先可以发现如果去除了可以改变权值的边,$s$到$t$的最短路若小于$l$,那么一定不行 若等于则直接将可改边权的边改为inf,输出即可 那么现在原图中的最短路是大于$l$的 因为每一条边 ...
- simulink产生周期矩形波和8421码
初次入门simulink,由于学习了数字逻辑,试图进行仿真,首先需要的就是8421码,但是没找到simulink里面相关模块,如果各位知道怎么弄可以评论告诉我分享分享哈哈 我用的是matlab2016 ...