返回序列化对象(如果存在)否则返回新实例?

时间:2013-05-17 01:00:29

标签: java class object instance

我希望通过调用此方法来获取序列化对象:

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
        }
}

3 个答案:

答案 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中继承的,因此即使您验证cArrayList的子类,也不能安全地假设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!