面试阿里,字节跳动,华为必须知道的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 ...
随机推荐
- 分布式消息系统之Kafka集群部署
一.kafka简介 kafka是基于发布/订阅模式的一个分布式消息队列系统,用java语言研发,是ASF旗下的一个开源项目:类似的消息队列服务还有rabbitmq.activemq.zeromq:ka ...
- MVC实现修改数据
前言 前言 最近没什么好写的,所以写个修改来巩固一下知识 控制器 public ActionResult UpdeteCartsNum(SYS_Carts sYS_Carts) { var list ...
- 51nod 最大M子段和系列(1052、1053、1115)
51nod1052 数据量小,可使用O(N*M)的DPAC,递推公式: dp[i][j]=max(dp[i-1][j-1], dp[i][j-1])+a[j]; dp[i][j]表示前j个数取 i 段 ...
- webpack4的安装使用
1.全局安装Webpack 安装到全局后你可以在任何地方共用一个 Webpack 可执行文件( 也就是说可以直接在终端使用webpack的命名 ,例如:webpack --config webpack ...
- Appium常用操作之「元素定位、swipe 滑屏操作」
坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:oschina.云+社区.知乎等各大平台都有. 目录 一.打开 uiautomatorviewer 二.Appium 常用操作 1.用 layui 做 ...
- 11 Servlet_03 关键字总结 资源跳转:重定项 键值对 继承类 do-get do-post Request域 Context域 =空针解决方法
知识点总结: 1.java里的关键字: byte short int long 数据类型 (正整数)char 数据类型(单字符型)boolesn ture false 布尔类型float dou ...
- Luogu P4643 阿狸和桃子的游戏
题解 传送门 既然题目要求的是差值 所以对于减数和被减数同时加上一个相同的数是毫无影响的 (详情参考人教版六年级上册数学教材) 所以不妨把边权分成两半 分别加给两个顶点 然后,直接每次选最大的点就好了 ...
- 03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)
功能和背景介绍 在项目的登录功能中,如果在登录时发现用户名和密码在用户表中不存在,会自动将用户名和密码保存在用户表中,创建一个新的用户. 因此,除了使用手机号和验证码登录以外,还支持使用用户名.密码进 ...
- python的分支语句与循环
一.分支语句 1.if else语句 语法: if 条件判断: 执行的语句块1 else : 执行语句块2 当满足条件的时候则执行语句块1 ,不满足条件就执行语句块2 注意:1.条件判断后面要加冒号& ...
- Java的Arrays.sort()方法到底用的什么排序算法
暂时网上看过很多JDK8中Arrays.sort的底层原理,有些说是插入排序,有些说是归并排序,也有说大于域值用计数排序法,否则就使用插入排序...其实不全对.让我们分析个究竟: 1 // Use Q ...