Contents | Prev | Next | Index | The JavaTM Virtual Machine Specification |
CHAPTER 2
The Java Virtual Machine was designed to support the Java programming language. Some concepts and vocabulary from the Java language are thus necessary to understand the virtual machine. This chapter gives enough of an overview of Java to support the discussion of the Java Virtual Machine to follow. Its material has been condensed from The Java Language Specification, by James Gosling, Bill Joy, and Guy Steele. For a complete discussion of the Java language, or for details and examples of the material in this chapter, refer to that book. Readers familiar with that book may wish to skip this chapter. Readers familiar with Java, but not with The Java Language Specification, should at least skim this chapter for the terminology it introduces.
This chapter does not attempt to provide an introduction to or a full treatment of the Java language. For an introduction to Java, see The Java Programming Language, by Ken Arnold and James Gosling.
ftp://unicode.org
. There
are a few minor errors in this update information; refer to The Java Language
Specification for corrections. Updates to the Unicode information published there
will be posted under the URL http://java.sun.com/docs/books/index.html
.
Except for comments and identifiers (§2.2) and the contents of character and string literals (§2.3), all input elements in a Java program are formed from only ASCII characters. ASCII (ANSI X3.4) is the American Standard Code for Information Interchange. The first 128 characters of the Unicode character encoding are the ASCII characters.
The Java method Character.isJavaLetter
returns true
when passed a Unicode character that is considered to be a letter in Java identifiers. The Java method Character.isJavaLetterOrDigit
returns true
when passed a Unicode character that is considered to be a letter or digit in Java identifiers.
Two identifiers are the same only if they have the same Unicode character for each letter or digit; identifiers that have the same external appearance may still be different. An identifier must not be the same as a Java keyword or a boolean literal (true or
false
).
String
type (§2.4.7), or the null type (§2.4). String literals and, more generally, strings that are the values of constant expressions, are "interned" so as to
share unique instances, using the method String.intern
.
The null type has one value, the null reference, denoted by the literal null
.
The boolean
type has two values, denoted by the literals true
and false
.
The types of the Java language are divided into two categories: primitive types (§2.4.1) and reference types (§2.4.5). There is also a special null type, the type of the expression null
, which has no name. The null reference is the only possible value of an expression of null type, and can always be converted to any reference type. In practice, the Java programmer can ignore the null type and just pretend that null
is a special literal that can be of any reference type.
Corresponding to the primitive types and reference types, there are two categories of data values that can be stored in variables, passed as arguments, returned by methods, and operated upon: primitive values (§2.4.1) and reference values (§2.4.5).
The primitive types are the boolean
type and the numeric types. The numeric types are the integral types and the floating-point types.
The integral types are byte
, short
, int
, and long
, whose values are 8-bit, 16-bit, 32-bit, and 64-bit signed two's-complement integers, respectively, and char
, whose values are 16-bit unsigned integers representing Unicode characters (§2.1).
The floating-point types are float
, whose values are 32-bit IEEE 754 floating-point numbers, and double
, whose values are 64-bit IEEE 754 floating-point numbers as specified in IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Standard 754-1985 (IEEE, New York). The IEEE 754 standard includes not only positive and negative sign-magnitude numbers, but also positive and negative zeroes, positive and negative infinities, and a special Not-a-Number (hereafter abbreviated NaN) value. The NaN value is used to represent the result of certain operations such as dividing zero by zero.
The boolean
type has the truth values true
and false
.
boolean
), arithmetic operators, increment and decrement, bitwise logical and shift operators, and numeric cast (§2.6.8).
Operands of certain unary and binary operators are subject to numeric promotion (§2.6.9).
The built-in integer operators do not indicate overflow or underflow in any way; they wrap around on overflow or underflow. The only integer operators that can throw an exception are the integer divide and integer remainder operators, which can throw an ArithmeticException
if the right-hand operand is zero.
Any value of any integral type may be cast to or from any numeric type. There are no casts between integral types and the type boolean
.
boolean
), arithmetic
operators, increment and decrement, and numeric cast (§2.6.8).
If at least one of the operands to a binary operator is of floating-point type, then the operation is a floating-point operation, even if the other operand is integral. Operands of certain unary and binary operators are subject to numeric promotion (§2.6.9).
Operators on floating-point numbers behave exactly as specified by IEEE 754. In particular, Java requires support of IEEE 754 denormalized floating-point numbers and gradual underflow, which make it easier to prove desirable properties of particular numerical algorithms.
Java requires that floating-point arithmetic behave as if every floating-point operator rounded its floating-point result to the result precision. Inexact results must be rounded to the representable value nearest to the infinitely precise result; if the two nearest representable values are equally near, the one with its least significant bit zero is chosen. This is the IEEE 754 standard's default rounding mode known as round-to-nearest.
Java uses round-towards-zero mode when converting a floating-point value to an integer (§2.6.3). Round-towards-zero mode acts as though the number were truncated, discarding the mantissa bits. Round-towards-zero chooses as its result the format's value closest to and no greater in magnitude than the infinitely precise result.
Java floating-point operators produce no exceptions (§2.15). An operation that overflows produces a signed infinity; an operation that underflows produces a signed zero; and an operation that has no mathematically definite result produces NaN. All numeric operations (except for numeric comparison) with
NaN as an operand produce
NaN as a result.
Any value of any floating-point type may be cast (§2.6.8) to or from any numeric type. There are no casts between floating-point types and the type boolean
.
boolean
Values boolean
expressions can be used in Java's control flow statements and as the first
operand of the conditional operator ?:
. An integral value x
can be converted to a
value of type boolean
, following the C language convention that any nonzero
value is true
, by the expression x!=0
. An object reference obj
can be converted
to a value of type boolean
, following the C language convention that any reference other than null
is true
, by the expression obj!=null
.
There are no casts between the type boolean
and any other type.
A class instance is explicitly created by a class instance creation expression, or by invoking the newInstance
method of class Class
. An array is explicitly created by an array creation expression. An object is created in the Java heap, and is garbage collected after there are no more references to it. Objects are never reclaimed or freed by explicit Java language directives.
There may be many references to the same object. Most objects have state, stored in the fields of objects that are instances of classes or in the variables that are the components of an array object. If two variables contain references to the same object, the state of the object can be modified using one variable's reference to the object, and then the altered state can be observed through the other variable's reference.
Each object has an associated lock (§2.17, §8.13) that is used by synchronized
methods and by the synchronized
statement to provide control over concurrent access to state by multiple threads (§2.17, §8.12).
Reference types form a hierarchy. Each class type is a subclass of another class type, except for the class Object
(§2.4.6), which is the superclass (§2.8.3) of all other class types. All objects, including arrays, support the methods of class Object
. String literals (§2.3) are references to instances of class String
(§2.4.7).
Object
Object
is the superclass (§2.8.3) of all other classes. A variable of type Object
can hold a reference to any object, whether it is an instance of
a class or an array. All class and array types inherit the methods of class Object
.
String
String
represent sequences of Unicode characters (§2.1). A
String
object has a constant, unchanging value. String literals (§2.3) are references to instances of class String
.
instanceof
, and the conditional operator ?:
.
Compatibility of the value of a variable with its type is guaranteed by the design of the Java language because default values (§2.5.1) are compatible and all assignments to a variable are checked, at compile time, for assignment compatibility.
There are seven kinds of variables:
static
(§2.9.1) within a class declaration, or with or without the keyword static
in an interface declaration. Class variables are created when the class or interface is loaded (§2.16.2) and are initialized on creation to default values (§2.5.1). The class variable effectively ceases to exist when its class or interface is unloaded (§2.16.8) after any necessary finalization of the class (§2.16.8) has been completed.
static
(§2.9.1). If a class T has a field a that is an instance variable, then a new instance variable a is created and initialized to a default value (§2.5.1) as part of each newly created object of class T or of any class that is a subclass of T. The instance variable effectively ceases to exist when the object of which it is a field is no longer referenced, after any necessary finalization of the object (§2.16.7) has been completed.
catch
clause of a try
statement (§2.15.2). The new variable is initialized with the actual object associated with the exception (§2.15.3). The exception-handler parameter effectively ceases to exist when execution of the block associated with the catch
clause (§2.15.2) is complete.
for
statement, a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block or for
statement. The local variable is not initialized, however, until the local variable declaration statement that declares it is executed. The local variable effectively ceases to exist when the execution of the block or for
statement is complete.
byte
, the default value is zero, that is, the value of (byte)0
.
short
, the default value is zero, that is, the value of (short)0
.
int
, the default value is zero, that is, 0
.
long
, the default value is zero, that is, 0L
.
float
, the default value is positive zero, that is, 0.0f
.
double
, the default value is positive zero, that is, 0.0d
.
char
, the default value is the null character, that is, 'u0000'
.
boolean
, the default value is false
.
null
(§2.3).
newInstance
method to produce the
object. This class is called the class of the object. An object is said to be an
instance of its class and of all superclasses of its class. Sometimes the class of an
object is called its "runtime type," but "class" is the more accurate term.
(Sometimes a variable or expression is said to have a "runtime type," but that is an abuse of terminology; it refers to the class of the object referred to by the value of the variable or expression at run time, assuming that the value is not null
. Properly speaking, type is a compile-time notion. A variable or expression has a type; an object or array has no type, but belongs to a class.)
The type of a variable is always declared, and the type of an expression can be deduced at compile time. The type limits the possible values that the variable can hold or the expression can produce at run time. If a runtime value is a reference that is not null
, it refers to an object or array that has a class (not a type), and that class will necessarily be compatible with the compile-time type.
Even though a variable or expression may have a compile-time type that is an interface type, there are no instances of interfaces (§2.13). A variable or expression whose type is an interface type can reference any object whose class implements that interface.
Every array also has a class. The classes for arrays have strange names that are not valid Java identifiers; for example, the class for an array of int
components has the name "[I"
.
Numeric promotions are conversions that change an operand of a numeric operation to a wider type, or both operands of a numeric operation to a common type, so that an operation can be performed.
In Java, there are six broad kinds of conversions:
String
(§2.4.7).
+
operator when one of the arguments is a String
; it will not be covered further. byte
to short
, int
, long
, float
, or double
short
to int
, long
, float
, or double
char
to int
, long
, float
, or double
int
to long
, float
, or double
long
to float
or double
float
to double
float
to double
do not lose any information at all; the numeric value is preserved exactly. Conversion of an int
or a long
value to float
, or of a long
value to double
, may lose precision, that is, the result may lose some of the least significant bits of the value; the resulting floating-point value is a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode (§2.4.3).
According to this rule, a widening conversion of a signed integer value to an integral type simply sign-extends the two's-complement representation of the integer value to fill the wider format. A widening conversion of a value of type char
to an integral type zero-extends the representation of the character value to fill the wider format.
Despite the fact that loss of precision may occur, widening conversions among primitive types never result in a runtime exception (§2.15).
byte
to char
short
to byte
or char
char
to byte
or short
int
to byte
, short
, or char
long
to byte
, short
, char
, or int
float
to byte
, short
, char
, int
, or long
double
to byte
, short
, char
, int
, long
, or float
int
value 32763
to type byte
produces the value -5
). Narrowing conversions may also lose precision.A narrowing conversion of a signed integer to an integral type simply discards all but the n lowest-order bits, where n is the number of bits used to represent the type. This may cause the resulting value to have a different sign than the input value.
A narrowing conversion of a character to an integral type likewise simply discards all but the n lowest bits, where n is the number of bits used to represent the type. This may cause the resulting value to be a negative number, even though characters represent 16-bit unsigned integer values.
In a narrowing conversion of a floating-point number to an integral type, if the floating-point number is NaN, the result of the conversion is
0
of the appropriate type. If the floating-point number is too large to be represented by the integral type, or is positive infinity, the result is the largest representable value of the integral type. If the floating-point number is too small to be represented, or is negative infinity, the result is the smallest representable value of the integral type. Otherwise, the result is the floating-point number rounded towards zero to an integer value using IEEE 754 round-towards-zero mode (§2.4.3)
A narrowing conversion from double
to float
behaves in accordance with IEEE 754. The result is correctly rounded using IEEE 754 round-to-nearest mode (§2.4.3). A value too small to be represented as a float
is converted to a positive or negative zero; a value too large to be represented as a float
is converted to a positive or negative infinity. A double
NaN is always converted to a
float
NaN.
Despite the fact that overflow, underflow, or loss of precision may occur, narrowing conversions among primitive types never result in a runtime exception.
Object
to any other class type.)
final
and does not implement K. (An important special case is that there is a narrowing conversion from the class type Object
to any interface type.)
Object
to any array type.
Object
to any interface type.
final
.
final
, provided that T implements J.
[]
to any array type TC[]
, provided that SC and TC are reference types and there is a permitted narrowing conversion from SC to TC.
ClassCastException
.
int
.
byte
, short
, or char
.
An assignment conversion never causes an exception. A value of primitive type must not be assigned to a variable of reference type. A value of reference type must not be assigned to a variable of primitive type. A value of type boolean
can be assigned only to a variable to type boolean
. A value of the null type may be assigned to any reference type.
Assignment of a value of compile-time reference type S (source) to a variable of compile-time reference type T (target) is permitted:
Object
.
[]
, that is, an array of components of type SC:
Object
.
Cloneable
.
[]
, array of components of type TC, then either
Casting can convert a value of any numeric type to any other numeric type. A value of type boolean
cannot be cast to another type. A value of reference type cannot be cast to a value of primitive type.
Some casts can be proven incorrect at compile time and result in a compile-time error. Otherwise, either the cast can be proven correct at compile time, or a runtime validity check is required. (See The Java Language Specification for details.) If the value at run time is a null reference, then the cast is allowed. If the check at run time fails, a ClassCastException
is thrown.
Numeric promotions are used to convert the operands of a numeric operator to a common type where an operation can be performed. The two kinds of numeric promotion are unary numeric promotion and binary numeric promotion. The analogous conversions in C are called "the usual unary conversions" and "the usual binary conversions." Numeric promotion is not a general feature of Java, but rather a property of the specific definitions of built-in operators.
An operator that applies unary numeric promotion to a single operand of numeric type converts an operand of type byte
, short
, or char
to int
, and otherwise leaves the operand alone. The operands of the shift operators are promoted independently using unary numeric promotions.
When an operator applies binary numeric promotion to a pair of numeric operands, the following rules apply, in order, using widening conversion (§2.6.2) to convert operands as necessary:
double
, the other is converted to double
.
float
, the other is converted to float
.
long
, the other is converted to long
.
int
.
A simple name is a single identifier (§2.2). Qualified names provide access to members of packages and reference types. A qualified name (§2.7.8) consists of a name, a "." token, and an identifier.
Not all identifiers in Java programs are part of a name. Identifiers are also used in declarations, where the identifier determines the name by which an entity will be known, in field access expressions and method invocation expressions, and in statement labels and break
and continue
statements which refer to statement labels.
Each Java host determines how packages, compilation units, and subpackages are created and stored; which top-level package names are in scope in a particular compilation; and which packages are accessible. Packages may be stored in a local file system, in a distributed file system, or in some form of database.
A package name component or class name might contain a character that cannot legally appear in a host file system's ordinary directory or file name: for instance, a Unicode character on a system that allows only ASCII characters in file names.
A Java system must support at least one unnamed package; it may support more than one unnamed package but is not required to do so. Which compilation units are in each unnamed package is determined by the host system. Unnamed packages are provided by Java principally for convenience when developing small or temporary applications or when just beginning development.
An import
declaration allows a type declared in another package to be known by a simple name rather than by the fully qualified name (§2.7.9) of the type. An import declaration affects only the type declarations of a single compilation unit. A compilation unit automatically imports each of the public
type names declared in the predefined package java.lang
.
In general, the subpackages of a package are determined by the host system. However, the standard package java
always has the subpackages lang
, util
, io
, and net
. No two distinct members of the same package may have the same simple name (§2.7.1), but members of different packages may have the same simple name.
A class type may have two or more methods with the same simple name if they have different numbers of parameters or different parameter types in at least one parameter position. Such a method member name is said to be overloaded. A class type may contain a declaration for a method with the same name and the same signature as a method that would otherwise be inherited from a superclass or superinterface. In this case, the method of the superclass or superinterface is not inherited. If the method not inherited is abstract
, the new declaration is said to implement it; if it is not abstract
, the new declaration is said to override it.
Object
(§2.4.6), and the field length
, which is a constant (final
)
field of every array.
Java provides mechanisms for limiting qualified access, to prevent users of a package or class from depending on unnecessary details of the implementation of that package or class. Access control also applies to constructors.
Whether a package is accessible is determined by the host system.
A class or interface may be declared public
, in which case it may be accessed, using a qualified name, by any Java code that can access the package in which it is declared. A class or interface that is not declared public
may be accessed from, and only from, anywhere in the package in which it is declared.
Every field or method of an interface must be public
. Every member of a public
interface is implicitly public
, whether or not the keyword public
appears in its declaration. If an interface is not public
, then every one of its fields and methods must be explicitly declared public
. It follows that a member of an interface is accessible if and only if the interface itself is accessible.
A field, method, or constructor of a class may be declared using at most one of the public
, private
, or protected
keywords. A public
member may be accessed by any Java code. A private
member may be accessed only from within the class that contains its declaration. A member that is not declared public
, protected
, or private
is said to have default access and may be accessed from, and only from, anywhere in the package in which it is declared.
A protected
member of an object may be accessed only by code responsible for the implementation of that object. To be precise, a protected
member may be accessed from anywhere in the package in which it is declared and, in addition, it may be accessed from within any declaration of a subclass of the class type that contains its declaration, provided that certain restrictions are obeyed.
boolean
, char
, byte
, short
, int
, long
, float
, or double
.
.
" followed by the simple (member) name of the subpackage.
.
" followed by the simple name of the class or interface.
[]
".
The body of a class declares members (fields and methods), static initializers, and constructors.
.
Identifier. If the class is in an unnamed package, then the class has the fully qualified name Identifier.
Two classes are the same class (and therefore the same type) if they are loaded by the same class loader (§2.16.2) and they have the same fully qualified name (§2.7.9).
public
,
as discussed in §2.7.8.
An abstract
class is a class which is incomplete, or considered incomplete. Only abstract
classes may have abstract
methods (§2.10.3), that is, methods which are declared but not yet implemented.
A class can be declared final
if its definition is complete and no subclasses are desired or required. Because a final
class never has any subclasses, the methods of a final
class cannot be overridden in a subclass. A class cannot be both final
and abstract
, because the implementation of such a class could never be completed.
A class is declared public
to make its type available to packages other than the one in which it is declared. A public
class is accessible from other packages, using either its fully qualified name or a shorter name created by an import
declaration (§2.7.2), whenever the host permits access to its package. If a class lacks the public
modifier, access to the class declaration is limited to the package in which it is declared.
extends
clause in a class declaration specifies the direct superclass
of the current class, the class from whose implementation the implementation of
the current class is derived. A class is said to be a direct subclass of the class it
extends
. Only the class Object
(§2.4.6) has no direct superclass. If the extends
clause is omitted from a class declaration, then the superclass of the new class is
Object
.
The subclass relationship is the transitive closure of the direct subclass relationship. A class A is a subclass of a class C if A is a direct subclass of C, or if there is a direct subclass B of C and class A is a subclass of B. Class A is said to be a superclass of class C whenever C is a subclass of A.
Object
, which has no direct superclass.
private
are not inherited by subclasses of that class. Members of a class that are not declared private
, protected
, or public
are not inherited by subclasses declared in a package other than the one in which the class is declared. Constructors (§2.12) and static initializers (§2.11) are not members and therefore are not inherited.static
) variables exist once per
class. Instance variables exist once per instance of the class. Fields may include
initializers and may be modified using various modifier keywords.
If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in the superclasses and superinterfaces of the class. A class inherits from its direct superclass and direct superinterfaces all the fields of the superclass and superinterfaces that are accessible to code in the class and are not hidden by a declaration in the class. A hidden field can be accessed by using a qualified name (if it is static
) or by using a field access expression that contains a cast to a superclass type or the keyword super
.
public
, protected
, or private
, as discussed in §2.7.8.
If a field is declared static
, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static
field, sometimes called a class variable, is incarnated when the class is initialized (§2.16.4).
A field that is not declared static
is called an instance variable. Whenever a new instance of a class is created, a new variable associated with that instance is created for every instance variable declared in that class or in any of its superclasses.
A field can be declared final
, in which case its declarator must include a variable initializer (§2.9.2). Both class and instance variables (static
and non-static
fields) may be declared final
. Once a final
field has been initialized, it always contains the same value. If a final
field holds a reference to an object, then the state of the object may be changed by operations on the object, but the field will always refer to the same object.
Variables may be marked transient
to indicate that they are not part of the persistent state of an object. The transient
attribute can be used by a Java implementation to support special system services. The Java Language Specification does not yet specify details of such services.
The Java language allows threads that access shared variables to keep private working copies of the variables; this allows a more efficient implementation of multiple threads (§2.17). These working copies need be reconciled with the master copies in the shared main memory only at prescribed synchronization points, namely when objects are locked or unlocked (§2.17). As a rule, to ensure that shared variables are consistently and reliably updated, a thread should ensure that it has exclusive access to such variables by obtaining a lock that conventionally enforces mutual exclusion for those shared variables.
Java provides a second mechanism that is more convenient for some purposes: a field may be declared volatile
, in which case a thread must reconcile its working copy of the field with the master copy every time it accesses the variable. Moreover, operations on the master copies of one or more volatile variables on behalf of a thread are performed by the main memory in exactly the order that the thread requested. A final
field cannot also be declared volatile
.
static
field), then the variable initializer is evaluated and the assignment performed exactly once, when the class is initialized (§2.16.4).
static
), then the variable initializer is evaluated and the assignment performed each time an instance of the class is created.
super
keyword.
public
, protected
, and private
are discussed in §2.7.8.
An abstract
method declaration introduces the method as a member, providing its signature (§2.10.2), return type, and throws
clause (if any), but does not provide an implementation. The declaration of an abstract
method m must appear within an abstract
class (call it A). Every subclass of A that is not itself abstract
must provide an implementation for m. A method declared abstract
cannot also be declared private
, static
, final
, native
, or synchronized
.
A method that is declared static
is called a class method. A class method is always invoked without reference to a particular object. A class method may refer to other fields and methods of the class by simple name only if they are class methods and class (static
) variables.
A method that is not declared static
is an instance method. An instance method is always invoked with respect to an object, which becomes the current object to which the keywords this
and super
refer during execution of the method body.
A method can be declared final
to prevent subclasses from overriding or hiding it. A private
method and all methods declared in a final
class (§2.8.2) are implicitly final
, because it is impossible to override them. If a method is final
or implicitly final
, a compiler or a runtime code generator can safely "inline" the body of a final
method, replacing an invocation of the method with the code in its body.
A synchronized
method will acquire a monitor lock (§2.17) before it executes. For a class (static
) method, the lock associated with the class object for the method's class is used. For an instance method, the lock associated with this
(the object for which the method is invoked) is used. The same per-object lock is used by the synchronized
statement.
A method can be declared native
to indicate that it is implemented in platform-dependent code, typically written in another programming language such as C, C++, or assembly language.
The static initializers and class variable initializers are executed in textual order. They may not refer to class variables declared in the class whose declarations appear textually after the use, even though these class variables are in scope. This restriction is designed to catch, at compile time, most circular or otherwise malformed initializations.
+
, and
by explicit constructor invocations from other constructors; they are never invoked
by method invocation expressions.
Access to and inheritance of constructors are governed by the access modifiers public
, protected
, and private
(§2.7.8). Constructor declarations are not members. They are never inherited and therefore are not subject to hiding or overriding.
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object
, then the constructor body is implicitly assumed by the compiler to begin with a superclass constructor invocation "super();
", an invocation of the constructor of its direct superclass that takes no arguments.
If a class declares no constructors, then a default constructor which takes no arguments is automatically provided. If the class being declared is Object
, then the default constructor has an empty body. Otherwise, the default constructor takes no arguments and simply invokes the superclass constructor with no arguments. If the class is declared public
, then the default constructor is implicitly given the access modifier public
. Otherwise, the default constructor has the default access implied by no access modifier (§2.7.8).
A class can be designed to prevent code outside the class declaration from creating instances of the class by declaring at least one constructor, to prevent the creation of an implicit constructor, and declaring all constructors to be private
.
abstract
methods. This type has no implementation, but otherwise unrelated classes can
implement it by providing implementations for its abstract
methods. Java programs can use interfaces to make it unnecessary for related classes to share a common abstract
superclass or to add methods to Object
.
An interface may be declared to be a direct extension of one or more other interfaces, meaning that it implicitly specifies all the abstract
methods and constants of the interfaces it extends, except for any constants that it may hide, and perhaps adding newly declared members of its own.
A class may be declared to directly implement one or more interfaces, meaning that any instance of the class implements all the abstract
methods specified by that interface. A class necessarily implements all the interfaces that its direct superclasses and direct superinterfaces do. This (multiple) interface inheritance allows objects to support (multiple) common behaviors without sharing any implementation.
A variable whose declared type is an interface type may have as its value a reference to an object that is an instance of any class that is declared to implement the specified interface. It is not sufficient that the class happens to implement all the abstract
methods of the interface; the class or one of its superclasses must actually be declared to implement the interface, or else the class is not considered to implement the interface.
public
and
abstract
. The access modifier public
is discussed in (§2.7.8). Every interface is
implicitly abstract
. All members of interfaces are implicitly public
.
An interface cannot be final
, because the implementation of such a class could never be completed.
extends
clause is provided, then the interface being declared extends each
of the other named interfaces, and therefore inherits the methods and constants of
each of the other named interfaces. Any class that implements
the declared interface is also considered to implement all the interfaces that this interface extends
and that are accessible to the class.
The implements
clause in a class declaration lists the names of interfaces that are direct superinterfaces of the class being declared. All interfaces in the current package are accessible. Interfaces in other packages are accessible if the host system permits access to the package and the interface is declared public
.
An interface type K is a superinterface of class type C if K is a direct superinterface of C; or if C has a direct superinterface J that has K as a superinterface; or if K is a superinterface of the direct superclass of C. A class is said to implement all its superinterfaces.
There is no analogue of the class Object
for interfaces; that is, while every class is an extension of class Object
, there is no single interface of which all interfaces are extensions.
Interface members are either fields or methods.
static
and final
.
Interfaces do not have instance variables. Every field declaration in an interface is
itself implicitly public
. A constant declaration in an interface must not include
either of the modifiers transient
or volatile
.
Every field in the body of an interface must have an initialization expression, which need not be a constant expression. The variable initializer is evaluated and the assignment performed exactly once, when the interface is initialized (§2.16.4).
abstract
.
Every method declaration in the body of an interface is implicitly public
.
A method declared in an interface must not be declared static
, because in Java static
methods cannot be abstract
. A method declared in the body of an interface must not be declared native
or synchronized
, because those keywords describe implementation properties rather than interface properties; however, a method declared in an interface may be implemented by a method that is declared native
or synchronized
in a class that implements the interface. A method declared in the body of an interface must not be declared final
; however, one may be implemented by a method that is declared final
in a class that implements the interface.
An interface inherits from its direct superinterfaces all methods of the superinterfaces that are not overridden by a declaration in the interface.
If two methods of an interface (whether both declared in the same interface, or both inherited by an interface, or one declared and one inherited) have the same name but different signatures, then the method name is said to be overloaded.
Object
(§2.4.6). All methods of class Object
may be invoked on an array.
An array object contains a number of variables. That number may be zero, in which case the array is said to be empty. The variables contained in an array have no names; instead they are referenced by array access expressions that use non-negative integer index values. These variables are called the components of the array. If an array has n components, we say n is the length of the array.
An array of zero components is not the same as the null reference (§2.4).
[]
.
The component type of an array may itself be an array type. The components of such an array may contain references to subarrays. If, starting from any array type, one considers its component type, and then (if that is also an array type) the component type of that type, and so on, eventually one must reach a component type that is not an array type; this is called the element type of the original array, and the components at this level of the data structure are called the elements of the original array.
There is one situation in which an element of an array can be an array: if the element type is Object
(§2.4.6), then some or all of the elements may be arrays, because every array object can be assigned to a variable of type Object
.
In Java, unlike C, an array of char
is not a String
(§2.4.6), and neither a String
nor an array of char
is terminated by 'u0000'
(the NUL
-character). A Java String
object is immutable (its value never changes), while an array of char
has mutable elements.
The element type of an array may be any type, whether primitive or reference. In particular, arrays with an interface type as the component type are supported; the elements of such an array may have as their value a null reference or instances of any class type that implements the interface. Arrays with an abstract
class type as the component type are supported; the elements of such an array may have as their value a null reference or instances of any subclass of this abstract
class that is not itself abstract
.
Because an array's length is not part of its type, a single variable of array type may contain references to arrays of different lengths. Once an array object is created, its length never changes. To make an array variable refer to an array of different length, a reference to a different array must be assigned to the variable.
If an array variable v has type A[]
, where A is a reference type, then v can hold a reference to any array type B[]
, provided B can be assigned to A (§2.6.6).
int
values; short
, byte
, or char
values may also be used as
they are subjected to unary numeric promotion (§2.6.9) and become int
values.
All arrays are 0-origin. An array with length n can be indexed by the integers 0 through n - 1. All array accesses are checked at run time; an attempt to use an index that is less than zero or greater than or equal to the length of the array causes an ArrayIndexOutOf-Bounds---Exception
to be thrown.
Java programs can also throw exceptions explicitly, using throw
statements. This provides an alternative to the old-fashioned style of handling error conditions by returning distinguished error values, such as the integer value -1
, where a negative value would not normally be expected.
Every exception is represented by an instance of the class Throwable
or one of its subclasses; such an object can be used to carry information from the point at which an exception occurs to the handler that catches it. Handlers are established by catch
clauses of try
statements. During the process of throwing an exception, a Java Virtual Machine abruptly completes, one by one, any expressions, statements, method and constructor invocations, static initializers, and field initialization expressions that have begun but not completed execution in the current thread. This process continues until a handler is found that indicates that it handles the thrown exception by naming the class of the exception or a superclass of the class of the exception. If no such handler is found, then the method uncaught-Exception
is invoked for the ThreadGroup
that is the parent of the current thread.
The Java exception mechanism is integrated with the Java synchronization model (§2.17), so that locks are properly released as synchronized
statements and invocations of synchronized
methods complete abruptly.
The specific exceptions covered in this section are that subset of the predefined exceptions that can be thrown directly by the operation of the Java Virtual Machine. Additional exceptions can be thrown by class library or user code; these exceptions are not covered here. See The Java Language Specification for information on all predefined exceptions.
throw
statement was executed in Java code.
stop
of class Thread
was invoked, or
Throwable
and instances of its subclasses. These classes are, collectively, the exception classes.catch
clause of a try
statement
that handles the exception.
A statement or expression is dynamically enclosed by a catch
clause if it appears within the try
block of the try
statement of which the catch
clause is a part, or if the caller of the statement or expression is dynamically enclosed by the catch
clause.
The caller of a statement or expression depends on where it occurs:
new-Instance
that was executed to cause an object to be created.
static
variable, then the caller is the expression that used the class or interface so as to cause it to be initialized.
catch
clause handles an exception is determined by comparing the class of the object that was thrown to the declared type of the parameter of the catch
clause. The catch
clause handles the exception if the type of its parameter is the class of the exception or a superclass of the class of the exception. Equivalently, a catch
clause will catch any exception object that is an instanceof
the declared parameter type.
The control transfer that occurs when an exception is thrown causes abrupt completion of expressions and statements until a catch
clause is encountered that can handle the exception; execution then continues by executing the block of that catch
clause. The code that caused the exception is never resumed.
If no catch
clause handling an exception can be found, then the current thread (the thread that encountered the exception) is terminated, but only after all finally
clauses have been executed and the method uncaughtException
has been invoked for the ThreadGroup
that is the parent of the current thread.
In situations where it is desirable to ensure that one block of code is always executed after another, even if that other block of code completes abruptly, a try
statement with a finally
clause may be used. If a try
or catch
block in a try-finally
or try-catch-finally
statement completes abruptly, then the finally
clause is executed during propagation of the exception, even if no matching catch
clause is ultimately found. If a finally
clause is executed because of abrupt completion of a try
block and the finally
clause itself completes abruptly, then the reason for the abrupt completion of the try
block is discarded and the new reason for abrupt completion is propagated from there.
Most exceptions in Java occur synchronously as a result of an action by the thread in which they occur, and at a point in the Java program that is specified to possibly result in such an exception. An asynchronous exception is, by contrast, an exception that can potentially occur at any point in the execution of a Java program.
Asynchronous exceptions are rare in Java. They occur only as a result of:
stop
methods of class Thread
or ThreadGroup
.
InternalError
in the Java Virtual Machine.
stop
methods may be invoked by one thread to affect another thread or all the
threads in a specified thread group. They are asynchronous because they may
occur at any point in the execution of the other thread or threads. An
InternalError
is considered asynchronous so that it may be handled using the
same mechanism that handles the stop
method, as will now be described.
Java permits a small but bounded amount of execution to occur before an asynchronous exception is thrown. This delay is permitted to allow optimized code to detect and throw these exceptions at points where it is practical to handle them while obeying the semantics of the Java language.
A simple implementation might poll for asynchronous exceptions at the point of each control transfer instruction. Since a Java program has a finite size, this provides a bound on the total delay in detecting an asynchronous exception. Since no asynchronous exception will occur between control transfers, the code generator has some flexibility to reorder computation between control transfers for greater performance.
All exceptions in Java are precise: when the transfer of control takes place, all effects of the statements executed and expressions evaluated before the point from which the exception is thrown must appear to have taken place. No expressions, statements, or parts thereof that occur after the point from which the exception is thrown may appear to have been evaluated. If optimized code has speculatively executed some of the expressions or statements which follow the point at which the exception occurs, such code must be prepared to hide this speculative execution from the user-visible state of the Java program.
Throwable
, a direct subclass of Object
. The classes Exception
and Error
are direct subclasses of Throwable
. The class RuntimeException
is a
direct subclass of Exception
.
Java programs can use the preexisting exception classes in throw
statements, or define additional exception classes, as subclasses of Throwable
or of any of its subclasses, as appropriate. To take advantage of Java's compile-time checking for exception handlers, it is typical to define most new exception classes as checked exception classes, specifically as subclasses of Exception
that are not subclasses of RuntimeException
.
Exception
and RuntimeException
Exception
is the superclass of all the standard exceptions that ordinary
programs may wish to recover from.
The class RuntimeException
is a subclass of class Exception
. The subclasses of RuntimeException
are unchecked exception classes. Package java.lang
defines the following standard unchecked runtime exceptions:
ArithmeticException
: An exceptional arithmetic situation has arisen, such as an integer division or remainder operation with a zero divisor.
ArrayStoreException
: An attempt has been made to store into an array component a value whose class is not assignment compatible with the component type of the array.
ClassCastException
: An attempt has been made to cast a reference to an object to an inappropriate type.
IllegalMonitorStateException
: A thread has attempted to wait on or notify other threads waiting on an object that it has not locked.
IndexOutOfBoundsException
: Either an index of some sort (such as to an array, a string, or a vector) or a subrange, specified either by two index values or by an index and a length, was out of range.
NegativeArraySizeException
: An attempt was made to create an array with a negative length.
NullPointerException
: An attempt was made to use a null reference in a case where an object reference was required.
SecurityException
: A security violation was detected.
Error
and its standard subclasses are exceptions from which ordinary programs are not ordinarily expected to recover. The class Error
is a separate subclass of Throwable
, distinct from Exception
in the class hierarchy, to allow programs to use the idiom
} catch (Exception e) {
to catch all exceptions from which recovery may be possible without catching
errors from which recovery is typically not possible. Package java.lang
defines
all the error classes described here.
A Java Virtual Machine throws an object that is an instance of a subclass of LinkageError
when a loading (§2.16.2), linking (§2.16.3), or initialization (§2.16.4) error occurs:
ClassFormatError
, ClassCircularityError
, and NoClassDefFoundError
are described there.
IncompatibleClassChangeError
), namely IllegalAccessError
, Instantiation-Error
, NoSuchFieldError
, and NoSuchMethodError
, are described there.
VerifyError
is described there.
AbstractMethodError
.
ExceptionInInitializerError
if execution of a static initializer or of an initializer for a static
field (§2.11) results in an exception that is not an Error
or a subclass of Error
.
VirtualMachineError
when an internal error or resource limitation prevents it from implementing the semantics of the Java Language. This specification defines the following virtual machine errors:
InternalError
: An internal error has occurred in a Java Virtual Machine, because of a fault in the software implementing the virtual machine, a fault in the underlying host system software, or a fault in the hardware. This error is delivered asynchronously when it is detected and may occur at any point in a Java program.
OutOfMemoryError
: A Java Virtual Machine has run out of either virtual or physical memory, and the automatic storage manager was unable to reclaim enough memory to satisfy an object creation request.
StackOverflowError
: A Java Virtual Machine has run out of stack space for a thread, typically because the thread is doing an unbounded number of recursive invocations as a result of a fault in the executing program.
UnknownError
: An exception or error has occurred but, for some reason, a Java Virtual Machine is unable to report the actual exception or error.
main
of some specified class, passing it a single argument, which is an array of strings. This causes
the specified class to be loaded (§2.16.2), linked (§2.16.3) to other types that it uses,
and initialized (§2.16.4). The method main
must be declared public
, static
, and
void
.
The manner in which the initial class is specified to the Java Virtual Machine is beyond the scope of this specification, but it is typical, in host environments that use command lines, for the fully qualified name of the class to be specified as a command-line argument and for subsequent command-line arguments to be used as strings to be provided as the argument to the method main
. For example, in Sun's JDK implementation on UNIX, the command line
java Terminator Hasta la vista Baby!
will start a Java Virtual Machine by invoking the method main
of class Terminator
(a class in an unnamed package), passing it an array containing the four strings
"Hasta"
, "la"
, "vista"
, and "Baby!"
.
We now outline the steps the virtual machine may take to execute Terminator
, as an example of the loading, linking, and initialization processes that are described further in later sections.
The initial attempt to execute the method main
of class Terminator
discovers that the class Terminator
is not loaded-that is, the virtual machine does not currently contain a binary representation for this class. The virtual machine then uses a ClassLoader
(§2.16.2) to attempt to find such a binary representation. If this process fails, an error is thrown. This loading process is described further in (§2.16.2).
After Terminator
is loaded, it must be initialized before main
can be invoked, and a type (class or interface) must always be linked before it is initialized. Linking involves verification, preparation, and (optionally) resolution. Linking is described further in §2.16.3.
Verification checks that the loaded representation of Terminator
is well formed, with a proper symbol table. Verification also checks that the code that implements Terminator
obeys the semantic requirements of the Java Virtual Machine. If a problem is detected during verification, an error is thrown. Verification is described further in §2.16.3.
Preparation involves allocation of static storage and any data structures that are used internally by the virtual machine, such as method tables. If a problem is detected during preparation, an error is thrown. Preparation is described further in §2.16.3.
Resolution is the process of checking symbolic references from Terminator
to other classes and interfaces, by loading the other classes and interfaces that are mentioned and checking that the references are correct.
The resolution step is optional at the time of initial linkage. An implementation may resolve a symbolic reference from a class or interface that is being linked very early, even to the point of resolving all symbolic references from the classes and interfaces that are further referenced, recursively. (This resolution may result in errors from further loading and linking steps.) This implementation choice represents one extreme and is similar to the kind of static linkage that has been done for many years in simple implementations of the C language.
An implementation may instead choose to resolve a symbolic reference only when it is actively used; consistent use of this strategy for all symbolic references would represent the "laziest" form of resolution. In this case, if Terminator
had several symbolic references to another class, the references might be resolved one at a time-perhaps not at all, if these references were never used during execution of the program.
The only requirement on when resolution is performed is that any errors detected during resolution must be thrown at a point in the program where some action is taken by the program that might, directly or indirectly, require linkage to the class or interface involved in the error. In the "static" example implementation choice described earlier, loading and linking errors could occur before the program is executed if they involved a class or interface mentioned in the class Terminator
or any of the further, recursively referenced classes and interfaces. In a system that implemented the "laziest" resolution, these errors would be thrown only when a symbolic reference is actively used.
The resolution process is described further in §2.16.3.
In our running example, the virtual machine is still trying to execute the method main of class Terminator
. This is an attempted active use (§2.16.4) of the class, which is permitted only if the class has been initialized.
Initialization consists of execution of any class variable initializers and static initializers of the class Terminator
, in textual order. But before Terminator
can be initialized, its direct superclass must be initialized, as well as the direct superclass of its direct superclass, and so on, recursively. In the simplest case, Terminator
has Object
as its implicit direct superclass; if class Object
has not yet been initialized, then it must be initialized before Terminator
is initialized.
If class Terminator
has another class Super
as its superclass, then Super
must be initialized before Terminator
. This requires loading, verifying, and preparing Super,
if this has not already been done, and, depending on the implementation, may also involve resolving the symbolic references from Super
and so on, recursively.
Initialization may thus cause loading, linking, and initialization errors, including such errors involving other types.
The initialization process is described further in §2.16.4.
Finally, after completion of the initialization for class Terminator
(during which other consequential loading, linking, and initializing may have occurred), the method main
of Terminator
is invoked.
Class
object to represent the
class or interface. The binary format of a class or interface is normally the class
file format (see Chapter 4, "The class File Format").
The loading process is implemented by the class ClassLoader
and its subclasses. Different subclasses of ClassLoader
may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together. These activities may not be completely transparent to a running Java application if, for example, a newly compiled version of a class is not found because an older version is cached by a class loader. It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
If an error occurs during class loading, then an instance of one of the following subclasses of class LinkageError
will be thrown at any point in the Java program that (directly or indirectly) uses the type:
ClassCircularityError
: A class or interface could not be loaded because it would be its own superclass or superinterface (§2.13.2).
ClassFormatError
: The binary data that purports to specify a requested compiled class or interface is malformed.
NoClassDefFoundError
: No definition for a requested class or interface could be found by the relevant class loader.
Java allows an implementation flexibility as to when linking activities (and, because of recursion, loading) take place, provided that the semantics of the language are respected, that a class or interface is completely verified and prepared before it is initialized, and that errors detected during linkage are thrown at a point in the program where some action is taken by the program that might require linkage to the class or interface involved in the error.
For example, an implementation may choose to resolve each symbolic reference in a class or interface individually, only when it is used (lazy or late resolution), or to resolve them all at once, for example, while the class is being verified (static resolution). This means that the resolution process may continue, in some implementations, after a class or interface has been initialized.
Verification ensures that the binary representation of a class or interface is structurally correct. For example, it checks that every instruction has a valid operation code; that every branch instruction branches to the start of some other instruction, rather than into the middle of an instruction; that every method is provided with a structurally correct signature; and that every instruction obeys the type discipline of the Java language.
If an error occurs during verification, then an instance of the following subclass of class LinkageError
will be thrown at the point in the Java program that caused the class to be verified:
VerifyError
: The binary definition for a class or interface failed to pass a set of required checks to verify that it obeys the semantics of the Java language and that it cannot violate the integrity of the Java Virtual Machine.
Java implementations must detect the following error during preparation:
AbstractMethodError
: A class that is not declared to be abstract
has an abstract
method. This can occur, for example, if a method that is originally not abstract
is changed to be abstract
after another class that inherits the now-abstract
method declaration has been compiled.
A Java binary file references other classes and interfaces and their fields, methods, and constructors symbolically, using the fully qualified names (§2.7.9) of the other classes and interfaces. For fields and methods these symbolic references include the name of the class or interface type which declares the field or method, as well as the name of the field or method itself, together with appropriate type information.
Before a symbolic reference can be used it must undergo resolution, wherein a symbolic reference is checked to be correct and, typically, replaced with a direct reference that can be more efficiently processed if the reference is used repeatedly.
If an error occurs during resolution, then an instance of one of the following subclasses of class IncompatibleClassChangeError
, or of some other subclass, or of IncompatibleClassChangeError
itself (which is a subclass of the class Linkage-Error
) may be thrown at any point in the Java program that uses a symbolic reference to the type:
IllegalAccessError
: A symbolic reference has been encountered that specifies a use or assignment of a field, or invocation of a method, or creation of an instance of a class, to which the code containing the reference does not have access because the field or method was declared private
, protected
, or default access (not public
), or because the class was not declared public
. This can occur, for example, if a field that is originally declared public
is changed to be private
after another class that refers to the field has been compiled.
InstantiationError
: A symbolic reference has been encountered that is used in a class instance creation expression, but an instance cannot be created because the reference turns out to refer to an interface or to an abstract
class. This can occur, for example, if a class that is originally not abstract
is changed to be abstract
after another class that refers to the class in question has been compiled.
NoSuchFieldError
: A symbolic reference has been encountered that refers to a specific field of a specific class or interface, but the class or interface does not declare a field of that name (it is specifically not sufficient for it simply to be an inherited field of that class or interface). This can occur, for example, if a field declaration was deleted from a class after another class that refers to the field was compiled.
NoSuchMethodError
: A symbolic reference has been encountered that refers to a specific method of a specific class or interface, but the class or interface does not declare a method of that name and signature (it is specifically not sufficient for it simply to be an inherited method of that class or interface). This can occur, for example, if a method declaration was deleted from a class after another class that refers to the method was compiled
Before a class is initialized, its superclass must be initialized, but interfaces implemented by the class need not be initialized. Similarly, the superinterfaces of an interface need not be initialized before the interface is initialized.
A class or interface type T will be initialized at its first active use, which occurs if:
final
and static
, and that is initialized with the value of a compile-time constant expression. Java specifies that a reference to such a field must be resolved at compile time to a copy of the compile-time constant value, so uses of such field are never active uses.
The intent here is that a type has a set of initializers that put it in a consistent state, and that this state is the first state that is observed by other classes. The static initializers and class variable initializers are executed in textual order and may not refer to class variables declared in the class whose declarations appear textually after the use, even though these class variables are in scope. This restriction is designed to detect, at compile time, most circular or otherwise malformed initializations.
Before a class is initialized its superclasses are initialized, if they have not previously been initialized.
A reference to a field is an active use of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.
Initialization of an interface does not, of itself, require initialization of any of its superinterfaces.
Class
object has already been verified and prepared, and that the
Class
object contains state that can indicates one of four situations:
Class
object is verified and prepared but not initialized.
Class
object is being initialized by some particular thread T.
Class
object is fully initialized and ready for use.
Class
object is in an erroneous state, perhaps because the verification or preparation step failed, or because initialization was attempted and failed.
Class
object that represents the class or interface to be initialized. This involves waiting until the current thread can obtain the lock for that object (§8.13).
wait
on this Class
object (which temporarily releases the lock). When the current thread awakens from the wait
, repeat this step.
Class
object and complete normally.
Class
object and complete normally.
Class
object is in an erroneous state, then initialization is not possible. Release the lock on the Class
object and throw a NoClassDefFoundError
.
Class
object is now in progress by the current thread and release the lock on the Class
object.
Class
object represents a class rather than an interface, and the superclass of this class has not yet been initialized, then recursively perform this entire procedure for the superclass. If necessary, verify and prepare the superclass first. If the initialization of the superclass completes abruptly because of a thrown exception, then lock this Class
object, label it erroneous, notify all waiting threads, release the lock, and complete abruptly, throwing the same exception that resulted from initializing the superclass.
final
static
variables and fields of interfaces whose values are compile-time constants are initialized first.
Class
object, label it fully initialized, notify all waiting threads, release the lock, and complete this procedure normally.
Error
or one of its subclasses, then create a new instance of the class ExceptionInInitializerError
, with E as the argument, and use this object in place of E in the following step. But if a new instance of ExceptionInInitializerError
cannot be created because an OutOfMemoryError
occurs, then instead use an OutOfMemoryError
object in place of E in the following step.
Class
object, label it erroneous, notify all waiting threads, release the lock, and complete this procedure abruptly with reason E or its replacement as determined in the previous step.
ExceptionInInitializerError
as
described here.
newInstance
method of class Class
creates a new instance of the class represented by the Class
object for which the method was invoked.
String
literal may create a new String
object (§2.4.7) to represent that literal. This may not occur if the same String
has previously been interned.
String
object to represent the result. String concatenation operators may also create temporary wrapper objects for a value of a primitive type (§2.4.1).
Whenever a new class instance is created, memory space is allocated for it with room for all the instance variables declared in the class type and all the instance variables declared in each superclass of the class type, including all the instance variables that may be hidden. If there is not sufficient space available to allocate memory for the object, then creation of the class instance completes abruptly with an OutOfMemoryError
. Otherwise, all the instance variables in the new object, including those declared in superclasses, are initialized to their default values (§2.5.1). Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
this
), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 5.
this
). If this constructor is for a class other than Object
, then this constructor will begin with a explicit or implicit invocation of a superclass constructor (using super
). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.
Object
has a protected
method called finalize
; this method can be
overridden by other classes. The particular definition of finalize
that can be
invoked for an object is called the finalizer of that object. Before the storage for an
object is reclaimed by the garbage collector, the Java Virtual Machine will invoke
the finalizer of that object.
Finalizers provide a chance to free up resources (such as file descriptors or operating system graphics contexts) that cannot be freed automatically by an automatic storage manager. In such situations, simply reclaiming the memory used by an object would not guarantee that the resources it held would be reclaimed.
The Java language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused. Also, the Java language does not specify which thread will invoke the finalizer for any given object. If an uncaught exception is thrown during the finalization, the exception is ignored and finalization of that object terminates.
The finalize
method declared in class Object
takes no action. However, the fact that class Object
declares a finalize
method means that the finalize
method for any class can always invoke the finalize
method for its superclass, which is usually good practice. (Unlike constructors, finalizers do not automatically invoke the finalizer for the superclass; such an invocation must be coded explicitly.)
For efficiency, an implementation may keep track of classes that do not override the finalize
method of class Object
, or override it in a trivial way, such as
protected void finalize() { super.finalize(); }We encourage implementations to treat such objects as having a finalizer that is not overridden, and to finalize them more efficiently.
The finalize
method may be invoked explicitly, just like any other method. However, doing so does not have any effect on the object's eventual automatic finalization.
The Java Virtual Machine imposes no ordering on finalize
method calls. Finalizers may be called in any order, or even concurrently.
As an example, if a circularly linked group of unfinalized objects becomes unreachable, then all the objects may become finalizable together. Eventually, the finalizers for these objects may be invoked, in any order, or even concurrently using multiple threads. If the automatic storage manager later finds that the objects are unreachable, then their storage can be reclaimed.
A class may not be unloaded while any instance of it is still reachable. A class or interface may not be unloaded while the Class
object that represents it is still reachable.
If a class declares a class method classFinalize
that takes no arguments, and returns no result:
static void classFinalize() { . . . }then this method will be invoked before the class is unloaded. Like the
finalize
method for objects, this method will be automatically invoked only once. This
method may optionally be declared private
, protected
, or public
.
exit
method of class Runtime
or class System
and the exit operation is permitted by the security manager.
runFinalizersOnExit
of the class
System
with the argument true
.3 The default is to not run finalizers on exit, and
this behavior may be restored by invoking runFinalizersOnExit
with the argument false
. An invocation of the runFinalizersOnExit
method is permitted
only if the caller is allowed to exit
, and is otherwise rejected by the security manager.
Any thread may be marked as a daemon thread. When code running in some thread creates a new Thread
object, that new thread is initially marked as a daemon thread if and only if the creating thread is a daemon thread. A program can change whether or not a particular thread is a daemon thread by calling the -setDaemon
method in class Thread
. The Java Virtual Machine initially starts up with a single non-daemon thread which typically calls the method main
of some class. The virtual machine may also create other daemon threads for internal purposes. The Java Virtual Machine exits when all non-daemon threads have died (§2.16.9).
Java supports the coding of programs that, though concurrent, still exhibit deterministic behavior, by providing mechanisms for synchronizing the concurrent activity of threads. To synchronize threads, Java uses monitors, which are a high-level mechanism for allowing only one thread at a time to execute a region of code protected by the monitor. The behavior of monitors is explained in terms of locks. There is a lock associated with each object.
The synchronized
statement performs two special actions relevant only to multithreaded operation:
synchronized
; such a method behaves as if its body were contained in a synchronized
statement.
wait
, notify
, and notifyAll
of class Object
support an efficient transfer of control from one thread to another. Rather than simply "spinning" (repeatedly locking and unlocking an object to see whether some internal state has changed), which consumes computational effort, a thread can suspend itself using wait
until such time as another thread awakens it using notify
or notifyAll
. This is especially appropriate in situations where threads have a producer-consumer relationship (actively cooperating on a common goal) rather than a mutual exclusion relationship (trying to avoid conflicts while sharing a common resource).As a thread executes code, it carries out a sequence of actions. A thread may use the value of a variable or assign it a new value. (Other actions include arithmetic operations, conditional tests, and method invocations, but these do not involve variables directly.) If two or more concurrent threads act on a shared variable, there is a possibility that the actions on the variable will produce timing-dependent results. This dependence on timing is inherent in concurrent programming and produces one of the few places in Java where the result of a program is not determined solely by The Java Language Specification.
Each thread has a working memory, in which it may keep copies of the values of variables from the main memory that are shared between all threads. To access a shared variable, a thread usually first obtains a lock and flushes its working memory. This guarantees that shared values will thereafter be loaded from the shared main memory to the working memory of the thread. By unlocking a lock, a thread guarantees that the values held by the thread in its working memory will be written back to the main memory.
The interaction of threads with the main memory, and thus with each other, may be explained in terms of certain low-level actions. There are rules about the order in which these actions may occur. These rules impose constraints on any implementation of Java, and a Java programmer may rely on the rules to predict the possible behaviors of a concurrent Java program. The rules do, however, intentionally give the implementor certain freedoms. The intent is to permit certain standard hardware and software techniques that can greatly improve the speed and efficiency of concurrent code.
Briefly put, the important consequences of the rules are the following:
long
and double
values; see §8.4.)
2 Class finalization and unloading are not implemented as of Sun's JDK release 1.0.2.
3
The method runFinalizersOnExit
is not implemented in Sun's JDK release 1.0.2.
Contents | Prev | Next | Index
Java Virtual Machine Specification
Copyright © 1996, 1997 Sun Microsystems, Inc.
All rights reserved
Please send any comments or corrections to [email protected]