java中创建对象的四种方式

1.new出一个对象

String s = new String(“abc”);

2.利用反射创建对象

利用反射的两种方式:

  1. 使用Class对象的newInstance()方法来创建Class对象对应类的实例。但是这种方法要求Class对象的对应类有默认构造器,而执行newInstance()方法时实际上利用默认构造器来创建该类的实例。
  2. 先使用Class对象获取指定的Constructor对象,在调用Construtor对象的newInstance()方法来创建该Class类对应类的实例,通过这种方式可以选择使用某个类的指定构造器来创建实例,有三步:
    (1)获取Class对象
    (2)利用Class对象的getConstrutor方法来获取指定的构造器
    (3)调用Construtor的newInstance方法来创建java对象。

3.利用clone创建对象

  1. Clone和Copy
  • Copy,copy后的cindyelf与tobby指向内存的同一个object。
Employee cindyelf=tobby;
  • Clone,得到tobby的精确拷贝,且两者相互不影响,这时会得到一个新的Employee对象,且与tobby有相同的属性值和方法。
Employee cindy=tobby.clone()
  1. Shallow Clone和Deep Clone
  • Shallow Clone
    Shallow Clone是某个对象实施Clone后简单执行域对域的copy,但是如果一个employee里的一个域hireDay不是基本类型变量,而是引用类型,经过Clone后,它与原始的域所指向的对象是同一个对象,这样的Clone会与原始类共享一个信息,显然是不利的
  • Deep Clone
    Deep Clone就是解决了Shallow Clone的问题,对那些特殊的域做特殊处理。重新定义Clone方法,对hireDay做特殊处理。
class Employee implements Cloneable  
  
{  
        public Object clone() throws CloneNotSupportedException  
        {  
         Employee cloned = (Employee) super.clone();  
      cloned.hireDay = (Date) hireDay.clone()  
      return cloned;  
        }  
} 
  1. Clone的保护机制
    在Object中Clone被声明为protected的,这样可以保证Clone的对象只能在本类里克隆。
  2. Clone()的使用方法
  3. 使用shallow clone 和 deep clone看对象的域是基本类型还是引用类型
  4. 调用clone方法时的对象所属类必须implements(继承)Cloneable接口,否则调用clone方法时抛出CloneNotSupportedException

4.利用反序列化创建对象

  1. 为什么要序列化
    关于java对象的生命周期,从创建到被堆的垃圾回不定期收回收,导致我们想再次访问访问不到,想要保存对象状态的话通过文件,数据库,序列化来完成。
    在远程访问方法调用RMI也会用到,在网络中传输对象,必须对对象序列化。
  2. 序列化
    设置三个属性
public class Person implements Serializable {  
int age;  
int height;
String name;
...
}
/** 
 * 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);  
out.close();  
} catch (IOException e) {  
e.printStackTrace();  
}  
} 

设置 序列化时需要实现Serializable,从javaAOP中我们可以看到这个接口为空接口,该接口没有声明任何方法
这里主要涉及到javaI/O流方面知识,主要用到FileOutPutString和ObjectOutPutString,FileOutPutString主要将字节输出到文件,ObjectOutPutString通过调用writeObject方法将对象变可以写出到流的数据,所以整个流程是这样的: ObjectOutputStream 将要序列化的对象转换为某种数据,然后通过 FileOutputStream 连接某磁盘文件,再对象转化的数据转化为字节数据再将其写出到磁盘文件。
3. 反序列化

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();  
}  
}  
}  

我们存储的目的主要是为了再恢复使用,主要用到的流是FileInputstream和ObjectInputstream正好与存储时用到的流相对应。另外从结果顺序我们可以看到反序列化后得到对象的顺序与序列化时的顺序一致。
5. 总结

  • 进行对象序列化主要目的是为了保存对象的状态(成员变量)。
  • 进行序列化主要用到的流是FileOutputStream和ObjectOutputStream。FileOutputStream主要用于连接磁盘文件,并把字节写出到该磁盘文件;ObjectOutputStream主要用于将对象写出为可转化为字节的数据。
  • 要将某类的对象序列化,则该类必须实现Serializable接口,该接口仅是一个标志,告诉JVM该类的对象可以被序列化。如果某类未实现Serializable接口,则该类对象不能实现序列化。
  • 保存状态的目的就是为了在未来的某个时候再恢复保存的内容,这可以通过反序列化来实现。对象的反序列化过程与序列化正好相反,主要用到的两个流是FileInputstream和ObjectInputStream。
  • 反序列化后得到的对象的顺序与保存时的顺序一致
    补充:
    要保存的成员变量要么是基本类型的要么是String类型的。但有时成员变量有可能是引用类型的,这是的情况会复杂一点。那就是当要对某对象进行序列化时,该对象中的引用变量所引用的对象也会被同时序列化,并且该对象中如果也有引用变量的话则该对象也将被序列化。总结说来就是在序列化的时候,对象中的所有引用变量所对应的对象将会被同时序列化。这意味着,引用变量类型也都要实现Serializable接口。当然其他对象的序列化都是自动进行的。所以我们只要保证里面的引用类型是都实现Serializable接口就行了,如果没有的话,会在编译时抛出异常。如果序列化的对象中包含没有实现Serializable的成员变量的话,这时可以使用transient关键字,让序列化的时候跳过该成员变量。使用关键字transient可以让你在序列化的时候自动跳过transient所修饰的成员变量,在反序列化时这些变量会恢复到默认值。
  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏日一凉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值