如 User user=new User();html
執行這條語句,jvm作了什麼?java
首先在方法區的常量池中查看是否有new 後面參數(也就是類名)的符號引用,並檢查是否有類的加載信息也就是是否被加載解析和初始化過。若是已經加載過了就不在加載,不然執行類的加載全過程android
加載完類後,大體作了以下三件事: a、給實例分配內存 b、調用構造函數,初始化成員字段 c、user對象指向分配的內存空間 注意:new操做不是原子操做,b和c的順序可能會調換數據庫
當咱們調用一個對象的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給你提供一種應該比你本身好的保存對象狀態的機制,那就是序列化。一句話歸納:序列化是指將對象的狀態信息轉換爲能夠存儲或傳輸的形式的過程。jvm
java中要序列化的類必要實現Serializable接口ide
a)當你想把的內存中的對象狀態保存到一個文件中或者數據庫中時候;函數
b)當你想用套接字在網絡上傳送對象的時候;post
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;
}
}
複製代碼
二、序列化與反序列化
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後,就能夠經過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 +
'}';
}
}
複製代碼
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
是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反射全解
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應用解析
若是還有其餘建立對象的方式,歡迎在評論區留言~