zoukankan      html  css  js  c++  java
  • 一段代码看 Java 引用类型

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

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

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

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

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

     1 public boolean equals(Object anObject) {
     2         if (this == anObject) {
     3             return true;
     4         }
     5         if (anObject instanceof String) {
     6             String anotherString = (String)anObject;
     7             int n = value.length;
     8             if (n == anotherString.value.length) {
     9                 char v1[] = value;
    10                 char v2[] = anotherString.value;
    11                 int i = 0;
    12                 while (n-- != 0) {
    13                     if (v1[i] != v2[i])
    14                         return false;
    15                     i++;
    16                 }
    17                 return true;
    18             }
    19         }
    20         return false;
    21     }

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

    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 中是怎么来操作的。

  • 相关阅读:
    SDNU 1219.sign up problem
    SDNU 1232.A*B Problem(高精度)
    Go操作MySQL
    BootStrap jQuery 在线cdn
    Go语言标准库之http/template
    Go语言基础之net/http
    Go语言基础之网络编程
    Go语言基础之单元测试
    Go语言基础之rand(随机数)包
    Go语言基础之并发
  • 原文地址:https://www.cnblogs.com/pied/p/11008779.html
Copyright © 2011-2022 走看看