我希望通过调用此方法来获取序列化对象:
ArrayList<String> myArrayList = (ArrayList<String>) getSerializedObject(ArrayList.class, "arraylist.ser");
如果指定的文件(arraylist.ser)不存在,或者与我传入的类不匹配,我想返回该类的新实例。
private Object getSerializedObject(Class<?> c, String filename) {
Object serObject = null;
try {
if (new File(filename).exists()) {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
Object tempObj = in.readObject();
if (tempObj.getClass().equals(c)) {
System.out.println("Loading "+filename);
serObject = tempObj;
}
in.close();
}
}
catch (FileNotFoundException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
catch (ClassNotFoundException e) { e.printStackTrace(); }
if (serObject != null) {
return serObject;
}
else {
// return new instance of Class c here
}
}
答案 0 :(得分:2)
使用反射可以创建新的类实例。我会指向您的包,但您已经在使用Class
类。
当然,如果默认的构造函数不存在,您可能必须以某种方式选择合适的构造函数。
答案 1 :(得分:2)
如果您已经知道该类,并假设所有类具有相同的构造函数签名,那么您可以使用反射来完成它。
以下是默认的无参数构造函数
Class<?>[] args = {};
Constructor<?> constructor = c.getConstructor(args);
Object inst = constructor.newInstance((Object[])args);
答案 2 :(得分:1)
在您的方法中,您接受c
作为输入,这是由Class<?>
对象表示的某种未知类型。如果c
表示的类型具有public
无参数构造函数,则可以通过调用以下函数创建新实例:
try {
// return c.newInstance(); -- DEPRECATED as of Java 9
return c.getConstructor().newInstance();
} catch (Exception e) {
// handle case of no such public, no-arg constructor
}
如果没有,那么你会得到一个例外。如果您不想交叉并猜测,而是想知道您可以访问哪些构造函数,那么Reflection API将为您提供以下信息:
Constructor[] publicConstructors = c.getConstructors(); // may have .length == 0
for (Constructor ctor : publicConstructors) {
// find the one you want
}
然后,您可以检查这些对象,以查看每个对象需要哪些类型的参数。当您找到所需的构造函数时,可以在newInstance(Object ...)
对象上调用Constructor
并传递相应的参数值。
然而,即使有这些信息,您也需要以某种方式提供适当的值。为了解决这个问题,任何一个班级&#34;非常困难。如果您可以按照已知顺序将所需的值限制为零或仅限几个特定值,那么它将成为一个更容易解决的问题,但它会严重限制您的函数实际能够构造的对象的数量或类型。
还要记住这些事情:
您的方法接受任何Class<?>
,其中包含interface
,例如List
。接口无法实例化,也没有构造函数。您的示例是通过使用具体实现ArrayList
来避免此边缘情况。
构造函数不是在Java中继承的,因此即使您验证c
是ArrayList
的子类,也不能安全地假设c
具有与ArrayList
相同的构造函数签名。 }。 (也就是说,除非它真的是同一个类:ArrayList.class.equals(c)
。)
如果重写此代码以表示它只反序列化List
(或特定ArrayList
)而不是接受任何类型,那么您只需调用常规ArrayList
构造函数并节省一些麻烦。
但即使您这样做,您的代码也不会验证反序列化列表是ArrayList<String>
。反序列化过程的结果将是ArrayList<?>
,或List<?>
,或者甚至根本不是List
的内容。假设你很幸运,该文件确实包含ArrayList
,唯一的方法是知道列表&#34;只包含String
&#34;是在反序列化后验证列表中的每个对象。
泛型强制执行发生在编译时,运行时反序列化不验证参数化类型是类型安全的。这就是为什么编译器会发出关于不安全演员的警告:
Object out = getSerializedObject(ArrayList.class, "arraylist.ser");
ArrayList<?> unboundedList = (ArrayList<?>) out; // verifies that 'out' is really an ArrayList
ArrayList<String> myArrayList =
(ArrayList<String>) unboundedList; // UNSAFE! Does not verify the list's contents!