类型

编辑

类型是对数据的分类,用于定义值的属性。这些属性指定值表示什么数据以及在 操作 期间如何评估值。每个类型都属于以下类别之一:基本类型引用类型动态类型

基本类型

编辑

基本类型表示 JVM 本身构建的基本数据,并分配到非堆内存中。声明基本类型 变量 或访问基本类型成员字段(来自引用类型实例),并为其分配基本类型值以在后续操作期间进行评估。新声明的基本类型变量的默认值在下面的定义中列出。在赋值或作为方法/函数调用的参数时,会复制基本类型值。

基本类型具有相应的引用类型(也称为装箱类型)。在基本类型值上使用 字段访问运算符方法调用运算符 以强制将其评估为其相应的引用类型值。

以下基本类型可用。相应的引用类型列在括号中。例如,Bytebyte 基本类型的引用类型

可用的基本类型
byte (Byte)
8 位,有符号,二进制补码整数。范围: [-128, 127]。默认值:0
short (Short)
16 位,有符号,二进制补码整数。范围: [-32768, 32767]。默认值:0
char (Character)
16 位,无符号,Unicode 字符。范围: [0, 65535]。默认值:0\u0000
int (Integer)
32 位,有符号,二进制补码整数。范围: [-2^31, 2^31-1]。默认值:0
long (Long)
64 位,有符号,二进制补码整数。范围: [-2^63, 2^63-1]。默认值:0
float (`Float)`
32 位,有符号,单精度,IEEE 754 浮点数。默认值 0.0
double (Double)
64 位,有符号,双精度,IEEE 754 浮点数。默认值:0.0
boolean (Boolean)
逻辑量,具有 truefalse 两个可能的值。默认值:false

示例

  • 在声明和赋值中使用基本类型。

    int i = 1;        
    double d;         
    boolean b = true; 

    声明 int i;将 int 1 存储到 i

    声明 double d;将默认值 double 0.0 存储到 d

    声明 boolean b;将 boolean true 存储到 b

  • 使用相应引用类型对基本类型进行方法调用。

    int i = 1;    
    i.toString(); 

    声明 int i;将 int 1 存储到 i

    i 加载 → int 1;将 int 1 装箱 → Integer 1 引用;对 Integer 1 引用 调用 toStringString '1'

引用类型

编辑

引用类型是命名构造(对象),可能表示多块数据(成员字段)以及操作这些数据的逻辑(成员方法),定义为脚本的应用程序编程接口 (API) 的一部分。

引用类型实例是一组特定引用类型对象的数据,分配到堆中。使用 新建实例运算符 分配引用类型实例。使用引用类型实例来加载、存储和操作复杂数据。

引用类型值引用引用类型实例,多个引用类型值可能引用同一个引用类型实例。对引用类型实例的更改将影响引用该特定实例的所有引用类型值。

声明引用类型 变量 或访问引用类型成员字段(来自引用类型实例),并为其分配引用类型值以在后续操作期间进行评估。新声明的引用类型变量的默认值为 null。在赋值或作为方法/函数调用的参数时,会浅复制引用类型值。将 null 分配给引用类型变量以指示引用类型值不引用任何引用类型实例。当不再有任何引用类型值引用引用类型实例时,JVM 将对其进行垃圾回收。将 null 作为参数传递给方法/函数调用以指示该参数不引用任何引用类型实例。

引用类型对象定义了以下各项中的零到多个

静态成员字段
静态成员字段是命名且类型化的数据片段。每个引用类型 对象 包含一组代表其静态成员字段的数据。使用 字段访问运算符 与引用类型对象名称对应,以访问用于加载和存储到特定引用类型 对象 的静态成员字段。无需分配引用类型实例即可使用静态成员字段。
非静态成员字段
非静态成员字段是命名且类型化的数据片段。每个引用类型 实例 包含一组代表其引用类型对象的非静态成员字段的数据。使用 字段访问运算符 加载和存储到特定引用类型 实例 的非静态成员字段。要使用非静态成员字段,需要分配引用类型实例。
静态成员方法
静态成员方法是在引用类型 对象 上调用的 函数。使用 方法调用运算符 与引用类型对象名称对应,以调用静态成员方法。无需分配引用类型实例即可使用静态成员方法。
非静态成员方法
非静态成员方法是在引用类型 实例 上调用的 函数。在引用类型实例上调用的非静态成员方法可以加载和存储到该特定引用类型实例的非静态成员字段。使用 方法调用运算符 与特定引用类型实例对应,以调用非静态成员方法。要使用非静态成员方法,需要分配引用类型实例。
构造函数
构造函数是一种特殊类型的 函数,用于分配由特定引用类型 对象 定义的引用类型 实例。使用 新建实例运算符 分配引用类型实例。

引用类型对象遵循基本继承模型。考虑类型 A 和 B。如果 B 继承(能够作为自己的成员访问)A 的所有非静态成员,则类型 A 被视为 B 的父类型,B 被视为 A 的子类型。如果从 B 到 A 存在递归的父子关系,并且中间没有到多个类型,则类型 B 被视为 A 的后代。在这种情况下,B 继承 A 的所有非静态成员以及中间类型的非静态成员。在两种关系中,类型 B 也被视为类型 A。

示例

  • 在几个不同的操作中评估引用类型。

    List l = new ArrayList(); 
    l.add(1);                 
    int i = l.get(0) + 2;     

    声明 List l;分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 隐式转换为 List 引用List 引用;将 List 引用 存储到 l

    l 加载 → List 引用;将 int 1 隐式转换为 defdefList 引用 调用 add,参数为 (def)

    声明 int i;从 l 加载 → List 引用;对 List 引用 调用 get,参数为 (int 0) → def;将 def 隐式转换为 int 1int 1;将 int 1int 2 相加 → int 3;将 int 3 存储到 i

  • 共享引用类型实例。

    List l0 = new ArrayList();     
    List l1 = l0;                  
    l0.add(1);                     
    l1.add(2);                     
    int i = l1.get(0) + l0.get(1); 

    声明 List l0;分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 隐式转换为 List 引用List 引用;将 List 引用 存储到 l0

    声明 List l1;从 l0 加载 → List 引用;将 List 引用 存储到 l1(注意 l0l1 引用同一个实例,称为浅复制)

    l0 加载 → List 引用;将 int 1 隐式转换为 defdefList 引用 调用 add,参数为 (def)

    l1 加载 → List 引用;将 int 2 隐式转换为 defdefList 引用 调用 add,参数为 (def)

    声明 int i;从 l0 加载 → List 引用;使用参数 (int 0) 调用 List 引用 上的 get 方法 → def @0;将 def @0 隐式转换为 int 1int 1;从 l1 加载 → List 引用;使用参数 (int 1) 调用 List 引用 上的 get 方法 → def @1;将 def @1 隐式转换为 int 2int 2;将 int 1int 2 相加 → int 3;将 int 3 存储到 i 中;

  • 使用引用类型的静态成员。

    int i = Integer.MAX_VALUE;       
    long l = Long.parseLong("123L"); 

    声明 int i;从 Integer 上的 MAX_VALUE 加载 → int 2147483647;将 int 2147483647 存储到 i

    声明 long l;使用参数 (long 123) 调用 Long 上的 parseLong 方法 → long 123;将 long 123 存储到 l

动态类型

编辑

动态类型值可以使用单个类型名称 def 表示任何基本类型或引用类型的值。 def 类型值模仿它在运行时表示的任何值的的行为,并且在操作期间进行评估时,始终表示任何类型值的子级最深层的后代类型值。

声明一个 def 类型变量或访问一个 def 类型成员字段(来自引用类型实例),并为其分配任何类型的值,以便在后续操作期间进行评估。新声明的 def 类型变量的默认值为 nulldef 类型变量或方法/函数参数可以在脚本的编译和评估期间更改它表示的类型。

使用 def 类型可能会对性能产生轻微影响。当性能至关重要时,请仅直接使用基本类型和引用类型。

错误

  • 如果 def 类型值在运行时表示的操作评估不合适的类型。

示例

  • def 类型的通用用法。

    def dp = 1;               
    def dr = new ArrayList(); 
    dr = dp;                  

    声明 def dp;将 int 1 隐式转换为 defdef;将 def 存储到 dp

    声明 def dr;分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 隐式转换为 defdef;将 def 存储到 dr

    dp 加载 → def;将 def 存储到 dr 中;(注意 dr 表示的类型从 ArrayList 更改为 int

  • def 类型值表示值的子级最深层的后代。

    Object l = new ArrayList(); 
    def d = l;                  
    d.ensureCapacity(10);       

    声明 Object l;分配 ArrayList 实例 → ArrayList 引用;将 ArrayList 引用 隐式转换为 Object 引用Object 引用;将 Object 引用 存储到 l

    声明 def d;从 l 加载 → Object 引用;将 Object 引用 隐式转换为 defdef;将 def 存储到 d 中;

    d 加载 → def;将 def 隐式转换为 ArrayList 引用ArrayList 引用;使用参数 (int 10) 调用 ArrayList 引用 上的 ensureCapacity 方法;(注意 def 被隐式转换为 ArrayList 引用,因为 ArrayList 是 def 类型值表示的子级最深层的后代类型值)

字符串类型

编辑

String 类型是一种专门的引用类型,不需要显式分配。使用字符串字面量直接评估 String 类型值。虽然不是必需的,但新实例运算符可以分配 String 类型实例。

示例

  • String 类型的通用用法。

    String r = "some text";             
    String s = 'some text';             
    String t = new String("some text"); 
    String u;                           

    声明 String r;将 String "some text" 存储到 r

    声明 String s;将 String 'some text' 存储到 s

    声明 String t;使用参数 (String "some text") 分配 String 实例 → String "some text";将 String "some text" 存储到 t

    声明 String u;将默认值 null 存储到 u

void 类型

编辑

void 类型表示类型缺失的概念。使用 void 类型表示函数不返回值。

示例

  • 在函数中使用 void 类型。

    void addToList(List l, def d) {
        l.add(d);
    }

数组类型

编辑

数组类型是一种专门的引用类型,其中数组类型实例包含一系列分配到堆中的值。数组类型实例中的每个值都被定义为一个元素。数组类型实例中的所有元素都具有相同的类型(元素类型),该类型在声明时指定。每个元素在范围 [0, length) 内分配一个索引,其中 length 是为数组类型实例分配的元素总数。

使用新数组运算符数组初始化运算符分配数组类型实例。声明一个数组类型变量或访问一个数组类型成员字段(来自引用类型实例),并为其分配一个数组类型值,以便在后续操作期间进行评估。新声明的数组类型变量的默认值为 null。在赋值或作为方法/函数调用的参数时,数组类型值会被浅拷贝。将 null 分配给数组类型变量以指示数组类型值不引用任何数组类型实例。当不再有任何数组类型值引用数组类型实例时,JVM 将对其进行垃圾回收。将 null 作为参数传递给方法/函数调用以指示该参数不引用任何数组类型实例。

使用数组长度运算符检索数组类型值的长度作为 int 类型值。使用数组访问运算符从数组类型实例中的单个元素加载和存储到其中。

当使用范围 [2, d] 分配多维数组类型实例时,其中 d >= 2,范围 [1, d-1] 中每个维度中的每个元素也是一个数组类型。每个维度 n 的元素类型是一个数组类型,其维度数等于 d-n。例如,考虑具有 3 个维度的 int[][][]。第 3 维 d-3 中的每个元素都是基本类型 int。第 2 维 d-2 中的每个元素都是数组类型 int[]。第 1 维 d-1 中的每个元素都是数组类型 int[][]

示例

  • 一维数组的通用用法。

    int[] x;                   
    float[] y = new float[10]; 
    def z = new float[5];      
    y[9] = 1.0F;               
    z[0] = y[9];               

    声明 int[] x;将默认值 null 存储到 x

    声明 float[] y;使用长度 [10] 分配 1-d float array 实例 → 1-d float array 引用;将 1-d float array 引用 存储到 y

    声明 def z;使用长度 [5] 分配 1-d float array 实例 → 1-d float array 引用;将 1-d float array 引用 隐式转换为 defdef;将 def 存储到 z

    y 加载 → 1-d float array 引用;将 float 1.0 存储到 1-d float array 引用 的索引 [9]

    y 加载 → 1-d float array 引用 @0;从 1-d float array 引用 @0 的索引 [9] 加载 → float 1.0;从 z 加载 → def;将 def 隐式转换为 1-d float array 引用 @11-d float array 引用 @1;将 float 1.0 存储到 1-d float array 引用 @1 的索引 [0]

  • 多维数组的通用用法。

    int[][][] ia3 = new int[2][3][4]; 
    ia3[1][2][3] = 99;                
    int i = ia3[1][2][3];             

    声明 int[][][] ia;使用长度 [2, 3, 4] 分配 3-d int array 实例 → 3-d int array 引用;将 3-d int array 引用 存储到 ia3

    ia3 加载 → 3-d int array 引用;将 int 99 存储到 3-d int array 引用 的索引 [1, 2, 3]

    声明 int i;从 ia3 加载 → 3-d int array 引用;从 3-d int array 引用 的索引 [1, 2, 3] 加载 → int 99;将 int 99 存储到 i