先看一个栗子,看看能不能找出来里面的错误:

/**
* 请不要在新代码中使用原生态类型
* @author weishiyao
*
*/
public class Test { public static void main(String[] args) {
List<String> strings = new ArrayList<>();
unsafeAdd(strings, new Integer(42));
String string = strings.get(0);
System.out.println(string);
} private static void unsafeAdd(List list, Object object) {
list.add(object);
}
}

  运行一下,看一下报错结果:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.weishiyao.effectiveJava.entry23.Test.main(Test.java:16)

  对的,是一个ClassCastException,这是一个编译器声称的转换,因此一般会保证成功,但是我嘛在这个栗子中忽略了一条编译器的警告,就会为此而付出代价。

  但是,如果用unsafeAdd(List<Object> list, Object object)代替原生的List类型,我们的IDE会直接报错。

  在不确定或者不在乎集合中元素类型的情况下,你也许会使用原生态的类型。例如,假设想要编写一个方法,它有两个集合(set),并从中返回他们公有的元素的数量。如果不熟悉范型的话,可以参考以下方式来编写这种方法:

	static int numElementsInCommen(Set s1, Set s2) {
int result = 0;
for (Object object : s1) {
if (s2.contains(object)) {
result++;
}
}
return result;
}

  这个方法倒是可行,但是它使用了原生态类型,这是很危险的。从java1.5发行版本开始,java就提供了一种安全的替代方法,称作无限制的通配符类型,如果要使用范型,但是确定或者不关心实际的参数类型,就可以用一个问号代替。例如范型Set<E>的无限制通配符类型为Set<?>。这是最普通的参数化Set类型,可以持有任何集合。

  在无限制通配类型Set<?>和原生态类型Set之间有什么区别呢?这个问号真正起到作用了么?这一点不需要赘述,但通配符类型是安全的,原生态类型则不安全。可以将任何元素放入使用原生态类型的集合中,因此很容易破坏该集合类型的约束条件;但不能将任何元素(除了null)放到Collection<?>中。

  不要在新代码中使用原生态类型,这条规则有两个小小的例外,两者都源于“范型信息可以在运行时被擦除”这一事实。在类文字中必须使用原生形态。规范不允许使用参数化类型。换句话说,List.class,String[].class和int.class都是合法的。但是List<String>.class和List<?>则不合法。

  这条规则第二个例外与instanceof操作符有关。由于范型信息可以在运行时被擦除,一次在参数化类型而非无限制通配符上使用instanceof操作符时非法的。用无限制通配符类型代替原生态类型,对instanceof操作符的行为不回产生任何影响。在这种情况下,尖括号<>和问号?就显得多余了。下面是利用范型来使用instanceof操作符的首选方法:

				if (object instanceof Set) {	// Raw type
Set<?> m = (Set<?>) object; // Wildcard type
}

  注意,一旦确定这个object是个Set,就必须将他转换成通配符类型Set<?>,而不是原生类型,这个是受检的,否则的话我们的IDE还是会报错的。

