有什么理由在Java中使用泛型吗?

有什么理由在Java中使用泛型吗?,java,generics,Java,Generics,也许我没有抓住要点,但我有C#的背景,我看不出有任何理由使用Java的泛型 在C#中,我有一个方法,它接受一个字符串并将其反序列化为一个对象 public static Deserialize<T>(string source) { // Use reflection to examine T and determine // which properties I should be reading from // the string. Create an

也许我没有抓住要点,但我有C#的背景,我看不出有任何理由使用Java的泛型

在C#中,我有一个方法,它接受一个字符串并将其反序列化为一个对象

public static Deserialize<T>(string source) {
    // Use reflection to examine T and determine
    // which properties I should be reading from
    // the string. Create an instance of T, 
    // populate the properties and return it
}
并进行一些类型编译时类型检查?如果是这样的话,考虑到变量名清楚地说明了类型应该是什么(至少只要我使用合理的命名约定),这似乎是多余的


我忍不住觉得我遗漏了什么…

泛型类型只在编译时检查,但它有助于避免bug。

如果不使用泛型,每次都可以强制转换。你必须:

// if raw List
MyClass c = (MyClass) myClassList.get(0);
// if List<MyClass>
MyClass c = myClassList.get(0);
//如果是原始列表
MyClass c=(MyClass)myClassList.get(0);
//如果列表
MyClass c=myClassList.get(0);
比如说

是的,泛型在运行时被删除,是的,它们只是在编译时强制执行类型安全;但是,在使用边界时仍然存在运行时类型擦除。例如:

public <E extends RuntimeException> E get(final Class<E> c,
    final Throwable t)
{
    try {
        return (E) getHandle(c).invokeExact(t);
    } catch (Error | RuntimeException e) {
        throw e;
    } catch (Throwable oops) {
        final RuntimeException exception = new IllegalStateException(oops);
        exception.addSuppressed(t);
        throw exception;
    }
}
public E get(最终c级、,
最终可丢弃量(t)
{
试一试{
return(E)getHandle(c)invokeExact(t);
}捕获(错误|运行时异常e){
投掷e;
}捕捉(可丢弃的oops){
最终运行时异常=新的非法状态异常(oops);
例外情况。添加抑制(t);
抛出异常;
}
}
此处的
E
具有运行时类型擦除;它
扩展了RuntimeException
。因此,强制转换为
运行时异常
,而不是
对象

有关运行时类型擦除的另一个有趣示例,请参见(提示:它为什么定义
T extends Object&Comparable
第二个将处理对象类型,并且允许您执行一些愚蠢的操作,比如MyClassList.add(新整数(0))

这是泛型的主要优点之一,或者C++中的模板。编译时检查验证你的应用程序不会做任何未定义的行为-就像上面的例子。

< P>从java文档:

为什么使用泛型? 简而言之,泛型支持类型(类和接口)定义类、接口和方法时作为参数。与方法声明中使用的更为常见的形式参数非常相似,类型参数为您提供了一种将相同代码与不同输入重复使用的方法。区别在于,形式参数的输入是值,而类型参数的输入是类型

与非泛型代码相比,使用泛型的代码有许多好处:

  • 编译时更强的类型检查。 Java编译器对泛型代码应用强类型检查,并在代码违反类型安全性时发出错误。修复编译时错误比修复运行时错误容易,而修复运行时错误可能很难找到

  • 消除铸型。 以下不带泛型的代码段需要强制转换:

    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);
    
    当重新编写以使用泛型时,代码不需要强制转换:

    List<String> list = new ArrayList<String>();
    list.add("hello");
    String s = list.get(0); // no cast
    
    List List=new ArrayList();
    添加(“你好”);
    字符串s=list.get(0);//不强制转换
    
  • 使程序员能够实现通用算法。 通过使用泛型,程序员可以实现在不同类型的集合上工作、可以自定义、类型安全且易于阅读的泛型算法


您的
反序列化
方法在Java中并非不可能。您只需显式地传递
对象,因为它在运行时无法通过类型参数
T
确定

public static <T> T deserialize(Class<T> clazz, String source) {
    // Use reflection to examine clazz and determine
    // which properties I should be reading from
    // the String. Create an instance of T 
    // (which you can do using clazz.newInstance()), 
    // populate the properties and return it
}
publicstatict反序列化(类clazz,字符串源){
//使用反射检查clazz并确定
//我应该阅读哪些属性
//创建一个T的实例
//(可以使用clazz.newInstance()执行此操作),
//填充属性并返回它
}
可以使用
反序列化(AnyClass.class,“AnyClass的字符串表示”)
调用它

这里的列表可以包含任何对象,可以是字符串、整数或双精度、Employee等
这会导致类型安全问题,并在编译时停止运行时错误

List<String> list  = new ArrayList<String>();
List List=new ArrayList();

在这里,只能添加字符串值

有趣的点re:bounds,但这意味着您总是以最小公分母为目标。如果您希望能够比较和(计数)呢?Comparable之所以有效,是因为它被所有具有可比性的类广泛使用。如果你想拥有两个这样的方法,你需要你的类继承自
MyComparableCountable
,这将你限制在你已经实现的类中……嗯,我不知道你所说的
Count
;请注意,
扩展E1&E2时&etc
,第二个参数和更多参数必须是接口。如果您的
Count
是一个具体的类,那么编写
T extends Count&ComparableCount可能是一个坏例子。我试图选择另一个方法,它可能存在于多个类上,但不是所有类上。您是说我可以链接尽可能多的“功能”吗正如我所需要的……
Count&Comparable&somethingels“我试图选择另一种可能存在于多个类上的方法”
&
在类型绑定中创建了一个交集类型。也许我很幸运,但我从未与如此不称职的开发人员合作过。当然,再次检查也不错,但是……如果有人犯了这样的错误,我不希望他们在我的codebase@Basic也许我的示例有点过于激烈,在复杂和大型的代码库中,类型检查是helpfull-这只是帮助开发人员发现bug的另一个工具。这就像是一场关于是否在java中使用断言或总是抛出异常的辩论。我可以从我使用动态语言的经验(主要是Clojure)中证明这一点跟踪集合所包含的内容是一件非常痛苦的事情,尤其是当您的代码经常使用相同概念的类似表示(如DB ID、完整实体对象、简化的专用哈希等)时
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
public static <T> T deserialize(Class<T> clazz, String source) {
    // Use reflection to examine clazz and determine
    // which properties I should be reading from
    // the String. Create an instance of T 
    // (which you can do using clazz.newInstance()), 
    // populate the properties and return it
}
List list = new ArrayList();
list.add("car");
list.add("cycle");
list.add(12);
List<String> list  = new ArrayList<String>();