Reputation: 1225
I'm writing a generic encoder/decoder and running into an issue with an extended generic. The idea is that I want to have an abstract Encodeable class that has a "virtual" static method decode which takes a Byte[] and constructs the object, similar to Serializable. (I know this can't really be done in java.) Each class that extends Encodeable will overwrite the encode/decode methods. I then want to use these subclasses of Encodeable generically. Here's an attempt to show what I mean:
public class Encodeable{
// I'd like to write
// static abstract Encodeable decode(Byte[]);
// similar to
// virtual Encodeable decode(Byte[]) = 0;
// in C++, but that seems to be illegal in java
static Encodeable decode(Byte[] buf){return null};
}
public class EncodeableFoo extends Encodeable{
static EncodeableFoo decode(Byte[] buf){
// do actual decoding logic here
}
}
public class Bar<T extends Encodeable>{
public void messageReceived(MessageEvent e){
Byte[] buf = e.getMessage();
T messageObj = T.decode(buf);
// do something with T
}
}
As is, I get an error message like
error: incompatible types
T messageObj = T.decode(objBuf);
^
required: T
found: Encodeable
where T is a type-variable:
T extends Encodeable declared in class EdgeClientHandler
at compile time. But if I change the decode line to
T messageObj = (T) T.decode(objBuf);
it works just fine. Can someone explain this black magic to me? Or, more importantly, give me a better way of writing my generic Bar class such that it knows T has a static method decode (and a non-static method encode)?
Upvotes: 0
Views: 167
Reputation: 359826
First, static methods in Java cannot be abstract.
Second, you need to declare the method to be generic if you want the compiler to understand that you're returning a T
, and not just an Encodeable
. I recommend staying away from static
entirely here. The basic idea:
public interface Decoder<T> {
T decode(Byte[] buf);
}
public class FooDecoder implements Decoder<Foo> {
Foo decode(Byte[] buf){
// do actual decoding logic here
}
}
public class Bar<T extends Encodeable> {
private Decoder<T> decoder; // you'll have to figure out where to get this
public void messageReceived(MessageEvent e){
Byte[] buf = e.getMessage();
T messageObj = decoder.decode(buf);
// do something with T
}
}
Your original setup seems to mix encodable types and things which know how to decode such types from a byte[]
, so I've renamed and fiddled a bit.
Side question: why Byte[]
s instead of byte[]
s?
Upvotes: 6
Reputation: 328608
Your design looks a little messy to me. I would not use a static method and do something like this instead:
public interface Decoder<T extends Encodable> {
T decode(Byte[] buf);
}
public class Bar<T extends Encodable> {
private final Decoder<T> decoder;
public Bar(Decoder<T> decoder) {
this.decoder = decoder;
}
public void messageReceived(MessageEvent e) {
Byte[] buf = e.getMessage();
T messageObj = decoder.decode(buf);
// do something with T
}
}
Upvotes: 3