简体   繁体   中英

How to call a method returning generic type correctly (Java)?

I have a generic method which has generic type to return. I would like to call it properly in order to return compilation error in case the returning type, I use it for, does not comply the boundaries this way avoiding run-time errors (vs compilation) and use all the power of Java generic types.

public <T extends IDeserializable> T restoreObject(byte[] objectArray) {

    T object = T.getDeserialized(objectArray);
    
    return object;
}

However, calling it this way

File ret = restoreObject(new byte[] {1,2,3});

would not produce compilation error and therefore the error will be generated at runtime only. The File type does not implement IDeserializable, however java does not generate compilation error.

public interface IDeserializable {
        public static <T> T getDeserialized(byte[] data) {
            return null;
        }
}

There are several problems here:

  • Calling static methods on type parameters does not work the way you may think it does ( here is a question about that).
  • In any case, getDeserialized is an instance method, not a static method, so you can't do T.getDeserialized(objectArray) .
  • The compiler cannot infer T just like that. @luk2302 has corrected me - T will be inferred as the type of whatever you're assigning the result to.

You need to give restoreObject an argument of type T so that the compiler can infer T and so that you can call the getDeserialized method:

public <T extends IDeserializable> T restoreObject(byte[] objectArray, T t) {
    return t.getDeserialized(objectArray);
}

However, I suspect you meant getDeserialized to be a static method. Unfortunately, you cannot do that, because static methods don't get overriden. You can, however, make restoreObject take a Function parameter:

public <T extends IDeserializable> T restoreObject(byte[] objectArray, Function<byte[], T> deserialize) {
    return deserialize.apply(objectArray);
}

Then you can use a lambda or method reference for the deserialize argument.


You can also use Serializable , but @daniu has pointed out that Serializable will be removed some time in the future and is not a good idea. There are tons of libraries out there already so you don't have to handle the serialization/deserialization yourself. Here are some alternatives for serialization in Java. Java also has its own XML API if you don't want to use outside libraries.

This gets obvious really fast, if you could imagine a theoretical type Weirdo that could do:

 class Weird extends File implements IDeserializable

And then:

static <T> T getDeserialized(byte[] data) {
        return new Weirdo();
}

Or even simpler (since the cast to a type parameter can't be enforced):

 static <T> T getDeserialized(byte[] data) {
      return (T) "";
 }

You can see that the problem is in your getDeserialized to begin with and callers have to trust you. But if you think why static methods exist in interfaces (their main purpose is to return an instance of the interface), then you are abusing these methods. What is the point in making it static if no one can override it? You might want to rethink what you are trying to do.

But anyway, if you replace that with a class - you will get a compile time error (I will let you figure out why, though):

public static class IDeserializable {

    static <T> T getDeserialized(byte[] data) {
        return ...;
    }
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM