java首先创建什么,java创建对象的五种方式

java中创建对象有几种方式?

一、使用new关键字

如 User user=new User();

执行这条语句,jvm做了什么?

首先在方法区的常量池中查看是否有new 后面参数(也就是类名)的符号引用,并检查是否有类的加载信息也就是是否被加载解析和初始化过。如果已经加载过了就不在加载,否则执行类的加载全过程

加载完类后,大致做了如下三件事: a、给实例分配内存 b、调用构造函数,初始化成员字段 c、user对象指向分配的内存空间 注意:new操作不是原子操作,b和c的顺序可能会调换

二、使用clone方法

当我们调用一个对象的clone方法,jvm就会创建一个新的对象,将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。因为Object 类的 clone 方法的 原理是从内存中(堆内存)以二进制流的方式进行拷贝,重新分配一个内存块,那构造函数没有被执行也是非常正常的了.

使用clone方法创建对象的实例:

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(String[] args) {

try {

CloneTest cloneTest = new CloneTest("酸辣汤",18);//todo

CloneTest copyClone = (CloneTest) cloneTest.clone();

System.out.println("newclone:"+cloneTest.getName());

System.out.println("copyClone:"+copyClone.getName());

} catch (CloneNotSupportedException e) {

e.printStackTrace();

}

}

}

输出:

newclone:酸辣汤

copyClone:酸辣汤

注意:

1.clone是Object中的方法,Cloneable是一个标识接口,它表明这个类的对象是可以拷贝的。如果没有实现Cloneable接口却调用了clone()函数将抛出异常

2.Object.clone()未做同步处理,线程不安全

3.clone()有深拷贝和浅拷贝两种方式

复制代码

三、使用反序列化

序列化是干什么的?

简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。虽然你可以用你自 己的各种各样的方法来保存object states,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。一句话概括:序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。

java中要序列化的类必要实现Serializable接口

什么情况下需要序列化

a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;

b)当你想用套接字在网络上传送对象的时候;

c)当你想通过RMI(远程方法调用)传输对象的时候;

使用反序列化创建对象实例:

1.对象要实现Serializable接口

import java.io.Serializable;

public class Person implements Serializable {

int age;

int height;

String name;

public Person(String name, int age, int height){

this.name = name;

this.age = age;

this.height = height;

}

}

复制代码

2、序列化与反序列化

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

public class MyTestSer {

/**

* Java对象的序列化与反序列化

*/

public static void main(String[] args) {

Person zhangsan = new Person("zhangsan", 30, 170);

Person lisi = new Person("lisi", 35, 175);

Person wangwu = new Person("wangwu", 28, 178);

try {

//需要一个文件输出流和对象输出流;文件输出流用于将字节输出到文件,对象输出流用于将对象输出为字节

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.ser"));

out.writeObject(zhangsan);

out.writeObject(lisi);

out.writeObject(wangwu);

} catch (IOException e) {

e.printStackTrace();

}

try {

ObjectInputStream in = new ObjectInputStream(new FileInputStream("person.ser"));

Person one = (Person) in.readObject();

Person two = (Person) in.readObject();

Person three = (Person) in.readObject();

System.out.println("name:"+one.name + " age:"+one.age + " height:"+one.height);

System.out.println("name:"+two.name + " age:"+two.age + " height:"+two.height);

System.out.println("name:"+three.name + " age:"+three.age + " height:"+three.height);

} catch (Exception e) {

e.printStackTrace();

}

}

}

运行结果:

name:zhangsan age:30 height:170 //todo

name:lisi age:35 height:175

name:wangwu age:28 height:178

复制代码

android中的场景

1.组件间(如activity间)的对象传递 (实现Parcelable或Serializable接口)

2.使用 Binder进行进程间的通讯传递的对象必须实现Parcelable接口

Serializable 是java的序列化接口,使用简单但是开销比较大,序列化和反序列化都涉及到大量的I/O操作,效率相对较低。Parcelable是Android提供的序列化方法,更适用于Android平台,效率很高,但是使用起来比较麻烦.Parcelable主要用在内存序列化上,序列化存储设备或将序列化后的对象通过网络传输建议使用Serializable。

四、使用反射

通过反射来创建类对象的实例,有两个步骤:

首先我们得拿到类对象的Class

如何获取? 有三种方式(反射章节会详细讲解)

类.class,如Person.class

对象.getClass()

Class.forName("类全路径")

通过反射创建类对象的实例对象

在拿到类对象的Class后,就可以通过Java的反射机制来创建类对象的实例对象了,主要分为两种方式:

