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兼容的方式序列化。