Java 中的操作数(不知道叫什么,相对于 bytecode 而言,类似 CPU 的操作码和操作数)分为值类型和引用类型:

值类型就是直接存储最终数值的,如 char, int, float, double...

引用类型包括了数组,以及其它所有用 class 定义的数据类型,这种数据类型由引用和对象实例连部分组成。

虽然 Java 中一切都是类,但是对于值类型,因为不需要存储其‘对象’特征,所以,编译器只为他们分配了 stack 上的空间,存储单个的值就可以了。而引用类型则不同,他们的变量存储分为两部分:在 stack 中的引用(指针),以及在 heap 中的对象实例。大概长这样(图借别人的,看最后的链接):

使用下面一段代码来理解这个问题,体会下区别(String.equals() 的标准实现)。

 public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

一起从这段代码来看看值类型和引用类型的区别:

1. 第 2 行,首先使用 == 判断,两个引用指向的是否为同一个对象实例。

2. 第 5 行,判断传入的 object 是否是 String 的实例。

3. 第 6 行,将传入的 object 强制转换为 String 类。

4. 第 7、8 行,取 this.value.length 与 anotherString.value.length 作比较。value 的类型是 char[],因为数组是一个有限的数据集合,其定义时就已经固定了长度。所以这个操作被编译后,只是两个内存单元的内容比较。

5. 第 9、10 行,创建新的数组引用,分别指向 this.value 和 anotherString.value。

6. 第 11-16 行,逐个比较两个 char 数组中的元素。直接比较两个数组各个元素的效率,是要比比较 String 元素的效率更高的(转化为 Char 对象的比较,再比较 Char value,显然是要耗费更多资源的...)。

关于数组

数组是 JVM 提供的基本数据类型之一。

