2012-12-28 122 views
0

我想創建一個新的類,我不完全確定類類型的東西。這可能與我的代碼可以更好地解釋說:Java - 實例化錯誤?

private static Class[] Packets = new Class[] 
      { 
       KeepAlivePacket.class, // 0x00 
       LoginRequestPacket.class, // 0x01 
       HandshakePacket.class, // 0x02 
        } 
....... 

class HandshakePacket extends TCPPacket 
{ 
    public HandshakePacket() 
    { 

    } 
    byte protocolVersion; 
    String username; 
    String host; 
    int port; 
    @Override 
    public void writePacketData(DataOutputStream os) throws IOException { 
     os.write(id); 
     os.writeByte(protocolVersion); 
     writeString(os, username); 
     writeString(os, host); 
     os.writeInt(port); 
    } 
    @Override 
    public void readPacketData(DataInputStream is) throws IOException { 
     protocolVersion = is.readByte(); 
     username = readString(is,16); 
     host = readString(is,16); 
     port = is.readInt(); 
    } 
    @Override 
    public void setId(byte id) 
    { 
     this.id = id; 
    } 
} 

....... 
    public static TCPPacket getNewPacket(int i) 
    { 
    try 
    { 
     Class var1 = (Class)Packets[i]; 
     return var1 == null ? null : (TCPPacket)var1.newInstance(); <-- error on this line 
    } 
    catch (Exception var2) 
    { 
     var2.printStackTrace(); 
     System.out.println("Skipping packet with id " + i); 
     return null; 
    } 
} 

和任何人想知道什麼是TCPPacket:

package vc.voidwhisperer.proxy.packet; 

import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.IOException; 

public class TCPPacket { 
public TCPPacket() 
{ 

} 
public byte id = 0; 
public void writePacketData(DataOutputStream os) throws IOException 
{ 

} 
public void readPacketData(DataInputStream is) throws IOException 
{ 

} 
public void setId(byte id) 
{ 

} 
} 

正如你可以看到我試圖instaniate一個新的對象,我不能完全確定類的類型。然而,它正在吐出這個例外:

java.lang.InstantiationException: vc.voidwhisperer.proxy.packet.Packet$HandshakePacket 
at java.lang.Class.newInstance0(Unknown Source) 
at java.lang.Class.newInstance(Unknown Source) 
at vc.voidwhisperer.proxy.packet.Packet.getNewPacket(Packet.java:2509) 
at vc.voidwhisperer.proxy.UserConnection.run(UserConnection.java:52) 
+1

InstantiationException包裝通常在其後打印的真正異常。你能提供實際的例外嗎?它還表示發生異常時調用Packet.HandshakePacket的構造函數。你能提供導致異常的類的源代碼並告訴使用它到底發生了哪一行嗎? –

+0

順便說一句'setId'沒有設置'id'字段嗎? –

+1

將'HandshakePacket'的相關代碼包含到您的問題中,包括其構造函數。我會推薦複製/粘貼代碼(而不是手動輸入問題)。 – Perception

回答

2

反射是這樣的矯枉過正。

只是做

switch (i) { 
    case 0: return new KeepAlivePacket(); 
    case 1: return new LoginRequestPacket(); 
    case 2: return new HandshakePacket(); 
    default: throw new IllegalArgumentException(); 
} 

和理想的替代i用枚舉。

這將爲您帶來靜態類型和簽名檢查的優點,使您的代碼更易於維護,並避免所有反射式guff掩蓋異常。

+0

大約有200個數據包。這不是矯枉過正:/ – VoidWhisperer

+1

呃,交易內存代碼是一個長期爭論的問題。如果您要從文件讀入配置,那麼您可以爲使用基於數據的調度而不是基於代碼的調度提供更好的參數。 –

+0

@VoidWhisperer,開關方法贏得大手工編碼陣列。由於它只是編譯爲單個邊界檢查和「jsr」指令,所以一個密集的int開關每個開銷的開銷爲零。每個返回無效構造函數調用結果的case語句對於'new'指令需要3個字節,對於返回需要1個字節。設置一個200元素數組的靜態初始化器的大小要大得多,因爲每個aastore需要3個其他指令來設置堆棧:'a = new Class [] {x,y,z}'實際上會解析爲'a =新班[3]; a [0] = x; a [1] = y; a [2] = z;'。 –

2

您試圖從靜態方法內實例化非靜態內部類。創建一個新的對象需要一個周圍的數據包對象,因爲它是父對象,並且您沒有提供它。

所以,要麼使HandshakePacket一個靜態內部類,使getNewPacket非靜態方法,或創建一個新的包對象的父用於新HandshakePacket對象。

+0

我使它成爲getNewPacket非靜態,它仍然存在錯誤。 – VoidWhisperer

+0

@VoidWhisperer,如果你打算反射地調用一個內部類的構造函數,你需要將外部實例作爲第一個參數傳遞,因爲'outerInstance.new NonStaticInnerClass()'desugars爲'new OuterClass $ NonStaticInnerClass(outerInstance)'並且'new NonStaticInnerClass()'實際上是'this.new NonStaticInnerClass()',所以解析成'new OuterClass $ NonStaticInnerClass(this)'。 'Class.newInstance()'不起作用。您需要使用['java.lang.reflect.Constructor.newInstance'](http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Constructor.html#newInstance%28java。 lang.Object ... 29%)。 –

+0

你唯一的改變是讓'getNewPacket'非靜態? 'Packet'是'HandshakePacket'的包含類嗎?從你的代碼中不清楚它是什麼 - 我只是認爲是這樣。 –