代码之家  ›  专栏  ›  技术社区  ›  Asa Ayers

重载方法的Java动态转换

  •  3
  • Asa Ayers  · 技术社区  · 17 年前

    我正在尝试创建一个函数,在这个函数中,我可以传递将放入 ContentValues . 我遇到的问题是,我试图允许一次传递多个键/值对,因此键可以是字符串数组,但值必须是对象和ContentValue。put()不允许对象,它们需要转换为String、Double、Float、,等等。是否有一种方法可以确定对象的类型并强制转换它,以便它调用正确的put()?下面是一个有效的方法,但它要求我为每种可能的值类型添加一个if。

     public long create(String[] names, Object[] values) {
            ContentValues initialValues = new ContentValues();
    
            for (int i = 0; i < names.length; i++)
            {
                String type = values[i].getClass().getName();
                if (type.equals("java.lang.Double"))
                {
                    initialValues.put(names[i], (Double)values[i]);
                }
                else if (type.equals("java.lang.String")) {
                    initialValues.put(names[i], (String)values[i]);
                }
                else
                {
                    throw new InvalidParameterException("Unable to convert type:"+type);
                }
            }
    
            return mDb.insert(this.getTableName(), null, initialValues);
        }
    
    4 回复  |  直到 17 年前
        1
  •  3
  •   Laurence Gonsalves    17 年前

    您的方法是正确的,尽管您应该使用 instanceof 而不是 getClass().getName() . 即:

    if (values[i] == null) {
      initialValues.putNull(names[i]);
    } else if (values[i] instanceof Boolean) {
      initialValues.put(names[i], (Boolean)values[i]);
    } else if (values[i] instanceof Byte) {
      initialValues.put(names[i], (Byte)values[i]);
    } else if (values[i] instanceof Double) {
      initialValues.put(names[i], (Double)values[i]);
    } else if (values[i] instanceof Float) {
      initialValues.put(names[i], (Float)values[i]);
    } else if (values[i] instanceof Integer) {
      initialValues.put(names[i], (Integer)values[i]);
    } else if (values[i] instanceof Long) {
      initialValues.put(names[i], (Long)values[i]);
    } else if (values[i] instanceof Short) {
      initialValues.put(names[i], (Short)values[i]);
    } else if (values[i] instanceof String) {
      initialValues.put(names[i], (String)values[i]);
    } else if (values[i] instanceof byte[]) {
      initialValues.put(names[i], (byte[])values[i]);
    } else if (values[i] instanceof ContentValues) {
      initialValues.putAll(names[i], (ContentValues)values[i]);
    } else {
      throw new IllegalArgumentException(
          "can't put " + values[i].getClass().getName() + " in ContentValues.");
    }
    

    如果 ContentValues 不是吗 final Object .

        2
  •  2
  •   cletus    17 年前

    您有两个选择:

    1. 使用反射查找传入类型的正确方法。

    需要考虑的是空值。如果传入的值为null,则没有类,因此您无法确定类型(如果该类型与您的使用相关)。

        3
  •  1
  •   Stephen C    17 年前

    这是你所能做到的最简洁、最高效、最正确的。编译器可以优化类型转换,但这并不重要。

    public long create(String[] names, Object[] values) {
        ContentValues initialValues = new ContentValues();
        for (int i = 0; i < names.length; i++) {
            Object v = values[i];
            if (v instanceof Double) {
                initialValues.put(names[i], (Double) v);
            } else if (v instanceof String) {
                initialValues.put(names[i], (String) v);
            } else {
                // You could test for v == null here ... otherwise you'll
                // get an NPE 
                throw new InvalidParameterException(
                        "Unable to convert type: " + v.getClass());
            }
        }
        return mDb.insert(this.getTableName(), null, initialValues);
    }
    

    一些注意事项:

    1. 编辑: 一般来说,您可能不想测试确切的类C。更可能的情况是您想测试“C或C的子类”。您不能使用类名来测试它。使用 instanceof
    2. 如果测试类名,请确保使用正确的类名。例如 Double.class.getName() 实际给予 "java/lang/Double" 不 "java.lang.Double"
    3. 以及比其他人慢 ,比较类名并不总是给出正确的答案。如果某个类正在使用类加载器技巧,则不同的类可以具有与报告的相同的名称 getName() getCanonicalName() .
    4. 避免对这样的事情使用反射。它不可避免地会变慢,而且编译器将无法发现您的许多错误。
        4
  •  0
  •   djna    17 年前

    ContentValues应该按照您将要编写的内容提供一个putObject()方法。我可能倾向于使用提供该方法的类来扩展或包装ContentValue,从而使代码可重用。