Class and object initialization-part1
2016-05-19 11:54
417 查看
This article marks a milestone in Java 101's exploration of client-side Java, as well as the one year anniversary of the series. Jeff begins moving away from simpler Java language concepts toward more advanced
theories -- and toward a grand tour of Java's standard class library. Begin the journey this month by learning all about Java initialization.
Initialization prepares classes and objects for use during a program's execution. Although we tend to think of initialization in terms of assigning values to variables, initialization is so much more. For example, initialization might involve opening a file
and reading its contents into a memory buffer, registering a database driver, preparing a memory buffer to hold an image's contents, acquiring the resources necessary for playing a video, and so on. Think of anything that prepares a class or an object for
use in a program as initialization.
Java supports initialization via language features collectively known as initializers.Because Java handles class initialization differently from object initialization, and because classes initialize before objects, we first explore class initialization
and class-oriented initializers. Later, we explore object initialization and object-oriented initializers.
A program consists of classes. Before a Java application runs, Java's class loader loads its starting class -- the class with a
-- and Java's byte code verifier verifies the class. Then that class initializes. The simplest kind of class initialization is automatic initialization of class fields to default values. Listing 1 demonstrates that initialization:
Listing 1. ClassInitializationDemo1.java
of class fields. As you can see, no explicit values assign to any of those fields. And yet, when you run
The
and
what automatically set those bits to zero? The JVM, after a class is verified. (Note: In the preceding output, you do not see a value beside
the JVM interprets
After automatic initialization, the next simplest kind of class initialization is the explicit initialization of class fields to values. Each class field explicitly initializes to a value via a class field initializer. Listing 2 illustrates several
class field initializers:
Listing 2. ClassInitializationDemo2.java
In contrast to
class field initializer explicitly assigns a nondefault value to each class field. Simply put, a class field initializer consists of the assignment operator (
and an expression that the JVM evaluates after a class loads and before any of that class's developer-specified methods execute. The assignment operator assigns the expression's value to the associated class field. When run,
the following output:
Although the output is as expected, what executes the class field initializers that explicitly initialize
the JVM zeroes the bits in all class fields, it calls a special JVM-level method to execute the byte code instructions that comprise the class's class field initializers. That method is known as
When you compile a class containing at least one class field initializer, the compiler generates code for
after the byte code verifier verifies the class's byte codes, and after the JVM allocates memory for the class fields and zeroes all bits in those class fields, the JVM calls the class's
(if present). The
check out Listing 3:
Listing 3. ClassInitializationDemo2's <clinit> method
Listing 3 presents some insight into how
works. Each line presents a number and a byte code instruction. The number represents the instruction's zero-based address and is not important to this discussion. The first instruction,
pushes integer constant 1 onto a stack, and the second instruction,
field
to the right of the
Boolean. Similarly,
character type,
the floating-point type,
the short integer type. The
and other
pop those values from the stack before assigning them to various class fields. The final
At that point, the
Some programs require class fields to refer to previously declared class fields. Java supports that activity by letting you specify the name of a previously declared class field in the expression portion of a subsequently declared class field's class field
initializer, as Listing 4 demonstrates:
Listing 4. ClassInitializationDemo3.java
assigns
class field
class initializer expression. When you run the program, you see the following output:
If you examine the byte code instructions for
you see something similar to Listing 5:
Listing 5. ClassInitializationDemo3's <clinit> method
Listing 5 shows byte code instructions that assign
add constant
ends up in a temporary stack-based variable. The instructions subsequently assign the contents of the temporary stack-based variable to
Although a subsequently declared class field can refer to a previously declared class field, the reverse is not true: You cannot declare a class field initializer that refers to a class field declared later in source code. In other words, Java does not permit
forward references with class field initializers, as the following code fragment demonstrates:
When the compiler encounters either the code above or another forward reference code fragment during compilation, it generates an error message because the developer's intention is unclear. Should the compiler regard
containing 0, which results in
containing 3, which results in
class fields.
Although sufficient for class field initialization, class field initializers prove inadequate for more complex class initialization. For example, suppose you need to read a file's contents into a buffer before the
executes. What do you do? Java meets that challenge by providing the class block initializer. A class block initializer consists of keyword
by an open brace character (
Furthermore, a class block initializer appears within a class, but not within any of that class's methods, as Listing 6 demonstrates:
Listing 6. ClassInitializationDemo4.java
and then introduces a class block initializer. That initializer displays a status message, obtains a list of all filenames for those files that appear in the current directory, and displays a second status message. All that activity takes place before the
executes. When
In addition to placing the class field initializers' byte code instructions in a class's
encountered class block initializer in that same method. The compiler places these instructions in the
compiler compiles a class in a top-to-bottom fashion, it places in the
encountered class field initializer and class block initializer. Refer back to Listing 6: The compiler places the class block initializer's byte code instructions in
If that class specified a class field initializer for its
before the class block initializer's byte code instructions in the
原文链接:http://www.javaworld.com/article/2075796/java-platform/java-101--class-and-object-initialization.html
theories -- and toward a grand tour of Java's standard class library. Begin the journey this month by learning all about Java initialization.
Initialization prepares classes and objects for use during a program's execution. Although we tend to think of initialization in terms of assigning values to variables, initialization is so much more. For example, initialization might involve opening a file
and reading its contents into a memory buffer, registering a database driver, preparing a memory buffer to hold an image's contents, acquiring the resources necessary for playing a video, and so on. Think of anything that prepares a class or an object for
use in a program as initialization.
Java supports initialization via language features collectively known as initializers.Because Java handles class initialization differently from object initialization, and because classes initialize before objects, we first explore class initialization
and class-oriented initializers. Later, we explore object initialization and object-oriented initializers.
Class initialization
A program consists of classes. Before a Java application runs, Java's class loader loads its starting class -- the class with a public static void main(String [] args)method
-- and Java's byte code verifier verifies the class. Then that class initializes. The simplest kind of class initialization is automatic initialization of class fields to default values. Listing 1 demonstrates that initialization:
Listing 1. ClassInitializationDemo1.java
// ClassInitializationDemo1.java class ClassInitializationDemo1 { static boolean b; static byte by; static char c; static double d; static float f; static int i; static long l; static short s; static String st; public static void main (String [] args) { System.out.println ("b = " + b); System.out.println ("by = " + by); System.out.println ("c = " + c); System.out.println ("d = " + d); System.out.println ("f = " + f); System.out.println ("i = " + i); System.out.println ("l = " + l); System.out.println ("s = " + s); System.out.println ("st = " + st); } }
ClassInitializationDemo1's
statickeyword introduces a variety
of class fields. As you can see, no explicit values assign to any of those fields. And yet, when you run
ClassInitializationDemo1, you see the following output:
b = false by = 0 c = d = 0.0 f = 0.0 i = 0 l = 0 s = 0 st = null
The
false,
0,
0.0,
and
nullvalues are the type-oriented representations of default values. They represent the result of all bits automatically set to zero in each class field. And
what automatically set those bits to zero? The JVM, after a class is verified. (Note: In the preceding output, you do not see a value beside
c =because
the JVM interprets
c's default value as the nondisplayable null value.)
Class field initializers
After automatic initialization, the next simplest kind of class initialization is the explicit initialization of class fields to values. Each class field explicitly initializes to a value via a class field initializer. Listing 2 illustrates severalclass field initializers:
Listing 2. ClassInitializationDemo2.java
// ClassInitializationDemo2.java class ClassInitializationDemo2 { static boolean b = true; static byte by = 1; static char c = 'A'; static double d = 1.2; static float f = 3.4f; static int i = 2; static long l = 3; static short s = 4; static String st = "abc"; public static void main (String [] args) { System.out.println ("b = " + b); System.out.println ("by = " + by); System.out.println ("c = " + c); System.out.println ("d = " + d); System.out.println ("f = " + f); System.out.println ("i = " + i); System.out.println ("l = " + l); System.out.println ("s = " + s); System.out.println ("st = " + st); } }
In contrast to
ClassInitializationDemo1, in
ClassInitializationDemo2a
class field initializer explicitly assigns a nondefault value to each class field. Simply put, a class field initializer consists of the assignment operator (
=)
and an expression that the JVM evaluates after a class loads and before any of that class's developer-specified methods execute. The assignment operator assigns the expression's value to the associated class field. When run,
ClassInitializationDemo2produces
the following output:
b = true by = 1 c = A d = 1.2 f = 3.4 i = 2 l = 3 s = 4 st = abc
Although the output is as expected, what executes the class field initializers that explicitly initialize
ClassInitializationDemo2's class fields? The answer: After
the JVM zeroes the bits in all class fields, it calls a special JVM-level method to execute the byte code instructions that comprise the class's class field initializers. That method is known as
<clinit>.
When you compile a class containing at least one class field initializer, the compiler generates code for
<clinit>. After the JVM's class loader loads the class,
after the byte code verifier verifies the class's byte codes, and after the JVM allocates memory for the class fields and zeroes all bits in those class fields, the JVM calls the class's
<clinit>method
(if present). The
<clinit>method's byte code instructions execute all class field initializers. To see what those byte code instructions look like for the above
ClassInitializationDemo2class,
check out Listing 3:
Listing 3. ClassInitializationDemo2's <clinit> method
0 iconst_1 1 putstatic ClassInitializationDemo2/b Z // boolean b = true; 4 iconst_1 5 putstatic ClassInitializationDemo2/by B // byte by = 1; 8 bipush 65 10 putstatic ClassInitializationDemo2/c C // char c = 'A'; 13 ldc2_w #1.200000 16 putstatic ClassInitializationDemo2/d D // double d = 1.2; 19 ldc #3.400000 21 putstatic ClassInitializationDemo2/f F // float f = 3.4f; 24 iconst_2 25 putstatic ClassInitializationDemo2/i I // int i = 2; 28 ldc2_w #3 31 putstatic ClassInitializationDemo2/l J // long l = 3; 34 iconst_4 35 putstatic ClassInitializationDemo2/s S // short s = 4; 38 ldc "abc" 40 putstatic ClassInitializationDemo2/st Ljava/lang/String; // String st = "abc"; 43 return
Listing 3 presents some insight into how
ClassInitializationDemo2's
<clinit>method
works. Each line presents a number and a byte code instruction. The number represents the instruction's zero-based address and is not important to this discussion. The first instruction,
iconst_1,
pushes integer constant 1 onto a stack, and the second instruction,
putstatic ClassInitializationDemo2/b Z, pops that constant from the stack and assigns it to
booleanclass
field
b. (At the JVM level, at least with Sun's JVM, the Boolean true value is represented as integer constant 1.) The
Zappearing
to the right of the
putstaticinstruction identifies the type of
bas
Boolean. Similarly,
Bidentifies the byte type,
Cidentifies the
character type,
Didentifies the double-precision floating-point type,
Fidentifies
the floating-point type,
Jidentifies the long integer type, and
Sidentifies
the short integer type. The
bipush,
ldc2_w,
ldc,
and other
iconstinstructions push other constants onto the stack, and their respective
putstaticinstructions
pop those values from the stack before assigning them to various class fields. The final
returninstruction causes execution to leave the
<clinit>method.
At that point, the
main()method starts to execute.
Some programs require class fields to refer to previously declared class fields. Java supports that activity by letting you specify the name of a previously declared class field in the expression portion of a subsequently declared class field's class field
initializer, as Listing 4 demonstrates:
Listing 4. ClassInitializationDemo3.java
// ClassInitializationDemo3.java class ClassInitializationDemo3 { static int first = 3; static int second = 1 + first; public static void main (String [] args) { System.out.println ("first = " + first); System.out.println ("second = " + second); } }
ClassInitializationDemo3declares class field
firstand explicitly
assigns
3to that field. Then,
ClassInitializationDemo3declares
class field
secondand refers to
firstin
second's
class initializer expression. When you run the program, you see the following output:
first = 3 second = 4
If you examine the byte code instructions for
ClassInitializationDemo3's
<clinit>method,
you see something similar to Listing 5:
Listing 5. ClassInitializationDemo3's <clinit> method
0 iconst_3 1 putstatic ClassInitializationDemo3/first I // first = 3; 4 iconst_1 5 getstatic ClassInitializationDemo3/first I 8 iadd 9 putstatic ClassInitializationDemo3/second I // second = 1 + first; 12 return
Listing 5 shows byte code instructions that assign
3to
firstand
add constant
1to
first's contents. The result of that addition
ends up in a temporary stack-based variable. The instructions subsequently assign the contents of the temporary stack-based variable to
second.
Although a subsequently declared class field can refer to a previously declared class field, the reverse is not true: You cannot declare a class field initializer that refers to a class field declared later in source code. In other words, Java does not permit
forward references with class field initializers, as the following code fragment demonstrates:
static int second = 1 + first; static int first = 3;
When the compiler encounters either the code above or another forward reference code fragment during compilation, it generates an error message because the developer's intention is unclear. Should the compiler regard
firstas
containing 0, which results in
secondinitializing to 1, or should the compiler regard
firstas
containing 3, which results in
secondinitializing to 4? To prevent that confusion, Java prohibits class field initializers from making forward references to other
class fields.
Class block initializers
Although sufficient for class field initialization, class field initializers prove inadequate for more complex class initialization. For example, suppose you need to read a file's contents into a buffer before the main()method
executes. What do you do? Java meets that challenge by providing the class block initializer. A class block initializer consists of keyword
staticfollowed
by an open brace character (
{), initialization code, and a close brace character (
}).
Furthermore, a class block initializer appears within a class, but not within any of that class's methods, as Listing 6 demonstrates:
Listing 6. ClassInitializationDemo4.java
// ClassInitializationDemo4.java import java.io.*; class ClassInitializationDemo4 { static String [] filenames; static { System.out.println ("Acquiring filenames"); filenames = new File (".").list (); System.out.println ("Filenames acquired"); } public static void main (String [] args) { System.out.println ("Displaying filenames\n"); for (int i = 0; i < filenames.length; i++) System.out.println (filenames [i]); } }
ClassInitializationDemo4declares a
filenamesarray field variable
and then introduces a class block initializer. That initializer displays a status message, obtains a list of all filenames for those files that appear in the current directory, and displays a second status message. All that activity takes place before the
main()method
executes. When
main()executes, a status message displays, along with a list of filenames. The result resembles the following output:
Acquiring filenames Filenames acquired Displaying filenames ClassInitializationDemo4.java ClassInitializationDemo4.class
In addition to placing the class field initializers' byte code instructions in a class's
<clinit>method, the compiler places the byte code instructions of each
encountered class block initializer in that same method. The compiler places these instructions in the
<clinit>method according to a specific order. Because the
compiler compiles a class in a top-to-bottom fashion, it places in the
<clinit>method, in a top-to-bottom order, the equivalent byte code instructions to each
encountered class field initializer and class block initializer. Refer back to Listing 6: The compiler places the class block initializer's byte code instructions in
ClassInitializationDemo4's
<clinit>method.
If that class specified a class field initializer for its
filenamesclass field, the byte code instructions comprising that class field initializer would appear
before the class block initializer's byte code instructions in the
<clinit>method.
原文链接:http://www.javaworld.com/article/2075796/java-platform/java-101--class-and-object-initialization.html
相关文章推荐
- 使用Object-C实现23种设计模式之工厂方法模式
- android activity之间传递ArrayList<HashMap<String,Object>>
- csharp: .NET Object Relationional Mapper (ORM)- SubSonic
- 论文阅读:Volumetric and Multi-View CNNs for Object Classification on 3D Data
- 设计模式之对象池模式(Object Pool)
- SAP Business One 对象类型大全 (Object Type)
- Jquery中(function($){...})(jQuery),$(function(){}),$.extend(object)和$.fn.extend(object)
- iOS中Objective-C与JavaScript之间相互调用的实现(实现了与Android相同的机制)
- ObjectAnimator实现机制_源码分析
- Objective-C语法汇总
- Exploring Python Code Objects
- Java之Object类详解
- Python integer objects implementation
- 错误解决:error while loading shared libraries: libcurl.so.4: cannot open shared object file: No such file or directory
- sql-syscolumns,INFORMATION_SCHEMA.columns,sysobjects
- Js中Prototype、__proto__、Constructor、Object、Function关系介绍
- object-oriented second work
- mssql的object_id
- J2SE(十八)Object之Clone
- Objective-C ---NSArray NSDictionary(梳理整理)