五分钟学Java:为什么不应该使用Java的原始类型?-阿里云开发者社区

开发者社区> 沉默王二> 正文

五分钟学Java:为什么不应该使用Java的原始类型?

简介: 五分钟学Java:为什么不应该使用Java的原始类型?
+关注继续查看

在逛 Stack Overflow 的时候,发现了一些访问量像熊耳山一样高的问题,比如说这个:为什么不应该使用Java的原始类型?访问量足足有 205K+,这不得了啊!说明有很多很多的程序员被这个问题困扰过。实话实说吧,本文之前的我就是其中之一。


来回顾一下提问者的问题吧:


Java 的原始类型是什么?为什么不要使用原始类型?如果不能使用原始类型,有什么更好的选择呢?

如果大家也被这个问题困扰过,或者正在被困扰,就请随我来,咱们肩并肩手拉手一起梳理一下这个问题,并找出最佳答案。Duang、Duang、Duang,打怪进阶喽!


01、Java 的原始类型是什么?


要理解 Java 的原始类型是什么,可以先看一下什么是泛型。


List<String> list = null;

1

其中 list 就是一个泛型,我们通常称之为字符串(String)列表(List),也就是说 list 中只能放字符串类型的元素。


如果我们按照下面这种方式声明 list 的话,它就是一个原始类型。


List list = null;


从 list 的声明当中我们可以对比发现,原始类型没有为容器指定明确的元素类型,所以我们可以在容器中放入一个 String,也可以放入一个 Integer,甚至任意的类型,就像下面这样。


public class RawType {

   public static void main(String[] args) {

       List list = new ArrayList();

       list.add("沉默王二");

       list.add(18);

       list.add(new RawType());

   }

}


注意哦,编译器没有任何提醒!这预示着 Java 这门强类型的语言竟然有点弱类型的影子了。


PS:关于 Java 中的类型术语,大家可以参照下表。


术语 含义 举例

Parameterized type 参数化类型 List<String>

Actual type parameter 实际类型参数 String

Generic type 泛型类型 List<E>

Formal type parameter 形式类型参数 E

Unbounded wildcard type 无限制通配符类型 List<?>

Raw type 原始类型 List

Bounded type parameter 限制类型参数 <E extends Number>

Bounded wildcard type 限制通配符类型 List<? extends Number>

02、为什么不要使用原始类型?


大家可能会有一个疑惑,原始类型用起来很爽啊!因为不用关心放入 List 的元素到底是什么类型,想放什么就可以放什么,不要太爽啊!


可当我们想要从 List 中把元素取出来使用的时候,可就遇到大麻烦了。


List list = new ArrayList();
list.add("沉默王二");
list.add(18);
list.add(new RawType());
for (Object o : list ) {
    String s = (String) o;
    System.out.println(s);
}


上面这段代码编译的时候没有任何问题,但输出的时候就会抛出 ClassCastException。


沉默王二

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

at com.cmower.java_demo.programcreek.RawType.main(RawType.java:14)


除非我们使用 instanceof 关键字进行类型判断,就像下面这样。


List list = new ArrayList();
list.add("沉默王二");
list.add(18);
list.add(new RawType());
for (Object o : list ) {
    if (o instanceof String) {
        String s = (String) o;
        System.out.println(s);
    } else if (o instanceof Integer) {
        Integer i = (Integer) o;
        System.out.println(i);
    } else if (o instanceof RawType) {
        RawType raw = (RawType) o;
        System.out.println(raw);
    }
}



可假如代码写成这样,可真真算得上是糟糕的代码了。


通常来说,为了代码的安全性起见,我们希望代码的错误发生得越早越好,能在编译时就不要在运行时。可使用原始类型的时候,我们发现错误一直到运行时才可能会被检出。


还记得《扁鹊见蔡桓公》的故事吗?


扁鹊见蔡桓公,立有间。扁鹊曰:“君有疾在腠理,不治将恐深。”桓侯曰:“寡人无疾。”扁鹊出,桓侯曰:“医之好治不病以为功。”…居十日,扁鹊望桓侯而还走。桓侯故使人问之,扁鹊曰:“疾在腠理,汤熨之所及也;在肌肤,针石之所及也;在肠胃,火齐之所及也;在骨髓,司命之所属,无奈何也。今在骨髓,臣是以无请也。”居五日,桓侯体痛,使人索扁鹊,已逃秦矣。桓侯遂死。

