Java泛型和类型转换怎么实现?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (6)
  • 关注 (0)
  • 查看 (2236)

我有一个创建得很糟糕的容器对象,它将不同java类型的值(字符串、布尔值等)放在一起。

public class BadlyCreatedClass {
    public Object get(String property) {
        ...;
    }
};

我们用这种方法提取值

String myStr = (String) badlyCreatedObj.get("abc");
Date myDate = (Date) badlyCreatedObj.get("def");

我被迫使用这个对象编写一些新代码,并且我试图看看是否有干净的方法来实现这一点。更具体地说,下面哪种方法是首选的?

显式铸造

String myStr = (String) badlyCreatedObj.get("abc")
Date myDate = (Date) badlyCreatedObj.get("def");

使用通用强制转换

public <X> X genericGet(String property) {

}

public String getString(String property) { 
return genericGet(property); 
}

public Date getDate(String property) { 
return genericGet(property); 
}

使用Class.cast

<T> T get(String property, Class<T> cls) {
    ;
}
提问于
用户回答回答于

给出一个快速的答案,而不是深入到好的编程实践中...

我会用:

private <X> X genericGet(String property) {

}

public String getString(String property) { 
//... checks on property (String specific)...
Object obj = genericGet(property);
//... checks if obj is what is expected and if good return it
return obj; 
}

public Date getDate(String property) { 
//... checks on property (Date specific)...
Object obj = genericGet(property);
//... checks if obj is what is expected and if good return it
return obj
}

通知私有泛型Get。这样,我就可以检查GET属性是否是我等待接收的东西,并以正确的方式处理它。

我可以在getString中添加检查,这取决于属性,以确保答案是String对象。

我可以对属性中的getDate进行其他检查,以确保它将是返回的日期。

用户回答回答于

因为所有选项都涉及类型转换,因此它们在某种程度上都是“不安全的”,并且可能会在ClassCastExceptions报错。

我绝对推荐使用助手方法,例如getString(),,,getDate()对于通常存储在此对象中的常见类型。这些方法对于所有三个选项都很有用,因为对象的用户必须编写的代码减少了。

但是,仍然需要一种从对象接收“不寻常”类型的方法。为此,我将使用显式强制转换或类强制转换。原因是我认为这两种方式是大多数人使用的方式。即使泛型方法调用可以正常工作,我认为方法调用如下obj.genericGet<String>("myproperty");不是每个java开发人员都知道的。这在实践中是很少见到的。

个人是会添加一个getObject()方法,即使我不喜欢将强制转换类型移动到对象的用户。这样做的好处是,将有一个一致的接口,如果我看到这样的方法,我就会这样想getString()getDate()...

用户回答回答于

正如已经提到的,上述所有方法都是危险的,可能在运行时导致ClassCastExceptions。

如果真的有必要的话,我更喜欢“通用cast”方法,因为它使接口显式和自扩展(使genericGet在这种情况下是私人的)。

结论:如果容器中有明确定义的类数,我将使用“泛型CAST”。如果你需要支持无数的类,我会使用“Class.Castes”

用户回答回答于

我更喜欢使用通用的cast。为什么?

  • 外露的cast总是更难维护。当阅读代码时,根本不知道这个方法可能返回什么。此外,该方法使用错误的可能性ClassCastException会在运行期间很高。
  • 类强制转换更难以维护。在我看来,你用这种方式创建了一些可以称为意大利面代码的东西。
  • 当创建如下方法时getStringgetDate你给你的类提供了非常清晰的界面。更重要的是,它总是可以获得其他类的对象,而不是StringDate因为还提供了泛型方法。
用户回答回答于

泛型强制转换方法导致编译器发出未经检查的警告。未选中的警告表示在运行时没有(完全)检查强制转换问题,也就是说,即使值不是正确的类型,它也可能成功。这会导致变量保存与声明的类型不兼容的值,Java语言规范调用的情况堆污染...

以下程序演示了这一点:

class Holder {
    Object value;

    Holder(Object value) {
        this.value = value;
    }

    <T> T get() {
        return (T) value;
    }
}

class C<T> {
    T value;

    C(Holder h) {
        value = h.get();
    }
}

public class Test {
    public static void main(String [] args) throws IOException {
        Holder holder = new Holder("Hello");
        C<Integer> c = new C<Integer>(holder);
        System.out.println("I just put a String into a variable of type Integer");

        // much later, possibly in a different part of your program
        c.value.longValue(); // throws ClassCastException
    }
}

因此,我强烈建议使用选中的强制转换。检查普通的转换(第一种方法)和反射的转换(第三种方法)。但是,反射式转换不能用于参数化类型(List<String>.class不编译)。

因此,最简单和最灵活的安全解决方案是普通cast。

用户回答回答于

类似于:

class Holder {
    private long id;
    private String name;
    private Date dateofBirth;

    //getters and setters
}

然后检索基于id,不需要任何cast。

扫码关注云+社区

领取腾讯云代金券