Data Types
editData Types
editPainless supports both dynamic and static types. Static types are split into primitive types and reference types.
Dynamic Types
editPainless supports one dynamic type: def
. The def
type can represent any
primitive or reference type. When you use the def
type, it mimics the exact
behavior of whatever type it represents at runtime. The default value for the
def type is null.
Internally, if the def
type represents a primitive type, it is converted to the
corresponding reference type. It still behaves like the primitive type, however,
including within the casting model. The def
type can be assigned to different
types during the course of script execution.
Because a def
type variable can be assigned to different types
during execution, type conversion errors that occur when using the def
type
happen at runtime.
Using the def
type can have a slight impact on performance. If performance is
critical, it’s better to declare static types.
Examples:
def x = 1; // Declare def variable x and set it to the // literal int 1 def l = new ArrayList(); // Declare def variable l and set it a newly // allocated ArrayList
Primitive Types
editPrimitive types are allocated directly onto the stack according to the standard Java memory model.
Primitive types can behave as their corresponding (boxed) reference type. This means any piece of a reference type can be accessed or called through the primitive type. Operations performed in this manner convert the primitive type to its corresponding reference type at runtime and perform the field access or method call without needing to perform any other operations.
Painless supports the following primitive types.
- byte
- An 8-bit, signed, two’s complement integer. Range: [-128, 127]. Default value: 0. Reference type: Byte.
- short
- A 16-bit, signed, two’s complement integer. Range: [-32768, 32767]. Default value: 0. Reference type: Short.
- char
-
A 16-bit Unicode character.
Range: [0, 65535].
Default value: 0 or
\u0000
. Reference type: Character. - int
- A 32-bit, signed, two’s complement integer. Range: [-2^32, 2^32-1]. Default value: 0. Reference type: Integer.
- long
- A 64-bit, signed, two’s complement integer. Range: [-2^64, 2^64-1]. Default value: 0. Reference type: Long.
- float
- A 32-bit, single-precision, IEEE 754 floating point number. Range: Depends on multiple factors. Default value: 0.0. Reference type: Float.
- double
- A 64-bit, double-precision, IEEE 754 floating point number. Range: Depends on multiple factors. Default value: 0.0. Reference type: Double.
- boolean
- A logical quanity with two possible values: true and false. Range: true/false. Default value: false. Reference type: Boolean.
Examples:
int i = 1; // Declare variable i as an int and set it to the // literal 1 double d; // Declare variable d as a double and set it to the // default value of 0.0 boolean b = true; // Declare variable b as a boolean and set it to true
Using methods from the corresponding reference type on a primitive type.
int i = 1; // Declare variable i as an int and set it to the // literal 1 i.toString(); // Invokes the Integer method toString on variable i
Reference Types
editReference types are similar to Java classes and can contain multiple pieces
known as members. However, reference types do not support access modifiers.
You allocate reference type instances on the heap using the new
operator.
Reference types can have both static and non-static members:
-
Static members are shared by all instances of the same reference type and
can be accessed without allocating an instance of the reference type. For
example
Integer.MAX_VALUE
. - Non-static members are specific to an instance of the reference type and can only be accessed through the allocated instance.
The default value for a reference type is null
, indicating that no memory has
been allocated for it. When you assign null
to a reference type, its previous
value is discarded and garbage collected in accordance with the Java memory
model as long as there are no other references to that value.
A reference type can contain:
- Zero to many primitive types. Primitive type members can be static or non-static and read-only or read-write.
- Zero to many reference types. Reference type members can be static or non-static and read-only or read-write.
- Methods that call an internal function to return a value and/or manipulate the primitive or reference type members. Method members can be static or non-static.
- Constructors that call an internal function to return a newly-allocated reference type instance. Constructors are non-static methods that can optionally manipulate the primitive and reference type members.
Reference types support a Java-style inheritance model. Consider types A and B. Type A is considered to be a parent of B, and B a child of A, if B inherits (is able to access as its own) all of A’s fields and methods. Type B is considered a descendant of A if there exists a recursive parent-child relationship from B to A with none to many types in between. In this case, B inherits all of A’s fields and methods along with all of the fields and methods of the types in between. Type B is also considered to be a type A in both relationships.
For the complete list of Painless reference types and their supported methods, see the Painless API Reference.
For more information about working with reference types, see Accessing Fields and Calling Methods.
Examples:
ArrayList al = new ArrayList(); // Declare variable al as an ArrayList and // set it to a newly allocated ArrayList List l = new ArrayList(); // Declare variable l as a List and set // it to a newly allocated ArrayList, which is // allowed because ArrayList inherits from List Map m; // Declare variable m as a Map and set it // to the default value of null
Directly accessing static pieces of a reference type.
Integer.MAX_VALUE // a static field access Long.parseLong("123L") // a static function call
String Type
editA String
is a specialized reference type that is immutable and does not have
to be explicitly allocated. You can directly assign to a String
without first
allocating it with the new
keyword. (Strings can be allocated with the new
keyword, but it’s not required.)
When assigning a value to a String
, you must enclose the text in single or
double quotes. Strings are allocated according to the standard Java Memory Model.
The default value for a String
is null.
Examples:
String r = "some text"; // Declare String r and set it to the // String "some text" String s = 'some text'; // Declare String s and set it to the // String 'some text' String t = new String("some text"); // Declare String t and set it to the // String "some text" String u; // Declare String u and set it to the // default value null
void Type
editThe void
type represents the concept of no type. In Painless, void
declares
that a function has no return value.
Array Type
editArrays contain a series of elements of the same type that can be allocated
simultaneously. Painless supports both single and multi-dimensional arrays for
all types except void (including def
).
You declare an array by specifying a type followed by a series of empty brackets,
where each set of brackets represents a dimension. Declared arrays have a default
value of null
and are themselves a reference type.
To allocate an array, you use the new
keyword followed by the type and a
set of brackets for each dimension. You can explicitly define the size of each dimension by specifying an expression within the brackets, or initialize each
dimension with the desired number of values. The allocated size of each
dimension is its permanent size.
To initialize an array, specify the values you want to initialize
each dimension with as a comma-separated list of expressions enclosed in braces.
For example, new int[] {1, 2, 3}
creates a one-dimensional int
array with a
size of 3 and the values 1, 2, and 3.
When you initialize an array, the order of the expressions is maintained. Each expression used as part of the initialization is converted to the array’s type. An error occurs if the types do not match.
Grammar:
declare_array: TYPE ('[' ']')+; array_initialization: 'new' TYPE '[' ']' '{' expression (',' expression) '}' | 'new' TYPE '[' ']' '{' '}';
Examples:
int[] x = new int[5]; // Declare int array x and assign it a newly // allocated int array with a size of 5 def[][] y = new def[5][5]; // Declare the 2-dimensional def array y and // assign it a newly allocated 2-dimensional // array where both dimensions have a size of 5 int[] x = new int[] {1, 2, 3}; // Declare int array x and set it to an int // array with values 1, 2, 3 and a size of 3 int i = 1; long l = 2L; float f = 3.0F; double d = 4.0; String s = "5"; def[] da = new def[] {i, l, f*d, s}; // Declare def array da and set it to // a def array with a size of 4 and the // values i, l, f*d, and s