JVM 直接提供的数组类型有 T_BOOLEAN([Z, 1byte)、T_CHAR([C, 2bytes)、T_FLOAT([F, 4bytes)、T_DOUBLE([D,8bytes)、T_BYTE([B, 1bytes)、T_SHORT([S, 2bytes)、T_INT([I, 4bytes)、T_LONG([J, 8bytes)。

我们可以轻松验证,一个数组是 instanceof Object,同时,数组调用方法 getClass().getName(),也是可以正确输出的。

public class arrayTest {
public static void main(String[] args) {
int[] a = {1,2,3,4};
System.out.println(a.getClass().getName());
System.out.println("a is instanceof Object? "+(a instanceof Object));
}
}

当然,数组的实现方法是在 JVM 中的,但这并不妨碍我们像使用其它类/对象一样类使用数组。

一个 array 在内存中的 layout 大概长这样:

从上面的图中,可以看到两个信息,第一个,数组在内存中是连续存放的,第二个,header 之后的位置存储着数组的长度。这也是为什么我们可以直接获取数组的 length 属性,而其它一些类,必须使用 length() 方法。

关于 length 存储空间的大小,这个显示是和 JVM 实现有关的。查阅文档发现,sun 的 JVM (java7) 版本:32位系统中 size_t 是4字节的,在64位系统中,size_t 是8字节的。

另外,好奇对象数组是怎样存的,打印了一下 String[] b 的 classNage,显示是“[Ljava.lang.String;”。其中 “[” 表示这是个数组,“L/java/lang.String;” 叫做 JavaNative Interface Field Descriptors,大概就是说这是个 String 类型的数组了。

创建数组的 bytecode 是 JAVA_NEWARRAY 和 JAVA_ANEWARRAY,暂作记录,改天有空再看看 JVM 中是怎么来操作的。

一段代码看 Java 引用类型的更多相关文章

  1. 从一段代码看fork()函数及其引发的竞争

    首先来看一段从<UNIX环境高级编程>中摘录的一段很有意思的代码.借此我们再来谈谈fork()函数的一些问题. #include "apue.h" static voi ...

  2. 一段代码了解Java中char和int的转换

    题目要求: 将输入的大写字母转成对应小写的后5个,如A转换后为f:如果转换后大于z则从a重新计,即多出1就转成a,多出2就转成b以此类推. Java代码: ```java private static ...

  3. c#代码 天气接口 一分钟搞懂你的博客为什么没人看 看完python这段爬虫代码,java流泪了c#沉默了 图片二进制转换与存入数据库相关 C#7.0--引用返回值和引用局部变量 JS直接调用C#后台方法(ajax调用) Linq To Json SqlServer 递归查询

    天气预报的程序.程序并不难. 看到这个需求第一个想法就是只要找到合适天气预报接口一切都是小意思,说干就干,立马跟学生沟通价格. ​ ​不过谈报价的过程中,差点没让我一口老血喷键盘上,话说我们程序猿的人 ...

  4. java中 synchronized 的使用,确保异步执行某一段代码。

    最近看了个有关访问网络url和下载的例子,里面有几个synchronized的地方,系统学习下,以下内容很重要,记下来. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一 ...

  5. 从JVM的角度看JAVA代码--代码优化

    从JVM的角度看JAVA代码–代码优化 从JVM的角度看JAVA代码代码优化 片段一反复计算 片段二反复比較 在JVM载入优化为class文件,运行class文件时,会有JIT(Just-In-Tim ...

  6. 127个常用的JS代码片段,每段代码花30秒就能看懂(上)

    127个常用的JS代码片段,每段代码花30秒就能看懂(上) JavaScript 是目前最流行的编程语言之一,正如大多数人所说:“如果你想学一门编程语言,请学JavaScript.” FreeCode ...

  7. 编写高质量代码:改善Java程序的151个建议(第8章:异常___建议114~117)

    建议114:不要在构造函数中抛出异常 Java异常的机制有三种: Error类及其子类表示的是错误,它是不需要程序员处理也不能处理的异常,比如VirtualMachineError虚拟机错误,Thre ...

  8. 编写高质量代码:改善Java程序的151个建议(第6章:枚举和注解___建议88~92)

    建议88:用枚举实现工厂方法模式更简洁 工厂方法模式(Factory Method Pattern)是" 创建对象的接口,让子类决定实例化哪一个类,并使一个类的实例化延迟到其它子类" ...

  9. 编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议47~51)

    建议47:在equals中使用getClass进行类型判断 本节我们继续讨论覆写equals的问题,这次我们编写一个员工Employee类继承Person类,这很正常,员工也是人嘛,而且在JavaBe ...

随机推荐

  1. 《linux就该这么学》课堂笔记14 Apache、SELinux、虚拟主机

    1.目前能够提供Web网络服务的程序有IIS(Windows系统中默认的Web服务程序,是一款图形化的网站管理工具).Nginx和Apache(RHEL 7系统中默认的Web服务程序)等. Apach ...

  2. 绘制指引线的JS库leader-line

    前言 之前看到一篇推荐Magi这个搜索引擎的新闻,对于这个搜索引擎是否好用咱们不予置评,但是我在这个搜索引擎上面发现了一个好玩的前端功能. 如上图,将鼠标浮动到学习来源上时,会展示一堆指引线. 本博客 ...

  3. mysql解析binlog日志

    binlog日志用于记录所有更新了数据或者已经潜在更新了数据(例如,没有匹配任何行的一个DELETE)的所有语句.语句以“事件”的形式保存,它描述数据更改.因为有了数据更新的binlog,所以可以用于 ...

  4. JS中把其他类型转换成字符串的三种方法

    1.toString()方法 toString()方法返回的是相应值的字符串表现 数值.布尔值.对象和字符串值都有toString()方法,但是null和undefined值没有这个方法 例子: va ...

  5. OpenCV 学习笔记(13)图像转换成视频

    关键 1参数里的分辨率是图像本身的分辨率,而不是指定生成的视频分辨率.如果要修改分辨率,要么后期软件处理,要么读图的时候resize 2要正常退出,不要强制退出. 3生成的只能是avi格式. #inc ...

  6. java读取HDFS压缩文件乱码

    java通过调用HDFS系统的FileSystem等API 直接读取HDFS的压缩文件会产生乱码 解决方法: 1.调用解码的API,解码后通过IO流处理. public static void mai ...

  7. Q1094

    一,看题 1,字符串确实是我的弱项. 2, 二,看题解 #include<iostream> #include<string> using namespace std; int ...

  8. nexus pip proxy config

    nexus pip proxy config config for linux touch config touch ~/.pip/pip.conf content [global] index-ur ...

  9. 如何使用离线存储(localStorage)?

    1.存储数据:localStorage.setItem("属性","属性值") 2.获取本地存储的值:localStorage.getItem("属性 ...

  10. 一步一步编写AVL树

    第一步:定义结构体 typedef struct Node{ int d; //data ; //height struct Node* l=NULL; struct Node* r=NULL; No ...