⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 java中的初始化类、变量、程序块加载探讨-java面向对象 - it电子教育门户 高端java培训.htm

📁 这是我自己认真整理的java面向对象的各个方面的知识.想和大家一起来分享我的快乐!
💻 HTM
📖 第 1 页 / 共 4 页
字号:
                  "+d);<BR>&nbsp;}<BR>&nbsp;public static void main(String[] 
                  args) {<BR>&nbsp; InitialValues iv=new 
                  InitialValues();<BR>&nbsp; 
                  iv.printInitialValues();<BR>&nbsp;}<BR>}<BR>结果:<BR>boolean&nbsp; 
                  false<BR>char&nbsp; _<BR>byte&nbsp; 0<BR>short&nbsp; 
                  0<BR>int&nbsp; 0<BR>long&nbsp; 0<BR>float&nbsp; 
                  0.0<BR>double&nbsp; 
                  0.0<BR>&nbsp;<BR>2.变量初始化<BR>&nbsp;&nbsp;&nbsp; 
                  在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧在任何方法(包括构造器)被调用之前得到初始化。看下面的代码:<BR>OrderOfInitialzation.java(执行顺序在代码中已标出,按类标注,罗马字母标注主类中执行顺序。)<BR>class 
                  Tag{<BR>&nbsp;Tag(int marker){<BR>&nbsp; 
                  System.out.println("Tag("+marker+")");<BR>&nbsp;}<BR>}<BR>class 
                  Card{<BR>&nbsp;Tag t1=new 
                  Tag(1);//Ⅰ①<BR>&nbsp;Card(){<BR>&nbsp; 
                  System.out.println("Card()");//Ⅰ④<BR>&nbsp; t3=new 
                  Tag(33);//Ⅰ⑤<BR>&nbsp;}<BR>&nbsp;Tag t2=new 
                  Tag(2);//Ⅰ②<BR>&nbsp;void f(){<BR>&nbsp; 
                  System.out.println("f()");//Ⅱ⑥<BR>&nbsp;}<BR>&nbsp;Tag t3=new 
                  Tag(3);//Ⅰ③<BR>}<BR>public class OrderOfInitialzation 
                  {<BR>&nbsp;public static void main(String[] args) {<BR>&nbsp; 
                  Card t=new Card();//Ⅰ<BR>&nbsp; 
                  t.f();//Ⅱ<BR>&nbsp;}<BR>}<BR>结果:<BR>Tag(1)<BR>Tag(2)<BR>Tag(3)<BR>Card()<BR>Tag(33)<BR>f()<BR>&nbsp;<BR>3.静态数据初始化<BR>看下面的代码:<BR>StaticInitialization 
                  .java<BR>class Bowl{<BR>&nbsp;Bowl(int marker){<BR>&nbsp; 
                  System.out.println("Bowl("+marker+")");<BR>&nbsp;}<BR>&nbsp;void 
                  f(int marker){<BR>&nbsp; 
                  System.out.println("f("+marker+")");<BR>&nbsp;}<BR>}<BR>class 
                  Table{<BR>&nbsp;static Bowl b1=new 
                  Bowl(1);//Ⅰ①<BR>&nbsp;Table(){<BR>&nbsp; 
                  System.out.println("Table()");//Ⅰ③<BR>&nbsp; 
                  b2.f(1);//Ⅰ④<BR>&nbsp;}<BR>&nbsp;void f2(int 
                  marker){<BR>&nbsp; 
                  System.out.println("f2("+marker+")");<BR>&nbsp;}<BR>&nbsp;static 
                  Bowl b2=new Bowl(2);//Ⅰ②<BR>}<BR>class Cupboard{<BR>&nbsp;Bowl 
                  b3=new Bowl(3);//Ⅱ③,Ⅳ①,Ⅵ①<BR>&nbsp;static Bowl b4=new 
                  Bowl(4);//Ⅱ①<BR>&nbsp;Cupboard(){<BR>&nbsp; 
                  System.out.println("Cupboard");//Ⅱ④,Ⅳ②,Ⅵ②<BR>&nbsp; 
                  b4.f(2);//Ⅱ⑤,Ⅳ③,Ⅵ③<BR>&nbsp;}<BR>&nbsp;void f3(int 
                  marker){<BR>&nbsp; 
                  System.out.println("f3("+marker+")");<BR>&nbsp;}<BR>&nbsp;static 
                  Bowl b5=new Bowl(5);//Ⅱ②<BR>}<BR>public class 
                  StaticInitialization {<BR>&nbsp;public static void 
                  main(String[] args) {<BR>&nbsp; System.out.println("Creating 
                  new Cupboard() in main");//Ⅲ<BR>&nbsp; new 
                  Cupboard();//Ⅳ<BR>&nbsp; System.out.println("Creating new 
                  Cupboard() in main");//Ⅴ<BR>&nbsp; new 
                  Cupboard();//Ⅵ<BR>&nbsp; t2.f2(1);//Ⅶ<BR>&nbsp; 
                  t3.f3(1);//Ⅷ<BR>&nbsp;}<BR>&nbsp;&nbsp;&nbsp; static Table 
                  t2=new Table();//Ⅰ<BR>&nbsp;&nbsp;&nbsp; static Cupboard 
                  t3=new 
                  Cupboard();//Ⅱ<BR>}<BR>结果:<BR>Bowl(1)<BR>Bowl(2)<BR>Table()<BR>f(1)<BR>Bowl(4)<BR>Bowl(5)<BR>Bowl(3)<BR>Cupboard<BR>f(2)<BR>Creating 
                  new Cupboard() in 
                  main<BR>Bowl(3)<BR>Cupboard<BR>f(2)<BR>Creating new Cupboard() 
                  in 
                  main<BR>Bowl(3)<BR>Cupboard<BR>f(2)<BR>f2(1)<BR>f3(1)<BR>&nbsp;&nbsp;&nbsp; 
                  由输出可见,静态初始化只有在必要时刻才会进行。如果不创建Table 
                  对象,也不引用Table.b1或Table.b2,那么静态的Bowl b1 和b2 永远都不会被创建。只有在第一个Table 
                  对象被创建(或者第一次访问静态数据)的时候,它们才会被初始化。此后,静态对象不会再次被初始化。 
                  <BR>&nbsp;&nbsp;&nbsp; 
                  初始化的顺序是先“静态”,(如果它们尚未因前面的对象创建过程而被初始化),后“非静态”。从输出结果中可以观察到这一点。<BR>&nbsp;<BR>4.静态块的初始化<BR>&nbsp;&nbsp;&nbsp; 
                  Java 
                  允许你将多个静态初始化动作组织成一个特殊的“静态子句”(有时也叫作“静态块”)。与其他静态初始化动作一样,这段代码仅执行一次:当你首次生成这个类的一个对象时,或者首次访问属于那个类的一个静态成员时(即便从未生成过那个类的对象)。看下面的代码:<BR>class 
                  Cup{<BR>&nbsp;Cup(int marker){<BR>&nbsp; 
                  System.out.println("Cup("+marker+")");<BR>&nbsp;}<BR>&nbsp;void 
                  f(int marker){<BR>&nbsp; 
                  System.out.println("f("+marker+")");<BR>&nbsp;}<BR>}<BR>class 
                  Cups{<BR>&nbsp;static Cup c1;<BR>&nbsp;static Cup 
                  c2;<BR>&nbsp;static{<BR>&nbsp; c1=new Cup(1);<BR>&nbsp; c2=new 
                  Cup(2);<BR>&nbsp;}<BR>&nbsp;Cups(){<BR>&nbsp; 
                  System.out.println("Cups()");<BR>&nbsp;}<BR>}<BR>public class 
                  ExpilicitStatic {<BR>&nbsp;public static void main(String[] 
                  args) {<BR>&nbsp; System.out.println("Inside 
                  main()");<BR>&nbsp; Cups.c1.f(99);//(1)<BR>&nbsp;}<BR>// 
                  static Cups x=new Cups();//(2)<BR>// static Cups y=new 
                  Cups();//(2)<BR>}<BR>结果:<BR>Inside 
                  main()<BR>Cup(1)<BR>Cup(2)<BR>f(99)<BR>&nbsp;&nbsp;&nbsp; 
                  无论是通过标为(1)的那行程序访问静态的 c1对象,还是把(1)注释掉,让它去运行标为(2) 的那行,Cups 
                  的静态初始化动作都会得到执行。如果把(1)和(2)同时注释掉,Cups 
                  的静态初始化动作就不会进行。此外,激活一行还是两行(2)代码都无关紧要,静态初始化动作只进行一次。<BR>&nbsp;<BR>5.非静态实例初始化<BR>看下面的代码:<BR>class 
                  Mug{<BR>&nbsp;Mug(int marker){<BR>&nbsp; 
                  System.out.println("Mug("+marker+")");<BR>&nbsp;}<BR>&nbsp;void 
                  f(int marker){<BR>&nbsp; 
                  System.out.println("f("+marker+")");<BR>&nbsp;}<BR>}<BR>public 
                  class Mugs {<BR>&nbsp;Mug c1;<BR>&nbsp;Mug 
                  c2;<BR>&nbsp;{<BR>&nbsp; c1=new Mug(1);<BR>&nbsp; c2=new 
                  Mug(2);<BR>&nbsp; System.out.println("c1&amp;c2 
                  initialized");<BR>&nbsp;}<BR>&nbsp;Mugs(){<BR>&nbsp; 
                  System.out.println("Mugs()");<BR>&nbsp;}<BR>&nbsp;public 
                  static void main(String[] args) {<BR>&nbsp; 
                  System.out.println("Inside main()");<BR>&nbsp; new 
                  Mugs();<BR>&nbsp;}<BR>}<BR>结果:<BR>Inside 
                  main()<BR>Mug(1)<BR>Mug(2)<BR>c1&amp;c2 
                  initialized<BR>Mugs()<BR>&nbsp;<BR>6.数组初始化<BR>&nbsp;&nbsp;&nbsp; 
                  注意区分基本类型数据与类数据的初始化。看以下代码:<BR>int[] a;&nbsp; <BR>a = new 
                  int[rand.nextInt(20)]; <BR>与<BR>Integer[] a = new 
                  Integer[rand.nextInt(20)];&nbsp; <BR>for(int i = 0; i &lt; 
                  a.length; i++) {&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp; a[i] = new 
                  Integer(rand.nextInt(500));&nbsp; <BR>}<BR>&nbsp;&nbsp;&nbsp; 
                  对于类数据类型的初始化,每个数组子成员都要重新new一下。<BR>&nbsp;<BR>7.涉及继承关系的初始化<BR>&nbsp;&nbsp;&nbsp; 
                  当创建一个导出类的对象时,该对象包含了一个基类的子对象。看下面代码:<BR>class 
                  Art{<BR>&nbsp;Art(){<BR>&nbsp; System.out.println("Art 
                  constructor");<BR>&nbsp;}<BR>} <BR>class Drawing extends 
                  Art{<BR>&nbsp;Drawing(){<BR>&nbsp; System.out.println("Drawing 
                  constructor");<BR>&nbsp;}<BR>}<BR>public class Cartoon extends 
                  Drawing{<BR>&nbsp;public Cartoon(){<BR>&nbsp; 
                  System.out.println("Cartoon 
                  constructor");<BR>&nbsp;}<BR>&nbsp;public static void 
                  main(String[] args) {<BR>&nbsp; new 
                  Cartoon();<BR>&nbsp;}<BR>}<BR>结果:<BR>Art 
                  constructor<BR>Drawing constructor<BR>Cartoon 
                  constructor<BR>&nbsp;&nbsp;&nbsp; 
                  可以发现,构建过程是从基类“向外”扩散的,所以基类在导出类构造器可以访问它之前,就已经完成了初始化。<BR>&nbsp;&nbsp;&nbsp; 
                  如果类没有缺省的参数,或者想调用一个带参数的基类构造器,就必须用关键字super显示地调用基类构造器的语句,并且配以适当的参数列表。看下面代码:<BR>class 
                  Game{<BR>&nbsp;Game(int i){<BR>&nbsp; System.out.println("Game 
                  constructor");<BR>&nbsp;}<BR>} <BR>class BoardGame extends 
                  Game{<BR>&nbsp;BoardGame(int i){<BR>&nbsp; super(i);<BR>&nbsp; 
                  System.out.println("BoardGame 
                  constructor");<BR>&nbsp;}<BR>}<BR>public class Chess extends 
                  BoardGame{<BR>&nbsp;Chess(){<BR>&nbsp; super(11);<BR>&nbsp; 
                  System.out.println("Chess 
                  constructor");<BR>&nbsp;}<BR>&nbsp;public static void 
                  main(String[] args) {<BR>&nbsp; new 
                  Chess();<BR>&nbsp;}<BR>}<BR>结果:<BR>Game 
                  constructor<BR>BoardGame constructor<BR>Chess 
                  constructor<BR>&nbsp;&nbsp;&nbsp; 
                  如果不在BoardGame()中调用基类构造器,编译器将无法找到符合Game()形式的构造器。而且,调用基类构造器必须是你在导出类构造器中要做的第一件事。<BR>&nbsp;<BR>8.构造器与多态<BR>8.1构造器的调用顺序<BR>&nbsp;&nbsp;&nbsp; 
                  基类的构造器总是在导出类的构造过程中被调用的,而且按照继承层次逐渐向上链接,以使每个基类的构造器都能得到调用。这样做是有意义的,因为构造器具有一项特殊的任务:检查对象是否被正确地构造。导出类只能访问它自己的成员,不能访问基类中的成员(基类成员通常是private类型)。只有基类的构造器才具有恰当的知识和权限来对自己的元素进行初始化。因此,必须令所有构造器都得到调用,否则就不可能正确构造完整对象。这正是编译器为什么要强制每个导出类部分都必须调用构造器的原因。<BR>&nbsp;<BR>8.2构造器内部的多态方法的行为<BR>看下面代码:<BR>abstract 
                  class Glyph{<BR>&nbsp;abstract void 
                  draw();<BR>&nbsp;Glyph(){<BR>&nbsp; 
                  System.out.println("Glyph() before draw()");<BR>&nbsp; 
                  draw();<BR>&nbsp; System.out.println("Glyph() after 
                  draw()");<BR>&nbsp;}<BR>} <BR>class RoundGlyph extends 
                  Glyph{<BR>&nbsp;private int radius=1;<BR>&nbsp;RoundGlyph(int 
                  r){<BR>&nbsp; radius=r;<BR>&nbsp; 
                  System.out.println("RoundGlyph.RoundGlyph(),radius="+radius);<BR>&nbsp;}<BR>&nbsp;void 
                  draw(){<BR>&nbsp; 
                  System.out.println("RoundGlyph.draw(),radius="+radius);<BR>&nbsp;}<BR>}<BR>public 
                  class PolyConstructors {<BR>&nbsp;public static void 
                  main(String[] args) {<BR>&nbsp; new 
                  RoundGlyph(5);<BR>&nbsp;}<BR>}<BR>结果:<BR>Glyph() before 
                  draw()<BR>RoundGlyph.draw(),radius=0<BR>Glyph() after 
                  draw()<BR>RoundGlyph.RoundGlyph(),radius=5<BR>&nbsp;&nbsp;&nbsp; 
                  在Glyph中,draw()方法是抽象的,这样设计是为了覆盖该方法。我们确实在RoungGlyph中强制覆盖了draw()。但是Glyph构造器会调用这个方法,结果导致了对RoundGlyph.draw()的调用,这看起来似乎是我们的目的。但是如果看到输出结果,我们会发现当Glyph的构造器调用draw()方法时,radius不是默认初始值1,而是0。<BR>&nbsp;&nbsp;&nbsp; 
                  解决这个问题的关键是初始化的实际过程:<BR>1)在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制零。</FONT></P>
                  <P><FONT 
                  face="Times New Roman">2)如前所述那样调用基类构造器。此时,调用被覆盖后的draw()方法(要在调用RoundGlyph构造器之前调用),由于步骤1的缘故,我们此时会发现radius的值为0。<BR>3)按照声明的顺序调用成员的初始化方法。<BR>4)调用导出类的构造器主体。<BR>9.初始化及类的加载<BR>看以下代码:<BR>class 
                  Tag{<BR>&nbsp;Tag(int marker){<BR>&nbsp; 
                  System.out.println("Tag("+marker+")");<BR>&nbsp;}<BR>} 
                  <BR>class Insect {<BR>&nbsp;private int i = 
                  9;<BR>&nbsp;protected int j,m;<BR>&nbsp;Insect() {<BR>&nbsp; 
                  System.out.println("i = " + i + ", j = " + j);<BR>&nbsp; j = 
                  39;<BR>&nbsp;}<BR>&nbsp;private static int x1 = print("static 
                  Insect.x1 initialized");<BR>&nbsp;static int print(String s) 
                  {<BR>&nbsp; System.out.println(s);<BR>&nbsp; return 
                  47;<BR>&nbsp;}<BR>&nbsp;Tag t1=new Tag(1);<BR>}<BR>public 
                  class Beetle extends Insect {<BR>&nbsp;private int k = 
                  print("Beetle.k initialized");<BR>&nbsp;public Beetle() 
                  {<BR>&nbsp; System.out.println("k = " + k);<BR>&nbsp; 
                  System.out.println("j = " + j);<BR>&nbsp; 
                  System.out.println("m = " + m);<BR>&nbsp;}<BR>&nbsp;private 
                  static int x2 = print("static Beetle.x2 
                  initialized");<BR>&nbsp;public static void main(String[] args) 
                  {<BR>&nbsp; System.out.println("Beetle 
                  constructor");<BR>&nbsp; Beetle b = new 
                  Beetle();<BR>&nbsp;}<BR>&nbsp;Tag t2=new 
                  Tag(2);<BR>}<BR>结果:<BR>static Insect.x1 initialized<BR>static 
                  Beetle.x2 initialized<BR>Beetle constructor<BR>Tag(1)<BR>i = 
                  9, j = 0<BR>Beetle.k initialized<BR>Tag(2)<BR>k = 47<BR>j = 
                  39<BR>m = 0<BR>&nbsp;&nbsp;&nbsp; 你在Beetle 上运行Java 
                  时,所发生的第一件事情就是你试图访问Beetle.main( ) (一个static 方法),于是加载器开始启动并找出 
                  Beetle 类被编译的程序代码(它被编译到了一个名为Beetle .class 
                  的文件之中)。在对它进行加载的过程中,编译器注意到它有一个基类(这是由关键字 extends&nbsp; 
                  告知的),于是它继续进行加载。不管你是否打算产生一个该基类的对象,这都要发生。<BR>&nbsp;&nbsp;&nbsp; 
                  如果该基类还有其自身的基类,那么第二个基类就会被加载,如此类推。接下来,根基类中的静态初始化(在此例中为Insect)即会被执行,然后是下一个导出类,以此类推。这种方式很重要,因为导出类的静态初始化可能会依赖于基类成员能否被正确初始化的。<BR>&nbsp;&nbsp;&nbsp; 
                  至此为止,必要的类都已加载完毕(静态变量和静态块),对象就可以被创建了。<BR>&nbsp;&nbsp;&nbsp; 
                  首先,对象中所有的原始类型都会被设为缺省值,对象引用被设为null——这是通过将对象内存设为二进制零值而一举生成的。然后,基类的构造器会被调用。在本例中,它是被自动调用的。但你也可以用super 
                  来指定对基类构造器的调用。基类构造器和导出类的构造器一样,以相同的顺序来经历相同的过程,即向上寻找基类构造器。在基类构造器完成之后(即根部构造器找到之后),实例变量(instance 
                  variables 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -