问题
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