205K+程序员关注过的问题:为什么不应该使用Java的原始类型?
在逛 Stack Overflow 的时候,发现了一些访问量像熊耳山一样高的问题,比如说这个:为什么不应该使用Java的原始类型?访问量足足有 205K+,这不得了啊!说明有很多很多的程序员被这个问题困扰过。实话实说吧,本文之前的我就是其中之一。
来回顾一下提问者的问题吧:
Java 的原始类型是什么?为什么不要使用原始类型?如果不能使用原始类型,有什么更好的选择呢?
如果大家也被这个问题困扰过,或者正在被困扰,就请随我来,咱们肩并肩手拉手一起梳理一下这个问题,并找出最佳答案。Duang、Duang、Duang,打怪进阶喽!
01、Java 的原始类型是什么?
要理解 Java 的原始类型是什么,可以先看一下什么是泛型。
List<String> list = null;
其中 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 代码中使用原始类型,未来的版本中可以会禁止使用原始类型,请小心点。
05、鸣谢
好了各位读者朋友们,以上就是本文的全部内容了。能看到这里的都是最优秀的程序员,二哥必须要动动手为你点个赞
205K+程序员关注过的问题:为什么不应该使用Java的原始类型?的更多相关文章
- 188W+程序员关注过的问题:Java到底是值传递还是引用传递?
在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java 到底是值传递还是引用传递?访问量足足有 188万+,这不得了啊!说明有很多很多的程序员被这个 ...
- 【Java】Java程序员面试宝典(第三版)第5章----Java程序设计基本概念
1.static静态变量,在次级作用域也可以被修改. 2.k++ + k++.第一个自加实际上只有在与计算+k++时补增.详情P36的题目. 3.Java数据类型从低到高分为(byte short c ...
- 牛客网程序员面试金典:1.2——原串翻转(java实现)
问题描述: 请实现一个算法,在不使用额外数据结构和储存空间的情况下,翻转一个给定的字符串(可以使用单个过程变量). 给定一个string iniString,请返回一个string,为翻转后的字符串. ...
- 多少牛逼的程序员毁在low逼的英文发音上(JAVA)
最最常用的关键词及音标 数据类型:boolean.byte.short.int.long.double.char.float.double. 包引入和包声明:import.package. 用于类和接 ...
- 对java程序员来说时间格式永远让人挠头来看Java Date Time 教程-时间测量
在Java中,用System.currentTimeMillis()来测量时间最方便. 你要做的是在某些操作之前获取到时间,然后在这些操作之后你想要测量时间,算出时间差.下面是一个例子: long s ...
- 从小工到专家 ——读《Java程序员职场全攻略》有感
从小工到专家 ——读<Java程序员职场全攻略>有感 <Java程序员职场全攻略>是以故事的形式,向读者介绍Java程序员的职场经验.作者牛开复在北京从事软件开发,已经是一 ...
- TCP/IP之四书五经[转自2003.12程序员]
TCP/IP协议是当前广域网和局域网通用的网络协议,因此,基于TCP/IP的编程就格外重要.从应用上来说,现在直接利用C层次Socket API进行TCP/IP编程的人确实越来越少了,各种现成的框架( ...
- 程序员带你学习安卓开发,十天快速入-对比C#学习java语法
关注今日头条-做全栈攻城狮,学代码也要读书,爱全栈,更爱生活.提供程序员技术及生活指导干货. 如果你真想学习,请评论学过的每篇文章,记录学习的痕迹. 请把所有教程文章中所提及的代码,最少敲写三遍,达到 ...
- Java程序员面试题集(1-50)(转)
转:http://blog.csdn.net/jackfrued/article/details/17339393 下面的内容是对网上原有的Java面试题集及答案进行了全面修订之后给出的负责任的题目和 ...
随机推荐
- ZeroC ICE中的对象模型和概念
Ice对象的模型和概念. Ice Object并非是我们的接口实现类的实例对象.我们的接口实现类的实例对象只是充当Ice Object的Servant的角色.一个Ice Object可以有众多Serv ...
- java中的string对象深入了解
这里来对Java中的String对象做一个稍微深入的了解. Java对象实现的演进 String对象是Java中使用最频繁的对象之一,所以Java开发者们也在不断地对String对象的实现进行优化,以 ...
- deepin安装pip
sudo apt install python3-venv python3-pip 升级最新版 pip3 install --upgrade pip 更新完以后就报错网上的解决办法没有好使的 退回版 ...
- python进程与线程的操作
进程操作: # project :Python_Script # -*- coding = UTF-8 -*- # Autohr :XingHeYang # File :processTest.py ...
- React中使用create-react-app创建项目,运行npm run eject建立灰度报错
我在运行npm run eject建立测试环境和正式环境时候报错 这里的问题是是脚手架添加.gitgnore文件,但是却没有本地仓库,按照以下顺序就可以正常使用 git add . git commi ...
- KubeCon 2019 北美会议完美落幕 | 云原生生态周报 Vol. 29
作者 | 陈俊.张晓宇.徐迪 业界要闻 KubeCon 2019 北美会议召开 业界最隆重的盛会 KubeCon+CloudNativeCon 今年在圣地亚哥举办,超过 12000 名参会者以及 10 ...
- 新闻实时分析系统-Flume数据采集准备
Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据:同时,Flume提供对数据进行简单处理,并 ...
- Dubbo实现登陆
一.目录展示 二.dubbo_logins_service 2.1 实体类和service层 2.2 logins实体类 package com.login.entity; import java.i ...
- python网络爬虫之入门[一]
目录 前言 一.探讨什么是python网络爬虫? 二.一个针对于网络传输的抓包工具fiddler 三.学习request模块来爬取第一个网页 * 扩展内容(爬取top250的网页) 后记 @(目录) ...
- Chapter 07-Basic statistics(Part3 correlations)
这一部分使用R基础已安装包中的state.x77数据集.该数据集的数据是关于美国50个州在1977年对人口,收入,文盲率,平均寿命,谋杀率,高中毕业率统计所得. 1.关联的种类(types of co ...