EffectiveJava——请不要在代码中使用原生态类型的更多相关文章

  1. effective_java第23条:请不要新代码中使用原生态类型

    从这条开始涉及泛型相关的点. 从JDK5开始Java新增了“泛型”新特性,例如:List<String>,在这之前则只有List不会限定类型. 如今的JDK版本中还是可以写原生类型,但这会 ...

  2. EffectiveJava(23)为什么不能在新生代码中使用原生态类型

    泛型类和泛型接口 声明一个或者多个类型参数的类或者接口. 为什么不要在新代码中使用原生态类型 原生态类型,即泛型不带参数的类型 如List的list,list就是其原生态类型 1.使用原生态类型,插入 ...

  3. Effective java 系列之避免过度同步和不要使用原生态类型,优先考虑泛型

    避免过度同步(67):在一个被同步的方法或代码块中,不要调用哪些被设计成被覆盖的方法或者是由客户端以函数对象的形式提供的方法(21). 有点拗口,书上提供的创建者与观察者模式,add方法太多,看得眼花 ...

  4. 在Visual Studio代码中使用Flask

    Flask是一个用于Web应用程序的轻量级Python框架,它提供了URL路由和页面呈现的基础知识. Flask被称为“微”框架,因为它不直接提供表单验证,数据库抽象,身份验证等功能.这些功能由称为F ...

  5. Dynamics AX 2012 R2 从代码中调用SSRS Report

    平时,我们制作SSRS Report的方法主要有两种:使用Query或RDP.如果需要为报表传递参数,就要在代码中为报表参数赋值,然后在代码中调用报表.下面我总结下这两种报表在代码中传参和调用的方式: ...

  6. 「Flink」Flink中的时间类型

    Flink中的时间类型和窗口是非常重要概念,是学习Flink必须要掌握的两个知识点. Flink中的时间类型 时间类型介绍 Flink流式处理中支持不同类型的时间.分为以下几种: 处理时间 Flink ...

  7. 该对象尚未初始化。请确保在所有其他初始化代码后面的应用程序启动代码中调用 HttpConfiguration.EnsureInitialized()。

    WebAPI使用属性路由,配置config.MapHttpAttributeRoutes();后出现错误: System.InvalidOperationException: 该对象尚未初始化.请确保 ...

  8. 【转】代码中特殊的注释技术——TODO、FIXME和XXX的用处

    (转自:http://blog.csdn.net/reille/article/details/7161942) 作者:reille 本博客网址:http://blog.csdn.net/reille ...

  9. linux内核分析作业4:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    系统调用:库函数封装了系统调用,通过库函数和系统调用打交道 用户态:低级别执行状态,代码的掌控范围会受到限制. 内核态:高执行级别,代码可移植性特权指令,访问任意物理地址 为什么划分级别:如果全部特权 ...

随机推荐

  1. Gridview转发

    首页 开源项目 问答 动弹 博客 翻译 资讯 专题 城市圈 [ 登录 | 注册 ] 博客专区 > Reya滴水心的博客详情 Asp.net中GridView使用详解(很全,很经典) Reya滴水 ...

  2. c#设计模式-工厂方法

    一. 工厂方法(Factory Method)模式 工厂方法(FactoryMethod)模式是类的创建模式,其用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中. 工厂方法模式是简单工 ...

  3. Jetty 服务器的知识

    Jetty 服务器的知识 也许你还没有听说过这个Jetty服务器,不过它确实是一种比较轻量级的Java服务器,和Tomcat一样,专门解释JavaWeb程序的服务器.因为在之前学习Java Web 的 ...

  4. Render OpenCascade Geometry Curves in OpenSceneGraph

    在OpenSceneGraph中绘制OpenCascade的曲线 Render OpenCascade Geometry Curves in OpenSceneGraph eryar@163.com ...

  5. gridview里日期显示格式

    Text='<%#Bind("EndDate","{0:yyyy-MM-dd}") %>'

  6. javase基础复习攻略《七》

    容器是什么?通俗的讲容器指可以装其它东西的器皿,前面我们提到的数组便是容器的一种,容器的概念在JAVA中便可以理解为用来存储其它对象的器皿.本篇就让我们一起来认识一下JAVA为我们提供的容器类. 1. ...

  7. 在IIS中部署ASP.NET 5应用程序遭遇的问题

    用VS2015中创建了一个非常简单的ASP.NET5程序: 在Startup.cs中只输入一行代码: using System; using Microsoft.AspNet.Builder; usi ...

  8. java设计模式(五)--建造者模式(Builder)

    转载:http://zz563143188.iteye.com/blog/1847029 工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象 ...

  9. 大数据下的Distinct Count(一):序

    在数据库中,常常会有Distinct Count的操作,比如,查看每一选修课程的人数: select course, count(distinct sid) from stu_table group ...

  10. CSS魔法堂:再次认识font

    一.前言 文字承载着站点内涵,而良好的字体.排版则为用户提供舒适的阅读体验.本文打算对字体稍微深入一下子网页字体的内容,若有纰漏请大家指正,谢谢! 目录一坨: 二, 字体分类 1. 衬线体(Serif ...