不用構造器也能創建對象

import java.io.ByteArrayInputStream;   
import java.io.ByteArrayOutputStream;   
import java.io.ObjectInputStream;   
import java.io.Serializable;   
public class TestClass implements Serializable{   
    private static final long serialVersionUID = 0L;   
    public TestClass() throws Exception {   
        throw new Exception("哎呀媽呀,異常啦!!!!");   
    }   
    public static void main(String[] args) throws Exception {   
        byte[] head = { -84, -19, 0, 5, 115, 114, 0 };   
        byte[] ass = { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 120, 112 };   
        String name = TestClass.class.getName();   
        ByteArrayOutputStream baos = new ByteArrayOutputStream();   
        baos.write(head);   
        baos.write(name.length());   
        baos.write(name.getBytes());   
        baos.write(ass);   
        baos.flush();   
        baos.close();   
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));   
        TestClass o = (TestClass) ois.readObject();   
        ois.close();   
        System.out.println("創建對象: " + o);   
    }   
}   
看到這裏先彆着急執行,先看看.你覺得能夠正常運行嗎? 結果是什麼?
-----------------------------------------------------------------------------------
運行結果:  創建對象: TestClass@743399
CSDN某帖子 寫道
對象創建的幾種方法:
1.使用new關鍵字 2.使用clone方法 3.反射機制 4.反序列化
其中1,3都會明確的顯式的調用構造函數
2是在內存上對已有對象的影印 所以不會調用構造函數
4是從文件中還原類的對象 也不會調用構造函數

上述代碼就是反序列化的結果
RednaxelaFX 寫道
嗯順帶推薦Effective Java, Second Edition的第74條
引用
Normally, objects are created using constructors;
serialization is an extralinguistic mechanism for creating objects. Whether
you accept the default behavior or override it, deserialization is a “hidden constructor”
with all of the same issues as other constructors.

大體的意思是反序列化有一定的風險.破壞了封裝.相當於一個隱藏的構造器.
RednaxelaFX 寫道
1、Java的實例構造器只負責初始化,不負責創建對象;Java虛擬機的字節碼指令的設計也反映了這一點,有一個new指令專門用於創建對象實例,而調用實例構造器則使用invokespecial指令。
2、“this”是作爲實例構造器的第一個實際參數傳入的。

Java反序列化實際上是調用了基類的構造方法.
ObjectStreamClass中調用ReflectionFactory.newConstructorForSerialization(cl, cons);
Objectstreamclass代碼 複製代碼 收藏代碼
  1. cons = reflFactory.newConstructorForSerialization(cl, cons);  

根據cl參數(TestClass類的Class對象)和cons參數(基類Object的構造器)創建了一個新的構造器
打印生成的構造器對象,輸出信息爲public java.lang.Object(),表面生成的構造器是TestClass父類Object的無參構造器.
但是調用newInstance()的結果卻產生了TestClass類的對象.(おかしい......)

ReflectionFactory.newConstructorForSerialization()例子
Java代碼 複製代碼 收藏代碼
  1. Constructor superCons = TestClass.class.getSuperclass().getConstructor();   
  2. System.out.println(superCons);   
  3. ReflectionFactory reflFactory = ReflectionFactory.getReflectionFactory();   
  4. Constructor c = reflFactory.newConstructorForSerialization(TestClass.class,superCons);   
  5. System.out.println(c.newInstance());  
        Constructor superCons = TestClass.class.getSuperclass().getConstructor();
        System.out.println(superCons);
        ReflectionFactory reflFactory = ReflectionFactory.getReflectionFactory();
        Constructor c = reflFactory.newConstructorForSerialization(TestClass.class,superCons);
        System.out.println(c.newInstance());

運行結果代碼 複製代碼 收藏代碼
  1. public java.lang.Object()   
  2. TestClass@fd13b5  

通過基類的方法調用生成了子類.繞開了TestClass類的構造方法.生成了看似不可能存在的TestClass對象

-----------------------------------------------------------------------------------
感謝FX,之前一篇關於構造器的詳細論述.傳送門http://rednaxelafx.iteye.com/blog/652719
FX寫的關於本篇的更詳細講解在這裏,傳送門http://rednaxelafx.iteye.com/blog/850082

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章