Java 是否可以在泛型函数中测试类型?

Java 是否可以在泛型函数中测试类型?,java,generics,Java,Generics,我想创建一个泛型函数,将字节数组反序列化为调用者指定的类型。 我觉得调用这样一个函数的一种真正直观的方式应该是: byte[255] myData = [...] String myUnserializedString = new Packet<String>(myData).unpack(); byte[4] myInt = [...] int myUnserializedInt = new Packet<Integer>(myInt).unpack(); 字节[2

我想创建一个泛型函数,将字节数组反序列化为调用者指定的类型。 我觉得调用这样一个函数的一种真正直观的方式应该是:

byte[255] myData = [...]
String myUnserializedString = new Packet<String>(myData).unpack();

byte[4] myInt = [...]
int myUnserializedInt = new Packet<Integer>(myInt).unpack();
字节[255]myData=[…] 字符串myUnserializedString=新数据包(myData).unpack(); 字节[4]myInt=[…] int myUnserializedInt=新数据包(myInt).unpack(); 作为一个用户,这是我希望提供的一种界面。问题是(显然)每种类型都必须以不同的方式进行非序列化。这意味着unpack()方法必须执行某种自反测试,以选择正确的方式来解释原始字节

在为这样一个类编写了一个原型之后,我开始觉得泛型可能不是这种设计的合适工具

是吗?为什么不是

class Packet<T> {
   private byte[] bytes;
   // consructor here
   public T unpack() {
       (T) readObject(bytes);
   }
}
类数据包{
专用字节[]字节;
//这里的建筑工人
公共T打开包装(){
(T) readObject(字节);
}
}
readObject(…)
可以依赖于
ObjectInputStream

为什么不能

class Packet<T> {
   private byte[] bytes;
   // consructor here
   public T unpack() {
       (T) readObject(bytes);
   }
}
类数据包{
专用字节[]字节;
//这里的建筑工人
公共T打开包装(){
(T) readObject(字节);
}
}

readObject(…)
可以依赖于
ObjectInputStream

泛型在这里不提供任何真正的类型安全性,但它可以提供一些强制转换便利。但是,显而易见的方法是让unpack方法完成所有工作:

 public <T> T unpack(Class<T> klass) {
      return klass.cast(unpackedData);
 }

即使您可以扭曲泛型,以您想要的方式完成它(我认为您可以使用不安全的强制转换,这就是Class.cast所做的一切),这也是更标准的idom,可以避免您自己进行不安全的强制转换。无论哪种方式,您都是说客户机知道类型,因为它在您的示例中设置了泛型参数。

泛型在这里没有提供任何真正的类型安全性,但它可以提供一些转换便利。但是,显而易见的方法是让unpack方法完成所有工作:

 public <T> T unpack(Class<T> klass) {
      return klass.cast(unpackedData);
 }

即使您可以扭曲泛型,以您想要的方式完成它(我认为您可以使用不安全的强制转换,这就是Class.cast所做的一切),这也是更标准的idom,可以避免您自己进行不安全的强制转换。无论哪种方式,您都是说客户机知道类型,因为它在您的示例中设置了泛型参数。

如果必须以不同的方式处理它们,则数据包不是真正的泛型

这没有什么问题

class StringPacket extends Packet {
 // ...
}


如果必须以不同的方式处理它们,那么数据包就不是真正通用的

这没有什么问题

class StringPacket extends Packet {
 // ...
}


您可以将数据包定义为一个接口,并为每种类型的数据提供一个实现

public interface Packet<T> {  
   T unpack(byte[] data);  
}  

public final class StringPacket implements Packet<String> {  
     public String unpack(byte[] data) {  
         // Implementation...  
     }  
}  

 // Similar classes for other types...
公共接口数据包{
T解包(字节[]数据);
}  
公共最终类StringPacket实现数据包{
公共字符串解包(字节[]数据){
//实施。。。
}  
}  
//其他类型的类似类。。。

您可以将数据包定义为一个接口,并为每种类型的数据提供一个实现

public interface Packet<T> {  
   T unpack(byte[] data);  
}  

public final class StringPacket implements Packet<String> {  
     public String unpack(byte[] data) {  
         // Implementation...  
     }  
}  

 // Similar classes for other types...
公共接口数据包{
T解包(字节[]数据);
}  
公共最终类StringPacket实现数据包{
公共字符串解包(字节[]数据){
//实施。。。
}  
}  
//其他类型的类似类。。。

能否显示您尝试的代码?可能会修复它。您能显示您尝试的代码吗?也许可以修复它。好吧,如果用户有错误的期望(作为.class或泛型),将抛出一个ClassCastException。@Bozho,当然,这就是为什么我说你没有得到任何真正的类型安全性,只是铸造方便性。好吧,如果用户有错误的期望(作为.class或泛型),一个ClassCastException将被抛出。@Bozho,当然,这就是为什么我说你没有得到任何真正的类型安全性,只是方便地进行了转换。+1。不同的数据类型需要不同的解包代码,因此子类化是一种自然的方式。如果使用
ObjectInputStream
,则根本不需要这样做-流中已经有了此功能。我将使用此解决方案,它似乎是实现此功能的“正确”方式。Yishai的解决方案更接近于我所寻找的那种接口,但扩展性也必须考虑在内:子类化将允许用户定义自己的数据包类型。谢谢大家的意见+1.不同的数据类型需要不同的解包代码,因此子类化是一种自然的方式。如果使用
ObjectInputStream
,则根本不需要这样做-流中已经有了此功能。我将使用此解决方案,它似乎是实现此功能的“正确”方式。Yishai的解决方案更接近于我所寻找的那种接口,但扩展性也必须考虑在内:子类化将允许用户定义自己的数据包类型。谢谢大家的意见!这是个好主意,但我将使用自制的序列化协议,因此对象不会以readObject兼容的方式序列化。这是个好主意,但我将使用自制的序列化协议,因此对象不会以readObject兼容的方式序列化。