【Java中创建对象的方式有哪些?】

news/2024/6/17 9:58:07 标签: java, 开发语言

在这里插入图片描述

✅Java中创建对象的方式有哪些?

  • ✅使用New关键字
  • ✅使用反射机制
  • ✅使用clone方法
  • ✅使用反序列化
  • ✅使用方法句柄
  • ✅ 使用Unsafe分配内存

✅使用New关键字


这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们还可以调用任意的构造函数 (无参的和有参的) 。


User user = new User();


✅使用反射机制


运用反射手段,调用Java.lang.Class或者Java.lang.reflect.Constructor类的newlnstance()实例方法。

1.使用Class类的newlnstance()方法


可以使用Class类的newlnstance方法创建对象。这个newlnstance方法调用无参的构造函数创建对象。


java">User user = (User)Class.forlame("xxx.xxx.User").newInstance();
User user = User.class .newInstance();

2.使用Constructor类的newlnstance方法


和Class类的newInstance方法很像,java.lang.reflect.Constructor类里也有一个newinstance()方法可以创建对象。我们可以通过这个newlnstance()方法调用有参数的和私有的构造函数。


java">Constructor constructor = User.class.getConstructor();
User user = constructor.newInstance();

这两种newInstance()方法就是大家所说的反射。事实上Class的newlnstance()方法内部调用Constructor的newlnstance()方法。


✅使用clone方法


无论何时我们调用一个对象的clone方法,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。


要使用clone方法,我们需要先实现Cloneable接口并实现其定义的clone方法。如果只实现了Cloneable接口,并没有重写clone方法的话,会默认使用Obiect类中的clone方法,这是一个native的方法。


java">public class CloneTest implements Cloneable {
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(string name)  {
		this .name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this .age = age;
	}
	public CloneTest(String name, int age) {
		super();
		this .name = name ;
		this .age = age;
	}
	public static void main(Stringl] args) {
		try {
			CloneTest cloneTest = new CloneTest("wangql",18);
			CloneTest copyClone = (CloneTest) cloneTest.clone();
			System.out.println("newclone:"+cloneTest.getName());
			System.out.println("copyClone:"+copyClone.getName());
			
		} catch (CloneNotSupportedException e) {
			e.printstackTrace();
		}
	}
}

✅使用反序列化


当我们序列化和反序列化一个对象,jvm会给我们创建一个单独的对象。其实反序列化也是基于反射实现的。


java">public static void main(Stringl] args) {
	//Initializes The Object
	User1 user = new User1();
	user.setName("Java");
	user.setAge(23);
	System.out.println(user);


	//Write Obj to File
	ObjectOutputStream oos = null;
	try {
		oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
		oos.writeObject(user);
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		IOUtils.closeQuietly(oos);
	}


	//Read Obj from File
	File file = new File("tempFile");
	ObjectInputStream ois = null;
	try {
		ois = new ObjectInputStream(new FileInputStream(file));
		User1 newUser = (User1) ois.readObject();
		System.out.println(newUser);
	} catch (IOException e)  {
		e.printstackTrace();
	} catch (ClassNotFoundException e)  {
		e.printstackTrace();
	}  finally  {
		IOUtils.closeQuietly(ois);
		try {
			FileUtils.forceDelete(file);
		} catch (IOException e) {
			e.printstackTrace();
		}
	}
}

✅使用方法句柄


通过使用方法句柄,可以间接地调用构造函数来创建对象


java">public static void main(String [] args) throws Throwable  {
	//定义构造函数的方法句柄类型为void类型,无参数
	MethodType constructorType = MethodType.methodType(void.class);


	//获取构造函数的方法句柄
	MethodHandles.Lookup lookup = MethodHandles.lookup();
	MethodHandle constructorHandle = lookup.findConstructor(User,class, constructorType);


	// 使用方法句柄调用构造函数创建对象
	User obj = (User) constructorHandle.invoke();
}