病情发现得越早,治疗的可能性就越大。同理,代码隐藏的问题发现的越晚,找出根源花费的精力就越大、时间就越多。


03、有什么更好的选择呢?


如果不能使用原始类型,有什么更好的选择呢?


为了让 List 能够容纳任意类型的元素,我们可以使用 List<Object>,尽管这并不是一个最优的选择。


List<Object> list = new ArrayList<>();
list.add("沉默王二");
list.add(18);
list.add(new RawType());


鹅鹅鹅,这样的参数化类型 List<Object> 和原始类型 List 之间有区别吗?


当然有了!


List<Object> 至少明确地告诉编译器,该容器可以存放任意类型的对象,没有丢失类型的安全性。


可能我这样的解释会遭到某些抨击:“这不五十步笑百步吗?呵呵。”但我要想表达的是登月男神阿姆斯特朗的那句话:“这是我个人的一小步,却是人类的一大步。”能向前迈一步是一步啊。


那最优的选择是什么呢?


从一开始就为 List 声明具体的类型,比如说 List<String> list,当我们尝试放入一个 int 值的时候就会编译出错。




从另一种层面上来说,这样做削弱了程序的灵活性,但保证了程序的绝对安全性,以及在表达上的明确性。


04、为什么 Java 允许使用原始类型?


既然原始类型是不安全的,那为什么 Java 一直允许使用原始类型呢?并且泛型擦除后仍然是个原始类型呢?


答案很简单、很无厘头、很苍白——为了版本兼容!


引入泛型的时候,Java 已经进入到第二个十年(年纪大了),市面上存在大量没有使用 Java 泛型的代码。如果因为版本升级导致它们不能使用,恐怕 Java 也活不到现在,毕竟对用户友好才是一个软件存在的硬道理。


当然了,Java 已经对开发者做出了警示:强烈建议不要在 Java 代码中使用原始类型,未来的版本中可以会禁止使用原始类型,请小心点。


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10014 0
ASP.NET MVC 5– 使用Wijmo MVC 5模板1分钟创建应用
开始使用 使用Wijmo制作MVC5应用程序,首先要做的是安装Wijmo 。 测试环境 VS2013(VS2010,VS2012支持MVC3,MVC4)、MVC5、Framework4.5、IE11、Studio for ASP.NET Wijmo2014V1,Note:不支持VS的更高版本 文件-新建项目 在安装了Wijmo之后,在 VS2010,VS2013 中选择新建项目分别如下。
1039 0
云原生应用万节点分钟级分发协同实践
作者:谢于宁、罗晶、邓隽 引言 2019 年天猫双11,阿里巴巴核心系统首次实现 100% 上云。面对全球最大的交易洪峰,阿里云扛住了每秒 54.4 万笔的交易峰值,这是“云原生”与“天猫全球狂欢节”的一次完美联名。 (图为 2019 年天猫双11 成交额) 容器镜像服务作为阿里巴巴经济体云原生领域的重要基础设施之一,早在 双1
383 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13814 0
在java中使用SPI创建可扩展的应用程序
什么是可扩展的应用程序呢?可扩展的意思是不需要修改原始代码,就可以扩展应用程序的功能。我们将应用程序做成插件或者模块。 这样可以在不修改原应用的基础上,对系统功能进行升级或者定制化。 本文将会向大家介绍如何通过java中的SPI机制实现这种可扩展的应用程序。
447 0
10分钟,不会“搬砖”的校长搭出了智慧校园微应用
有着两个校区的合肥师范学院附属实验小学,目前共有2541名学生和146名教师。多校区管理,意味着需要应对师生、家长的众多需求,对于校园管理和后勤服务的要求非常高。面对这样的校情,该校校长彭正认为开启校园“智慧管理”刻不容缓,借力“宜搭”不懂代码的他们构建了“智慧校园生态圈”。
2517 0
+关注
沉默王二
微信搜索「沉默王二」,回复关键字「00」获取硬核计算机基础资料。
1084
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载