Use generic type with specification on constructor
如何在Java中正确执行下列操作?我希望有一个可以创建对象列表的通用例程。在这个例程中,我期望这些对象类的构造函数支持一个特定的参数。
澄清:我希望这个例程从JSON字符串创建一个
1 2 3 4 5 6 7 8 9 10 11 12 | interface CreatableFromJSONObject<T> { T(JSONObject object); // Complains about missing return type. } static <T> List<T extends CreatableFromJSONObject> jsonArrayToList(JSONArray array) { List<T> result = new ArrayList<T>(); for (int i = 0; i < array.length; ++i) { JSONObject jsonObject = array.getJSONObject(i); result.add(T(jsonObject)); // If T has one constructor with 1 one argument JSONObject } return result; } |
然后用一个实现这个接口的示例类
1 2 3 4 5 | class SomeClass implements CreatableFromJSONObject { SomeClass(JSONObject object) throws JSONException { // implementation here } } |
我可以使用所需的方法:
1 | List<SomeClass> list = jsonArrayToList<SomeClass>(someJSONArray); |
现在,在StActFoad上有相当多的点击,所以我已经了解到上面所概述的是不可能的,因为Java不支持在接口中指定一个特定的构造函数,也不支持静态方法(这是对同一事物的替代路径,同样的原因也是不可能的)。
那么,实现这一目标的最佳方法是什么呢?
我目前的最佳尝试是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Constructor<T> fromJSONObjectConstructor) { List<T> result = new ArrayList<T>(); try { for (int i = 0; i < jsonArray.length(); i++) { result.add(fromJSONObjectConstructor.newInstance(jsonArray.getJSONObject(i))); } } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (JSONException e) { throw new RuntimeException(e); } return result; } |
然后添加到该方法应支持的每个类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class SomeClass { public static final Constructor<SomeClass> jsonObjectConstructor; static { try { jsonObjectConstructor = CafellowEntity.class.getConstructor(JSONObject.class); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } SomeClass(JSONObject object) throws JSONException { // Implementation here } } |
我用
1 | List<SomeClass> list = jsonArrayToList(myJSONArray, SomeClass.jsonObjectConstructor); |
这是我能想到的最漂亮的解决方案,除了根本不使用通用实现之外,只要把(在本例中)两行代码放在我需要它们用于特定类的任何地方的例行工作中就可以了。
有什么建议吗?与其他解决方案相比,这个解决方案的性能如何?通过不支持它,就像Java可能告诉我,我不应该做这件事,但这并不能阻止我对它的好奇。
除非您正在进行某种异常的反序列化,否则这种设计过于复杂且容易出错。Android捆绑了一个优秀的JSON解析器,它已经能够做到这一点,并且做得很好。当前为其定义自定义构造函数的每个类型都可以用一行代码反序列化:
1 | final CustomObj obj = new Gson().fromJson(jsonObj.toString(), CustomObj.class); |
将此合并到现有方法中,您最终会得到以下结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Class<T> clazz) { if (jsonArray == null || clazz == null) return null; final Gson gson = new Gson(); List<T> result = new ArrayList<T>(jsonArray.length()); for (int i = 0; i < jsonArray.length(); i++) { try { result.add(gson.fromJson(jsonArray.getJSONObject(i).toString(), clazz)); } catch (final JSONException je) { je.printStackTrace(); return null; } } return result; } |
您可以通过省略构造函数实例和使用clazz实例来简化解决方案。因此,
1 | public static <T> List<T> jsonArrayToList(final JSONArray jsonArray, Class<T> clazz); |
然后由
如果你事先知道课程的类型,这就可以了。