使用了MethodHandles.lookup().findConstructor()方法获取构造函数的方法句柄,然后通过invoke()方法调用构造函数来创建对象。


✅ 使用Unsafe分配内存


在Java中,可以使用sun.misc.Unsate类来进行直接的内存提作,包括内存分配和对象实例化。然而,需要注意的是,sun.misc.Unsafe类是Java的内部API,它并不属于Java标准库的一部分,也不建议直接在生产环境中使用。


java">public static void main(String[] args) throws Exception {
	
	Field field = Unsafe.class.getDeclaredField("theUnsafe");
	field.setAccessible(true);
	Unsafe unsafe = field.get(null);
	
	//获取User类的字段偏移量
	long nameOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("name"));
	long ageOffset = unsafe.objectField0ffset(User.class.getDeclaredField("age"));
	
	//使用allocateInstance方法创建对象,不会调用构造函数
	User user = (User) unsafe.allocateInstance(User.class);

	// 使用putObject方法设置字段的值
	unsafe.putObject(user, nameOffset,"Java");
	unsafe.putInt(user, ageOffset, 30);
}

这种方式有以下几个缺点:


1 . 不可移植性:Unsafe类的行为在不同的Java版本和不同的JVM实现中可能会有差异,因此代码在不同的环境可能会出现不可移植的问题。
2 . 安全性问题:Unsafe类的功能是非常强大和危险的,可以绕过Java的安全机制,可能会导致内存泄漏、非法访问、数据损坏等安全问题。
3 . 不符合面向对象的原则:Java是一门面向对象的语言,鼓励使用构造函数和工厂方法来创建对象,以确保对象的正确初始化和维护对象的不变性。

http://www.niftyadmin.cn/n/5284157.html

相关文章

力扣每日一题day38[106. 从中序与后序遍历序列构造二叉树]

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 示例 1: 输入:inorder [9,3,15,20,7], postorder [9,15,7,20,3] 输出:[…

树与堆的基本概念

当看到这里的时候,相信你的链表,队列,栈学的也差不多可以了,那么接下来让我们一起进入树的学习吧! 一.树的概念以及一些知识记忆 树的定义: 树是一种 非线性 的数据结构,它是由 n &#xff08…

全面解读《State of PostgreSQL 2023》报告

本文由 Cloudberry Database 社区根据 Timescale 发布的 2023 年最新《State of PostgreSQL》英文版报告整理而成。 《State of PostgreSQL》是由 Timescale 2019 年开始发起的一项 PostgreSQL 社区问卷调查,到今年已经进行了四年,问卷涉及受访者信息如区…

【leetcode100-018】【矩阵】矩阵置零

【题干】 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 进阶: 一个直观的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。一个简单的改进方案是使用 O(…

Pixi入门第一章:绘制一个小精灵

之前有介绍过threeJs做3D场景的教程,但是发现web3D还是有很多局限性的,尤其是在绘制地图一方面,3D场景必须通过射线选取物体,而且会因为相机视角的问题出现偏差,另一方面3D在渲染性能上消耗远大于2D的场景,…

【飞翔的鸟】飞行游戏-uniapp项目开发流程详解

小时候玩过的飞行游戏,叫什么名字来着,通过点击操作控制煽动翅膀来持续飞行,躲避障碍物,有多远就飞多远吧,现在想起来,其中的实现原理非常简单,感兴趣的话来一起看看,这里给大家讲一…

MYSQL 5.7数据库同步结构#1067报错 invalid default value for解决方法

一直喜欢把数据库下载到本地电脑再进行升级,数据库结构同步,结构同步时今天一直出现1067报错 invalid default value for ,网上搜索了很多方法也没解决,主要原因是PHP5.7 里 Mysql 不允许时间戳的值为 0 导致同步错误,…

JSP打印直角三角形

代码&#xff1a; <%page language"java" contentType"text/html;charsetutf-8"%> <html> <head><title>expressionDemo</title> </head> <body> <h1>以直角三角形的形式输出数字</h1> <table&…