java 创建对象有多种方式 :
方式1> new
方式2> 使用 Object 的 clone 方法
<1> 实现 clone类 首先实现 Cloneble接口,Cloneable接口 实质上是一个标识接口 类似于 Serializable 接口,没有任何方法
<2> 重写 Object 中的 clone方法
<3> 在 clone方法中调用 super.clone(),无论 clone类 的继承结构是什么,super.clone() 都会直接或间接调用 Object类 中的 clone方法
public class Obj implements Cloneable {
private int a = 0;
public Obj() {
System.out.println("construct Obj");
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public void changeA() {
this.a = 1;
}
// 将 protected 作用域改成 public
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) {
try {
Obj a = new Obj();
Obj b = (Obj) a.clone();
b.changeA();
System.out.println(a.getA());
System.out.println(b.getA());
} catch (Exception e) {
e.printStackTrace();
}
}
// 打印
// construct Obj # 只打一个一次,说明没有进行两次 new 操作
// 0 # 两次打印的结果不同,说明 a b 指向的不是同一个对象
// 1
}
方式3> 利用反射
public class Person {
private String name = "Jack";
public Person() {
System.out.println("construct Person");
}
@Override
public String toString() {
return name;
}
public static void main(String[] args) {
Class clazz;
try {
clazz = Class.forName("com.chenshun.test.object.Person");
Person p = (Person) clazz.newInstance();
System.out.println(p);
} catch (Exception e) {
e.printStackTrace();
}
}
}
方式4> 通过反序列化来创建对象
public class People implements Serializable {
private static final long serialVersionUID = 8561166444504657722L;
private String name;
public People() {
this.name = "6点A君";
System.out.println("construct people");
}
@Override
public String toString() {
return this.name;
}
public static void main(String[] args) {
People p = new People();
System.out.println(p);
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
FileOutputStream fos = new FileOutputStream("test.out");
oos = new ObjectOutputStream(fos);
oos.writeObject(p);
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
People p1;
try {
FileInputStream fis = new FileInputStream("test.out");
ois = new ObjectInputStream(fis);
p1 = (People) ois.readObject();
System.out.println(p1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java 中 Class.forName() 和 ClassLoader 都可用来对类进行加载
1> Class.forName() 用于将类的 .class文件 加载到 JVM,还可以对类进行解释,执行类中的 static块。另外,Class.forName(name, initialize, loader) 带参函数也可控制是否加载 static块。并且只有调用 newInstance()方法采用调用构造函数,创建类的对象
2> ClassLoader 只干一件事情,就是将 .class文件加载到 JVM 中,不会执行 static 中的内容,只有在 newInstance 才会去执行 static块
public class Point {
static {
System.out.println("静态代码块执行:loading point");
}
}
`
private static void testClassloader(String wholeNamePoint) {
Class<?> point;
ClassLoader loader = ClassLoader.getSystemClassLoader();
try {
point = loader.loadClass(wholeNamePoint);
// demo = ClassloaderAndForNameTest.class.getClassLoader().loadClass(wholeNamePoint); // 这个也是可以的
System.out.println("point " + point.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static void testForName(String wholeNamePoint) {
try {
Class point = Class.forName(wholeNamePoint);
System.out.println("point " + point.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String wholeNamePoint = "com.chenshun.test.object.Point";
System.out.println("下面是测试Classloader的效果");
testClassloader(wholeNamePoint);
System.out.println("----------------------------------");
System.out.println("下面是测试Class.forName的效果");
testForName(wholeNamePoint);
}
# 打印
下面是测试Classloader的效果
point com.chenshun.test.object.Point
----------------------------------
下面是测试Class.forName的效果
静态代码块执行:loading point
point com.chenshun.test.object.Point
这个案例需要注意的是如果 main 方法在 Point 中将会先打印 "静态代码块执行:loading point" 然后再执行其它操作,这是由于运行 main 方法前会先运行静态代码块 有 Java 成员运行顺序决定