Java到底是不是一种纯面向对象语言?
本文由码农网 – Dee1024原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!
Java——是否确实的 “纯面向对象”?让我们深入到Java的世界,试图来证实它。
在我刚开始学习 Java 的前面几年,我从书本里知道了 Java 是遵循 “面向对象编程范式(Object Oriented Programming paradigm)”的。在Java世界内一切都是对象,甚至包括字符串(String)这些都是对象(在 C 语言中,字符串是字符数组),那时候,我认为 Java是一种面向对象的语言。
但是在后来,我在互联网站上陆续看到不少开发者说 “Java实际上不是纯粹的面向对象,因为并不是所有的东西在 Java 世界都是一个对象”。他们很多的论点都可以概括为以下两点:
- 所有的静态内容( static 关键修饰的变量和方法)不属于任何对象,所以这些是非对象的东西。
- 所有基本类型(char,boolean,byte,short,int,long,float,double)都不是对象,因为我们不能做类似正常对象的所具有的操作(例如:使用“.”来访问对象的属性和方法)。
在那时,由于个人知识经验储备有限,我又很容地相信上面的论点,并且也开始认为 “Java 不是纯粹的面向对象编程语言”。
到了更后来,在我的一次JVM学习过程中,我有了新的发现:
JVM 在创建对象的时候,实际上会创建两个对象:
- 一个是实例对象。
- 另一个是Class 对象。该 Class 对象在JVM内仅仅会装载一次,该类的静态方法和静态属性也一同装载,JVM使用该 Class 对象来创建具体的实例对象(如上面的对象)。
例如,在下面的 Java 语句中,将有两个对象被创建:
Employee emp = new Employee();
一个是实例对象 emp ;另一个则是 Class对象,我们可以通过 Employee.class 引用到它;这个 Class 对象拥有所有的这个类定义的静态变量和静态方法,同时,如果我们访问 通过 emp 对象来访问静态内容,会发现它其实指向的对象就是 Employee.class 。
这也揭开了另一个迷:为什么静态内容在一个对象中(不管是emp还是emp2)改变了,在另一个对象中也同时改变,因为这两个对象改变的都是在 Employee.class 同一个对象里面的内容。
现在,上面说到的第一个论点我们要取消了。因为,静态内容确实被证实属于一个对象。
但是我们还要确认第二个论点:正如早前提到的,原始类型在Java中不是对象,它们无法做类似对象的操作。为了解决这个问题,Java 官方为每一个原始类型推出了对应的包装类(比如:Integer 对应 int,Long 对应 long,Character 对应 char),所以,其实现在我们可以为原始类型创建一个包装对象,同时对它们做对象相关的操作。并且,由于自动拆装箱,我们可以把一个原始类型值赋值给它对应的包装类的引用。但是我们仍然不能对这些原始类型做对象的操作——我们需要创建对应包装类的对象。
例如:
Integer obj = new Integer(5); // here we can do i.toString(); int i = 5; // but we can't do i.toString() here
到目前为止,从一个最终用户的角度上来看的,我们可以确认 “原始类别不是对象”。( Java开发人员是Java的最终用户,因为我们正在使用它,而不是创造它 )。
如果站在JVM的视角,会有新的发现:
其实,在JVM看来它把所有的 “原始类型” 都是当作对象处理” ,要证明这一点可以通过 Class类的源代码 或者 Javadoc中Class类的说明。
根据 java.lang.Class 类的源代码,该类的注释是:
Java官方描述:
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
参考译文:
Class类的实例表示正在运行的Java应用程序的类和接口。像枚举是一种类和注解则是一种接口。每个数组也属于被反射作为由具有相同的元素类型和尺寸的数目的所有阵列共享一类对象的类。原始的Java类型(boolean, byte, char, short, int, long, float, and double)和关键字void也表示为Class对象。
同时也根据Javadoc中对Class.isPrimitive()方法的定义,来判断
Java官方描述:
public boolean isPrimitive()
Determines if the specified Class object represents a primitive type.
There are nine predefined Class objects to represent the eight primitive types and void. These are created by the Java Virtual Machine, and have the same names as t he primitive types that they represent, namely boolean,byte, char, short, int, long, float, and double.
These objects may only be accessed via the following public static final variables, and are the only Class objects for which this method returns true.
Returns:
true if and only if this class represents a primitive type
Since:
JDK1.1
参考翻译:
public boolean isPrimitive()
判断指定的Class对象是否代表一个基本类型。
一共有9种设定好的Class对象来表示对应的基本类型和void关键字。这些对象都是由JVM创建的。…
return当且仅当该类表示一个真正的基本类型
以上都说明,在JVM内部,其实原始类型就是对象。
当你打开 Javadoc 对 Class 类的定义中,通过 “CTRL+F ” 查找关键字 “primitive”, 将会发现证据在表面 “在JVM里,它把基本类型当作对象来处理的”。
我们可以再来看一个例子: Integer.TYPE,在这部分文档清晰记录着:
Java官方描述:
public static final Class<Integer> TYPE
The Class instance representing the primitive type int.
以上都说明,在JVM内部,其实原始类型就是对象。
那么,既然说 “JVM”会为所有的基本类型创建一个对象,那我们为什么还那么常用 “原始类型”, 而不是直接使用对应的包装类对象呢?
这是因为,为 “原始类型” 创建的对象,在JVM内部是很轻量级的,相对与我们直接创建的对应包装类对象做了许多优化; 也正因为轻量的缘故,这些原始类的功能就比较少(例如我们不能调用其内部的方法,因为他们内部已经优化成没有方法了)
使用实际的例子来说明,为什么我们更应该使用 “原始类型”:
“原始类型”有更快的速度(例如,下面的代码执行,在我们的机器上需要9秒,但当我把 Long 改成 long 之后,0秒内就完成了)
public static void main(String[] args) {
long millis = System.currentTimeMillis();
Long sum = 0L; // uses Long, not long
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
System.out.println((System.currentTimeMillis() - millis) / 1000);
}
“原始类型”允许我们直接使用 “==”来进行比较
new Integer(3) == new Integer(3); // false new Integer(100) == new Integer(100); // false Integer.valueOf(5) == Integer.valueOf(5); //true Integer.valueOf(200) == Integer.valueOf(200); //false
我们注意看第四句,输出结果确实为 “false” 。这个是因在 [-128; 127] 这个区间的265个整数会被 JVM 缓存存放, 所以在这个区间, JVM返回相同的对象;然而,超出这个区间, JVM就不再有缓存了,将会创建新的对象,所以结果是不等的。
所以总结一下是: 在JVM内部,原始类型就是被当作对象来处理的。但是我们开发者直接把 “原始类型” 当作对象使用,开发者应该使用对应的包装来。
以上就是为什么我说 “ Java确实是一个纯粹的面向对象语言 ”的证实过程。如果你们对这个有什么其他的观点,请在评论留言,一起讨论。
译文链接:http://www.codeceo.com/article/why-java-purely-object-oriented-language.html
英文原文:Why Java Is a Purely Object-Oriented Language... Or Why Not
翻译作者:码农网 – Dee1024
[ 转载必须在正文中标注并保留原文链接、译文链接和译者等信息。]
Java到底是不是一种纯面向对象语言?的更多相关文章
- 为什么 Java 不是纯面向对象语言?
什么是纯面向对象语言? 纯面向对象语言或完全面向对象语言是指完全面向对象的语言,它支持或具有将程序内的所有内容视为对象的功能.它不支持原始数据类型(如 int,char,float,bool 等).编 ...
- JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)
1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...
- 188W+程序员关注过的问题:Java到底是值传递还是引用传递?
在逛 Stack Overflow 的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java 到底是值传递还是引用传递?访问量足足有 188万+,这不得了啊!说明有很多很多的程序员被这个 ...
- [转帖]Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递? http://www.itpub.net/2019/12/03/4567/ 在逛 Stack Overfl ...
- 面试官:兄弟,说说Java到底是值传递还是引用传递
二哥,好久没更新面试官系列的文章了啊,真的是把我等着急了,所以特意过来催催.我最近一段时间在找工作,能从二哥的文章中学到一点就多一点信心啊! 说句实在话,离读者 trust you 发给我这段信息已经 ...
- Java到底是解释型还是编译型语言
Java到底是解释型还是编译型语言? 定义 回答这个问题,我们首先来看下概念: 开发人员编写代码,语言是人类可理解的方式,是具有语义的,然而计算机无法理解和执行,因此需要做一层转换. 解释型语言: 运 ...
- Hibernate 系列 07 - Hibernate中Java对象的三种状态
引导目录: Hibernate 系列教程 目录 1. Java对象的三种状态 当应用通过调用Hibernate API与框架发生交互时,需要从持久化的角度关注应用对象的生命周期. 持久化声明周期是Hi ...
- Hibernate中Java对象的三种状态
Hibernate中Java对象的三种 ...
- (转) java定时器的几种用法
package com.lid; import java.util.Calendar; import java.util.Date; import java.util.Timer; import ja ...
随机推荐
- android ListView内数据的动态添加与删除
main.xml 文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns ...
- Uva 12361 File Retrieval 后缀数组+并查集
题意:有F个单词,1 <= F <=60 , 长度<=10^4, 每次可以输入一个字符串,所有包含该字串的单词会形成一个集合. 问最多能形成多少个不同的集合.集合不能为空. 分析:用 ...
- javaweb学习总结(四十三)——Filter高级开发
在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator(装饰器)模式对request.response对象进行包装,再把包装对象传给目 ...
- Pascal Game Development with Jason McMillen
In this much belated episode I talk with Jason McMillen of Pascal Game Development. We discuss the s ...
- net中System.Security.Cryptography 命名空间 下的加密算法
.net中System.Security.Cryptography命名空间 在.NETFramework出现之前,如果我们需要进行加密的话,我们只有各种较底层的技术可以选择,如 Microsoft C ...
- C++文件读写总结
在C++中如何实现文件的读写? 作者: infobillows 发表日期: 2007-04-03 21:33 点击数: 465 一.ASCII 输出 为了使用下面的方法, 你必须包含头文件<fs ...
- Sublime Text 插件 autoprefixer
Sublime Text 早就有插件(Sublime Prefixr)使用 prefixr 的 API 来自动完成 CSS 前缀,但是 autoprefixer 更牛,这款可使用 Can I Use ...
- T型架构观点学习
一.成为T型人才 眼界格局思维要尽可能的开阔,并不断横向开阔,专业能力要尽可能专注,并且纵向上不断加深: 互联网的快速迭代开发和扁平化管理,使单纯管理人才的作用越来越小,除了分配任务和项目管理,在其他 ...
- BrnShop开源网上商城第四讲:自定义插件
重要通知:BrnShop企业版NOSQL设计(基于Redis)已经开源!源码内置于最新版的BrnShop中,感兴趣的园友可以去下载来看看.官网地址:www.brnshop.com. 好了现在进入今天的 ...
- 安卓使用WIFI调试程序
不知怎么回事,USB老是掉,真心烦.于是想着用WIFI可不可以调试呢,去百度一搜,果然可以.下面我说一下我的方案. 1.使用APWIFI创建WIFI热点,用安卓手机连接该热点,试试手机可以上网不. 2 ...