Java创建对象的四种方法

有4种显式地创建对象的方式:

1.用new语句创建对象,这是最常用的创建对象的方式。

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

3.调用对象的clone()方法。

4.运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法.

下面演示了用前面3种方式创建对象的过程。

public class Customer implements Cloneable{

private String name;

private int age;

public Customer(){

  this("unknown",0);

  System.out.println("call default constructor");

}

public Customer(String name,int age){

  this.name=name;

  this.age=age;

  System.out.println("call second constructor");

}

public Object clone()throws CloneNotSupportedException{

return super.clone();

}

public boolean equals(Object o){

  if(this==o)return true;

  if(! (o instanceof Customer)) return false;

  final Customer other=(Customer)o;

  if(this.name.equals(other.name) && this.age==other.age)

     return true;

  else

     return false;

}

public String toString(){

return "name="+name+",age="+age;

}

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

//运用反射手段创建Customer对象

Class objClass=Class.forName("Customer");

Customer c1=(Customer)objClass.newInstance(); //会调用Customer类的默认构造方法

System.out.println("c1: "+c1); //打印name=unknown,age=0



//用new语句创建Customer对象

Customer c2=new Customer("Tom",20);

System.out.println("c2: "+c2); //打印name=tom,age=20



//运用克隆手段创建Customer对象

Customer c3=(Customer)c2.clone(); //不会调用Customer类的构造方法

System.out.println("c2==c3 : "+(c2==c3)); //打印false

System.out.println("c2.equals(c3) : "+c2.equals(c3)); //打印true

System.out.println("c3: "+c3); //打印name=tom,age=20

}

}



以上程序的打印结果如下:

call second constructor

call default constructor

c1: name=unknown,age=0

call second constructor

c2: name=Tom,age=20

c2==c3 : false

c2.equals(c3) : true

c3: name=Tom,age=20

从以上打印结果看出,用new语句或Class对象的newInstance()方法创建Customer对象时,都会执行Customer类的构造方法,而用对象的clone()方法创建Customer对象时,不会执行Customer类的构造方法。(区别)
除了以上4种显式地创建对象的方式以外,在程序中还可以隐含地创建对象,包括以下几种情况:

1.对于java命令中的每个命令行参数,Java虚拟机都会创建相应的String对象,并把它们组织到一个String数组中,再把该数组作为参数传给程序入口main(String args[])方法。

2.程序代码中的String类型的直接数对应一个String对象,例如:

String s1="Hello";

String s2="Hello"; //s2和s1引用同一个String对象
String s3=new String("Hello");

System.out.println(s1==s2); //打印true

System.out.println(s1==s3); //打印false

执行完以上程序,内存中实际上只有两个String对象,一个是直接数,由Java虚拟机隐含地创建,还有一个通过new语句显式地创建。

3.字符串操作符“+”的运算结果为一个新的String对象。例如:

String s1="H";

String s2=" ello";

String s3=s1+s2; //s3引用一个新的String对象
System.out.println(s3=="Hello"); //打印false

System.out.println(s3.equals("Hello")); //打印true

4.当Java虚拟机加载一个类时,会隐含地创建描述这个类的Class实例


Class类的forName方法public static Class<?> forName(String className)
throws ClassNotFoundException
返回与带有给定字符串名的类或接口相关联的 Class 对象。调用此方法等效于:
  Class.forName(className, true, currentLoader)

其中 currentLoader 表示此类的定义类加载器。
例如,以下代码片段返回 java.lang.Thread 类的运行时 Class 描述符。

   Class t = Class.forName("java.lang.Thread")

调用 forName("X") 将导致名为 X 的类被初始化。



参数:
className - 所需类的完全限定名。
返回:
具有指定名的类的 Class 对象。
抛出:
LinkageError - 如果链接失败
ExceptionInInitializerError - 如果此方法所激发的初始化失败
ClassNotFoundException - 如果找不到该类
Object类的clone()方法

protected Object clone()
throws CloneNotSupportedException
创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。一般来说,对于任何对象 x,如果表达式:
x.clone() != x
是正确的,则表达式:
x.clone().getClass() == x.getClass()
将为 true,但这些不是绝对条件。一般情况下是:
x.clone().equals(x)
将为 true,但这不是绝对条件。
按照惯例,返回的对象应该通过调用 super.clone 获得。如果一个类及其所有的超类(Object 除外)都遵守此约定,则 x.clone().getClass() == x.getClass()。

按照惯例,此方法返回的对象应该独立于该对象(正被克隆的对象)。要获得此独立性,在 super.clone 返回对象之前,有必要对该对象的一个或多个字段进行修改。这通常意味着要复制包含正在被克隆对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。如果一个类只包含基本字段或对不变对象的引用,那么通常不需要修改 super.clone 返回的对象中的字段。

Object 类的 clone 方法执行特定的克隆操作。首先,如果此对象的类不能实现接口 Cloneable,则会抛出 CloneNotSupportedException。注意:所有的数组都被视为实现接口 Cloneable。否则,此方法会创建此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我克隆。所以,此方法执行的是该对象的“浅表复制”,而不“深层复制”操作。

Object 类本身不实现接口 Cloneable,所以在类为 Object 的对象上调用 clone 方法将会导致在运行时抛出异常。



返回:
此实例的一个克隆。
抛出:
CloneNotSupportedException - 如果对象的类不支持 Cloneable 接口,则重写 clone 方法的子类也会抛出此异常,以指示无法克隆某个实例。


[转载]http://blog.csdn.net/yakihappy/archive/2009/03/11/3979348.aspx

例子2:
package org.whb.test.demo724;

import java.io.*;
import java.util.Date;

/**
* 对象的序列化和反序列化测试类.
*1、序列化是干什么的?
简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。虽然你可以用你自 己的各种各样的方法来保存object states,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。

*2、什么情况下需要序列化
a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
*
*3、相关注意事项
a)序列化时,只对对象的状态进行保存,而不管对象的方法;
b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
d)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:
1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输 等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分 配,而且,也是没有必要这样实现。
*/

public class ObjectSaver {
public static void main(String[] args) throws Exception {
ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream("D:/objectFile.swf"));
//序列化对象
Customer customer = new Customer("haobo", 24);
out.writeObject("你好!");
out.writeObject(new Date());
out.writeObject(customer);
out.writeInt(123); //写入基本类型数据
out.close();
//反序列化对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:/objectFile.swf"));
System.out.println("obj1=" + (String) in.readObject());
System.out.println("obj2=" + (Date) in.readObject());
Customer obj3 = (Customer) in.readObject();
System.out.println("obj3=" + obj3);
int obj4 = in.readInt();
System.out.println("obj4=" + obj4);
in.close();
}
}
class Customer implements Serializable {
/**
*
*/
private static final long serialVersionUID = -88175599799432325L;
private String name;
private int age;
public Customer(String name, int age) {
  this.name = name;
  this.age = age;
}
  public String toString() {
   return "name=" + name + ", age=" + age;
  }
}
/*
* obj1=你好!
obj2=Sat Jul 24 21:18:19 CST 2010
obj3=name=haobo, age=24
obj4=123
*/

 

你可能感兴趣的:(java,thread,数据结构,虚拟机,socket)