Class and object initialization-part2
2016-05-19 11:56
447 查看
Page 2 of 4
After studying
class block initializer to its
class block initializers to simplify database driver registration. Consider the following code fragment:
The code fragment calls
(located in the
registers with JDBC. What causes that registration to occur? The answer is Java statements that comprise
to say about JDBC in a future article.)
When working with class block initializers, keep in mind two more items: First, any variable that you declare in a class block initializer is local to that block. No code outside the block can access the variable. Second, Java permits you to declare a constant
class field without a class field initializer as long as you explicitly initialize that constant in a class block initializer. Furthermore, within the class block initializer, you must initialize the constant before you attempt to read its value. Listing 7
illustrates both points:
Listing 7. ClassInitializationDemo5.java
When you compile
class block initializer. However, if you comment out
You might think it bizarre to see the declaration of constant
initializes to
Thus far, you have only seen class field initializers and class block initializers in the context of a single class. How does class initialization work in the context of a class hierarchy? When a class hierarchy is involved, the compiler creates a separate
for each class in that hierarchy. At runtime, the JVM loads all hierarchy classes and calls their
superclass's
executes first. After
next highest superclass's
(if present) executes. Listing 8 demonstrates the
Listing 8. ClassInitializationDemo6.java
Each class's
that
examine the following
The output shows that
first. Next,
class field initializer
class block initializer executes. And that is pretty much all there is to know regarding class initialization and class hierarchies.
Now that you have seen class initialization at work, it is time to focus on object initialization. As you will discover, the initializers that perform object initialization mirror those initializers that perform class initialization. As with class initialization,
the simplest kind of object initialization is automatic initialization of object fields to default values. Listing 9 illustrates that type of initialization:
Listing 9. ObjectInitializationDemo1.java
it introduces a variety of fields -- object fields, to be exact. Furthermore, no explicit values assign to any of those fields.
You see the following output when
This time, the JVM zeroes all object fields' bits. Unlike class fields, which the JVM zeroes after a class loads and is verified, the JVM only zeroes the bits of a class's object fields when a program creates an object from that class. That activity
should come as no surprise when you consider that object fields bind to objects. Therefore, object fields do not exist until a program creates an object. Furthermore, each object receives its own copies of a class's object fields.
The next simplest kind of object initialization is the explicit initialization of object fields to values. Each object field explicitly initializes to a value via an object field initializer. Listing 10 shows several object field initializers:
Listing 10. ObjectInitializationDemo2.java
In contrast to
object field initializer explicitly assigns a nondefault value to each object field. Essentially, an object field initializer consists of the assignment operator (
and an expression that evaluates during object creation. The assignment operator assigns the expression's value to the associated object field. When run,
the following output:
What is responsible for executing the object field initializers? Would you believe that the constructor is? As strange as it might seem, the compiler inserts byte code instructions into a class's constructor to execute object field initializers. But there's
more: When you look at a constructor from the JVM's perspective, you no longer see a constructor. Instead, you see what the JVM refers to as an
During class compilation, the compiler generates an
the compiler generates an
and that the compiler places byte code instructions, apart from the instructions you specify (via Java source code), into that method. Some of those instructions serve to execute object field initializers.
Take a close look at Listing 10. You cannot see its presence, but a constructor does exist. If you could see that constructor, it would probably look like the following code fragment:
That's right! The constructor would appear empty. Suppose you disassemble
that matches the default no-argument constructor. And what instructions would you find in that method? Take a look at Listing 11:
Listing 11. ObjectInitializationDemo2's no-argument <init> method
Apart from Listing 11's byte code instructions executing
items about how Java works:
Note the
instruction push? The current object address -- as keyword
pop that address from the stack and use the address to identify the proper object when making a call to an object method or writing to an object field.
Note the
constructor -- to be precise, the default no-argument
(Remember keyword
Note the location of
that instruction as the second instruction (after
In accordance with the way Java works, a constructor must first either call another constructor in the same class or a constructor in its superclass. If a constructor does not explicitly call another constructor in the same class (via
or a constructor in a superclass (via
We will explore the second and third items in the above list later in this section, when we examine object initialization and class hierarchies. But first, we need to explore object field initializers and forward references, along with object block initializers.
As with class fields, some programs require object fields to refer to previously declared object fields. Java supports that activity by allowing you to specify the name of a previously declared object field in the expression portion of a subsequently declared
object field's initializer. However, just as you cannot use forward references with class field initializers, you cannot use forward references with object field initializers. Listing 12 demonstrates both concepts:
Listing 12. ObjectInitializationDemo3.java
After studying
ClassInitializationDemo4's source code, you might wonder how useful class block initializers are. After all, you could easily move all code from
ClassInitializationDemo4's
class block initializer to its
main()method. Nevertheless, class block initializers are useful. For example, Sun's JDBC (Java Database Connectivity) API uses
class block initializers to simplify database driver registration. Consider the following code fragment:
Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver");
The code fragment calls
Class's
forName()method to load the
JdbcOdbcDriverclass
(located in the
sun.jdbc.odbcpackage). Once that code fragment completes, the class loads, and the database driver associated with the
JdbcOdbcDriverclass
registers with JDBC. What causes that registration to occur? The answer is Java statements that comprise
JdbcOdbcDriver's class block initializer. (I have more
to say about JDBC in a future article.)
When working with class block initializers, keep in mind two more items: First, any variable that you declare in a class block initializer is local to that block. No code outside the block can access the variable. Second, Java permits you to declare a constant
class field without a class field initializer as long as you explicitly initialize that constant in a class block initializer. Furthermore, within the class block initializer, you must initialize the constant before you attempt to read its value. Listing 7
illustrates both points:
Listing 7. ClassInitializationDemo5.java
// ClassInitializationDemo5.java import java.io.*; class ClassInitializationDemo5 { final static double PI; static { PI = 3.14159; int i; for (i = 0; i < 5; i++) System.out.println (i); } static int j = i; public static void main (String [] args) { System.out.println ("PI = " + PI); } }
When you compile
ClassInitializationDemo5, the compiler reports an error when it encounters
static int j = i;because it cannot find
i--
iis local to the
class block initializer. However, if you comment out
static int j = i;and recompile, you don't receive a compiler error. Instead, you receive the following output:
0 1 2 3 4 PI = 3.14159
You might think it bizarre to see the declaration of constant
PIwithout a class field initializer to initialize that constant. However, as long as
PIexplicitly
initializes to
3.14159in either a class field initializer or in a class block initializer, the compiler does not complain.
Class initialization and class hierarchies
Thus far, you have only seen class field initializers and class block initializers in the context of a single class. How does class initialization work in the context of a class hierarchy? When a class hierarchy is involved, the compiler creates a separate<clinit>method
for each class in that hierarchy. At runtime, the JVM loads all hierarchy classes and calls their
<clinit>methods in a top-to-bottom order. That means the highest
superclass's
<clinit>method (which is
Object's
<clinit>method)
executes first. After
Object's
<clinit>method completes, the
next highest superclass's
<clinit>method executes. The process continues in a top-down fashion until the class with the
main()method's
<clinit>method
(if present) executes. Listing 8 demonstrates the
<clinit>execution order:
Listing 8. ClassInitializationDemo6.java
// ClassInitializationDemo6.java class Parent { static int a = 1; static { System.out.println ("a = " + a); System.out.println ("Parent initializer"); } } class ClassInitializationDemo6 extends Parent { static int b = 2 + a; static { System.out.println ("b = " + b); System.out.println ("Child initializer"); System.out.println ("a = " + a); } public static void main (String [] args) { } }
ClassInitializationDemo6introduces a pair of classes:
Parentand
ClassInitializationDemo6.
Each class's
<clinit>method executes the byte code instructions comprising that class's class field initializer and class block initializer. To prove to yourself
that
Parent's
<clinit>method executes before
ClassInitializationDemo6's
<clinit>method,
examine the following
ClassInitializationDemo6output:
a = 1 Parent initializer b = 3 Child initializer a = 1
The output shows that
Parent's class field initializer
= 1;executes
first. Next,
Parent's class block initializer executes. Moving on,
ClassInitializationDemo6's
class field initializer
= 2 + a;executes. Finally,
ClassInitializationDemo6's
class block initializer executes. And that is pretty much all there is to know regarding class initialization and class hierarchies.
Object initialization
Now that you have seen class initialization at work, it is time to focus on object initialization. As you will discover, the initializers that perform object initialization mirror those initializers that perform class initialization. As with class initialization,the simplest kind of object initialization is automatic initialization of object fields to default values. Listing 9 illustrates that type of initialization:
Listing 9. ObjectInitializationDemo1.java
// ObjectInitializationDemo1.java class ObjectInitializationDemo1 { boolean b; byte by; char c; double d; float f; int i; long l; short s; String st; public static void main (String [] args) { ObjectInitializationDemo1 oid1 = new ObjectInitializationDemo1 (); System.out.println ("oid1.b = " + oid1.b); System.out.println ("oid1.by = " + oid1.by); System.out.println ("oid1.c = " + oid1.c); System.out.println ("oid1.d = " + oid1.d); System.out.println ("oid1.f = " + oid1.f); System.out.println ("oid1.i = " + oid1.i); System.out.println ("oid1.l = " + oid1.l); System.out.println ("oid1.s = " + oid1.s); System.out.println ("oid1.st = " + oid1.st); } }
ObjectInitializationDemo1mirrors
ClassInitializationDemo1in that
it introduces a variety of fields -- object fields, to be exact. Furthermore, no explicit values assign to any of those fields.
You see the following output when
ObjectInitializationDemo1runs:
b = false by = 0 c = d = 0.0 f = 0.0 i = 0 l = 0 s = 0 st = null
This time, the JVM zeroes all object fields' bits. Unlike class fields, which the JVM zeroes after a class loads and is verified, the JVM only zeroes the bits of a class's object fields when a program creates an object from that class. That activity
should come as no surprise when you consider that object fields bind to objects. Therefore, object fields do not exist until a program creates an object. Furthermore, each object receives its own copies of a class's object fields.
Object field initializers
The next simplest kind of object initialization is the explicit initialization of object fields to values. Each object field explicitly initializes to a value via an object field initializer. Listing 10 shows several object field initializers:Listing 10. ObjectInitializationDemo2.java
// ObjectInitializationDemo2.java class ObjectInitializationDemo2 { boolean b = true; byte by = 1; char c = 'A'; double d = 1.2; float f = 3.4f; int i = 2; long l = 3; short s = 4; String st = "abc"; public static void main (String [] args) { ObjectInitializationDemo2 oid2 = new ObjectInitializationDemo2 (); System.out.println ("oid2.b = " + oid2.b); System.out.println ("oid2.by = " + oid2.by); System.out.println ("oid2.c = " + oid2.c); System.out.println ("oid2.d = " + oid2.d); System.out.println ("oid2.f = " + oid2.f); System.out.println ("oid2.i = " + oid2.i); System.out.println ("oid2.l = " + oid2.l); System.out.println ("oid2.s = " + oid2.s); System.out.println ("oid2.st = " + oid2.st); } }
In contrast to
ObjectInitializationDemo1, in
ObjectInitializationDemo2an
object field initializer explicitly assigns a nondefault value to each object field. Essentially, an object field initializer consists of the assignment operator (
=)
and an expression that evaluates during object creation. The assignment operator assigns the expression's value to the associated object field. When run,
ObjectInitializationDemo2produces
the following output:
oid2.b = true oid2.by = 1 oid2.c = A oid2.d = 1.2 oid2.f = 3.4 oid2.i = 2 oid2.l = 3 oid2.s = 4 oid2.st = abc
What is responsible for executing the object field initializers? Would you believe that the constructor is? As strange as it might seem, the compiler inserts byte code instructions into a class's constructor to execute object field initializers. But there's
more: When you look at a constructor from the JVM's perspective, you no longer see a constructor. Instead, you see what the JVM refers to as an
<init>method.
During class compilation, the compiler generates an
<init>method for each of that class's constructors. If that class contains no constructors (as in
ObjectInitializationDemo2),
the compiler generates an
<init>method that matches the default no-argument constructor. It is important to realize that each constructor has its own corresponding
<init>method
and that the compiler places byte code instructions, apart from the instructions you specify (via Java source code), into that method. Some of those instructions serve to execute object field initializers.
Take a close look at Listing 10. You cannot see its presence, but a constructor does exist. If you could see that constructor, it would probably look like the following code fragment:
ObjectInitializationDemo2 () { }
That's right! The constructor would appear empty. Suppose you disassemble
ObjectInitializationDemo2's class file. In that disassembly, you would encounter a no-argument
<init>method
that matches the default no-argument constructor. And what instructions would you find in that method? Take a look at Listing 11:
Listing 11. ObjectInitializationDemo2's no-argument <init> method
0 aload_0 1 invokespecial java/lang/Object/<init>()V 4 aload_0 5 iconst_1 6 putfield ObjectInitializationDemo2/b Z 9 aload_0 10 iconst_1 11 putfield ObjectInitializationDemo2/by B 14 aload_0 15 bipush 65 17 putfield ObjectInitializationDemo2/c C 20 aload_0 21 ldc2_w #1.200000 24 putfield ObjectInitializationDemo2/d D 27 aload_0 28 ldc #3.400000 30 putfield ObjectInitializationDemo2/f F 33 aload_0 34 iconst_2 35 putfield ObjectInitializationDemo2/i I 38 aload_0 39 ldc2_w #3 42 putfield ObjectInitializationDemo2/l J 45 aload_0 46 iconst_4 47 putfield ObjectInitializationDemo2/s S 50 aload_0 51 ldc "abc" 53 putfield ObjectInitializationDemo2/st Ljava/lang/String; 56 return
Apart from Listing 11's byte code instructions executing
ObjectInitializationDemo2's object field initializers, a close examination of Listing 11 reveals some interesting
items about how Java works:
Note the
aload_0instruction. That instruction pushes an address onto a stack. And what address does that
instruction push? The current object address -- as keyword
thisrepresents in source code. The
invokespecialand
putfieldinstructions
pop that address from the stack and use the address to identify the proper object when making a call to an object method or writing to an object field.
Note the
invokespecial java/lang/Object/<init>()Vinstruction. That instruction calls the default no-argument
constructor -- to be precise, the default no-argument
<init>method -- in the
Objectsuperclass.
(Remember keyword
super's use in calling a superclass constructor? You are seeing how Java uses that keyword at the byte code level.)
Note the location of
invokespecial java/lang/Object/<init>()V. It is no accident that the compiler places
that instruction as the second instruction (after
aload_0) in the default no-argument
<init>method.
In accordance with the way Java works, a constructor must first either call another constructor in the same class or a constructor in its superclass. If a constructor does not explicitly call another constructor in the same class (via
this)
or a constructor in a superclass (via
super), the compiler generates byte code instructions that are the equivalent of placing
super ();at a constructor's start.
We will explore the second and third items in the above list later in this section, when we examine object initialization and class hierarchies. But first, we need to explore object field initializers and forward references, along with object block initializers.
As with class fields, some programs require object fields to refer to previously declared object fields. Java supports that activity by allowing you to specify the name of a previously declared object field in the expression portion of a subsequently declared
object field's initializer. However, just as you cannot use forward references with class field initializers, you cannot use forward references with object field initializers. Listing 12 demonstrates both concepts:
Listing 12. ObjectInitializationDemo3.java
// ObjectInitializationDemo3.java class ObjectInitializationDemo3 { // int forwardReference = first; int first = 3; int second = 1 + first; public static void main (String [] args) { ObjectInitializationDemo3 oid3 = new ObjectInitializationDemo3 (); System.out.println ("oid3.first = " + oid3.first); System.out.println ("oid3.second = " + oid3.second); } }
相关文章推荐
- Class and object initialization-part1
- 使用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