Java method with generic return Type

北战南征 提交于 2019-12-13 03:41:25

问题


Is there a way in Java to return different types with one declaration of a method?

public Object loadSerialized(String path) {
    Object tmpObject;

    try {
        FileInputStream fis = new FileInputStream(path);
        ObjectInputStream ois = new ObjectInputStream(fis);
        tmpObject = (Object) ois.readObject();

        ois.close();
        fis.close();

        return tmpObject;
    } catch (FileNotFoundException e) {
        return null;
    } catch (Exception e) {
    }
}

I want this method to return an Object and I cloud cast it to the right type at the function call. That was what i thought but it doesn't work like this. Do I need some kind of generic return Type to do this? What would be the best way to solve this problem?


回答1:


To do this safely, you need to pass in the desired type as a Class object:

public <T> T loadSerialized(String path, Class<T> targetType) {
    try (ObjectInputStream ois = new ObjectInputStream(
        new BufferedInputStream(
            new FileInputStream(path)))) {

        Object tmpObject = (Object) ois.readObject();
        return targetType.cast(tmpObject);
    } catch (FileNotFoundException e) {
        return null;
    } catch (IOException | ClassNotFoundException e) {
        throw new RuntimeException(e);
    }
}

While you could write return (T) tmpObject;, that will generate a compiler warning, because it is not safe: since the compiler only knows that T might be some descendant of Object (or Object itself), the compiler generates (Object), which is the same as doing nothing at all. The code blindly assumes the returned object is of type T, but if it isn’t, when the program tries to call a method defined in T, you’ll get a surprise exception. It’s better to know as soon as you have deserialized the object whether it was the type you expected.

A similar thing happens if you do an unsafe cast on, say, a List:

List<Integer> numbers = Arrays.asList(1, 2, 3);

List<?> list = numbers;
List<String> names = (List<String>) list;  // Unsafe!

String name = names.get(0);    // ClassCastException - not really a String!



回答2:


You can use a generic in your return type. It might look something like this. In simple terms, the compiler chooses the best type for T depending on how the method has been called. The casting then happens inside the method, not outside.

Note that I've used the try-with-resources syntax, to avoid messing round with closing streams.

public <T> T loadSerialized(String path) throws IOException, ClassNotFoundException {
    try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path))) {
        return (T) ois.readObject();
    }
}


来源:https://stackoverflow.com/questions/47931063/java-method-with-generic-return-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!