Class.newInstance()

调用类对象的构造方法

举个栗子:

首先准备一个Person的类:

public class Person {

private String name;

private int age;

public Person() {

}

public Person(String name, int age) {

this.name = name;

this.age = 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;

}

@Override

public String toString() {

return "Person{" +

"name='" + name + '\'' +

", age=" + age +

'}';

}

}

复制代码

使用Class.newInstance()创建对象:

public class ClassNewInstance {

public static void main(String[] args) throws IllegalAccessException, InstantiationException {

Person person = Person.class.newInstance();

person.setAge(18);

person.setName("酸辣汤");

System.out.println(person);

}

}

运行结果:

Person{name='酸辣汤', age=18}

复制代码

注意 :newInstance创建对象实例的时候会调用无参的构造函数,所以必需确保类中有无参数的可见的构造函数,否则将会抛出异常。

调用类对象的构造方法——Constructor

Constructor是Java反射机制中的构造函数对象,获取该对象的方法有以下几种:

Class.getConstructors():获取类对象的所有可见的构造函数

Class.getConstructor(Class... paramTypes):获取指定的构造函数

获取类对象所有的构造方法并遍历:

public class ConstructorInstance {

public static void main(String[] args) {

Class p = Person.class;

for(Constructor constructor : p.getConstructors()){

System.out.println(constructor);

}

}

}

运行结果:

public com.eft.reflect.Person()

public com.eft.reflect.Person(java.lang.String,int)

复制代码

获取指定的构造方法

通过Class.getConstructor(Class... paramTypes)即可获取类对象指定的构造方法,其中paramTypes为参数类型的Class可变参数,当不传paramTypes时,获取的构造方法即为默认的构造方法。

public class ConstructorInstance {

public static void main(String[] args) throws Exception {

Class p = Person.class;

Constructor constructor1 = p.getConstructor();//获取默认的构造方法

Constructor constructor2 = p.getConstructor(String.class,int.class);//获取指定的构造方法

System.out.println(constructor1);

System.out.println(constructor2);

}

}

运行结果:

public com.eft.reflect.Person()

public com.eft.reflect.Person(java.lang.String,int)

复制代码

通过构造方法创建对象

Constructor对象中有一个方法newInstance(Object ... initargs),这里的initargs即为要传给构造方法的参数,如Person(String,int),通过其对应的Constructor实例,调用newInstance方法并传入相应的参数,即可通过Person(String,int)来创建类对象的实例对象。

测试代码如下:

public class ConstructorInstance {

public static void main(String[] args) throws Exception {

Class p = Person.class;

Constructor constructor = p.getConstructor(String.class,int.class);

Person person = (Person) constructor.newInstance("酸辣汤",18);

System.out.println(person);

}

}

运行结果:

Person{name='酸辣汤', age=18}

复制代码

如上通过反射创建对象,只是反射机制中的冰山一角,详细了解java反射知识,可以参考这篇 java反射全解

五、使用Unsafe

sun.misc.Unsafe中提供allocateInstance方法,仅通过Class对象就可以创建此类的实例对象,而且不需要调用其构造函数、初始化代码、JVM安全检查等。它抑制修饰符检测,也就是即使构造器是private修饰的也能通过此方法实例化,只需提类对象即可创建相应的对象。由于这种特性,allocateInstance在java.lang.invoke、Objenesis(提供绕过类构造器的对象生成方式)、Gson(反序列化时用到)中都有相应的应用。

直接看例子

package cn.eft.llj.unsafe;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class Demo9 {

static Unsafe unsafe;

static {

//获取Unsafe对象

try {

Field field = Unsafe.class.getDeclaredField("theUnsafe");

field.setAccessible(true);

unsafe = (Unsafe) field.get(null);

} catch (Exception e) {

e.printStackTrace();

}

}

static class C1 {

private String name;

private C1() {

System.out.println("C1 default constructor!");

}

private C1(String name) {

this.name = name;

System.out.println("C1 有参 constructor!");

}

public void test(){

System.out.println("执行了test方法");

}

}

public static void main(String[] args) throws InstantiationException {

C1 c= (C1) unsafe.allocateInstance(C1.class);

System.out.println(c);

c.test();

}

}

复制代码

输出结果:

cn.eft.llj.unsafe.Demo9$C1@6bc7c054

执行了test方法

复制代码

关于Unsafe的详细了解,可以参考这篇Java魔法类:Unsafe应用解析

结尾

如果还有其他创建对象的方式,欢迎在评论区留言~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值