一、动态语言与静态语言的区别
静态类型语言是指在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型,某些具有类型推导能力的现代语言可能能够部分减轻这个要求. 动态类型语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
动态语言目前非常具有活力。众所周知的ECMAScript(JavaScript)便是一个动态语言,除此之外如PHP、Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。
二、对象与内存控制
成员变量:实例变量和类变量
局部变量:形参,方法中的变量,代码块中的变量
一个类只为一个类变量分配一块内存,二实例变量在每次实例化对象时都会分配一块内存空间
三种初始化的方式

public class Cat { //实例变量 String name; int age; //类变量 static int eyeNum=2; //构造函数初始化 public Cat(String name, int age) { this.name = name; this.age = age; } //指定初始化值 double weight = 2.3; //初始化块 { System.out.println("非静态初始化实例变量"); weight = 2; } public String tostring() { return "name:" + name + " " + "age:" + age + " " + "weight:" + weight+ " " + "eyeNum:" + eyeNum; } } public class lesson2variable { public static void main(String[] args) { Cat kitty = new Cat("kitty", 12); Cat hello = new Cat("hello", 12); System.out.println(kitty.tostring()); } }
三、构建器的初始化
为什么要引入构建器,为了方便程序更加灵活,在运行期间也可以对变量进行赋值,从而“现场”决定初始值。在一个类里,初始化的顺序是由变量在类中的顺序决定的,即使变量定义大量遍布在方法定义的中间,那些变量的初始化仍然会在调用任何方法之前得到初始化,---甚至在构建器之前。

class Tag { Tag(int marker) { System.out.println("Tag(" + marker + ")"); } } public class Card { Tag t1 = new Tag(1); // Before constructor Card() { // Indicate we're in the constructor: System.out.println("Card()"); t3 = new Tag(33); // Re-initialize t3 } Tag t2 = new Tag(2); // After constructor void f() { System.out.println("f()"); } Tag t3 = new Tag(3); // At end } public class Main { public static void main(String[] args) { Card t = new Card(); t.f(); // Shows that construction is done } } 运行结果: Tag(1) Tag(2) Tag(3) Card() Tag(33) f()
四、类变量和实例变量的初始化
类变量的初始化在一个类被初始化时,JVM对每个类只初始化一次,类变量只分配一次内存空间,执行一次初始化,

public class Price { final static Price InstancePRICE=new Price(2.8);//凡事讲究先来后到,此时initPrice已分配内存,但是还没有进行初始化赋值 static double initPrice=20; double currentPrice; public Price(double discount){ System.out.println("正在执行构造器"+this.initPrice); System.out.println(Price.InstancePRICE.currentPrice); currentPrice=initPrice-discount; } } //主程序 public class TestPrice { public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(Price.InstancePRICE.currentPrice); Price p1=new Price(2.8); System.out.println(p1.currentPrice); } } 运行结果: 正在执行构造器0.0 -2.8 -2.8 正在执行构造器20.0 17.2
总结:static 初始化只有在必要的时候才会进行。如果不创建一个Table 对象,而且永远都不引用Table.b1 或
Table.b2,那么static Bowl b1 和b2 永远都不会创建。然而,只有在创建了第一个Table 对象之后(或者
发生了第一次static 访问),它们才会创建

class Bowl { Bowl(int marker) { System.out.println("Bowl(" + marker + ")"); } void f(int marker) { System.out.println("f(" + marker + ")"); } } class Table { static Bowl b1 = new Bowl(1); Table() { System.out.println("Table()"); b2.f(1); } void f2(int marker) { System.out.println("f2(" + marker + ")"); } static Bowl b2 = new Bowl(2); } class Cupboard{ Bowl b3 = new Bowl(3); static Bowl b4 = new Bowl(4);//初始化的顺序是首先static(如果它们尚未由前一次对象创建过程初始化),接着是非static 对象 Cupboard() { System.out.println("Cupboard()"); b4.f(2); } void f3(int marker) { System.out.println("f3(" + marker + ")"); } static Bowl b5 = new Bowl(5); } public class StaticInitialization { public static void main(String[] args) { System.out.println( "Creating new Cupboard() in main"); new Cupboard(); System.out.println( "Creating new Cupboard() in main"); new Cupboard(); t2.f2(1); t3.f3(1); } static Table t2 = new Table(); static Cupboard t3 = new Cupboard(); } ///:~ 运行结果: Bowl(1) Bowl(2) Table() f(1) Bowl(4) Bowl(5) Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) Creating new Cupboard() in main Bowl(3) Cupboard() f(2) f2(1) f3(1)
总结:
初始化的顺序是首先static(如果它们尚未由前一次对象创建过程初始化),接着是非static 对象。大家
可从输出结果中找到相应的证据。
在这里有必要总结一下对象的创建过程。请考虑一个名为Dog 的类:
(1) 类型为Dog 的一个对象首次创建时,或者Dog 类的static 方法/static 字段首次访问时,Java 解释器
必须找到Dog.class(在事先设好的类路径里搜索)。
(2) 找到Dog.class 后(它会创建一个Class 对象,这将在后面学到),它的所有static 初始化模块都会运
行。因此,static 初始化仅发生一次——在Class 对象首次载入的时候。
(3) 创建一个new Dog()时,Dog 对象的构建进程首先会在内存堆(Heap)里为一个Dog 对象分配足够多的存
储空间。
(4) 这种存储空间会清为零,将Dog 中的所有基本类型设为它们的默认值(零用于数字,以及boolean 和
char 的等价设定)。
(5) 进行字段定义时发生的所有初始化都会执行。
(6) 执行构建器。正如第6 章将要讲到的那样,这实际可能要求进行相当多的操作,特别是在涉及继承的时
候。
五、继承的初始化
继承初始化时,首先要进行类装载

public class Insect { int i = 9; int j; Insect() { prt("i = " + i + ", j = " + j); j = 39; } static int x1 = prt("static Insect.x1 initialized"); static int prt(String s) { System.out.println(s); return 47; } } public class Beetle extends Insect { int k = prt("Beetle.k initialized"); Beetle() { prt("k = " + k); prt("j = " + j); } static int x2 = prt("static Beetle.x2 initialized"); static int prt(String s) { System.out.println(s); return 63; } public static void main(String[] args) { prt("Beetle constructor"); Beetle b = new Beetle(); } }
运行结果为:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 63
j = 39
1)发生的第一件事情是装载程序到外面找到那个基础类,若基础类含有另一个基础类,则另一个基础类随即也会载入,以此类推;
2)接下来,会在根基础类(此时是Insect)执行static 初始化,再在下一个衍生类执行,以此类推
3)必要的类已全部装载完毕,所以能够创建对象
4)首先,这个对象中的所有基本数据类型都会设成它们的默认值,而将对象句柄设为null
5)随后会调用基础类构建器
6)基础类的构建器完成以后,本类中的实例变量会按本来的顺序得以初始化。最后,执行构建器剩余的主体部分。
补充:在程序中Insect类中x1后加入final变量
final int y1 =
prt("final Insect.y1 initialized");
则输出的结果是:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
final Insect.y1 initialized }
i = 9, j = 0}
Beetle.k initialized
k = 63
j = 39
可以说明:final变量的初始化本质上是在构造器中进行的
六、父类构造器---super和this
super是指子类在调用父类指定参数的构造器
this表示子类在调用本类中指定参数的另一个构造器
当子类构造器中没有雨super和this的时候,子类构造器会自动调用父类的无参构造器
注意:super调用和this调用(super(),this())只能在构造器中使用,且必须是第一行,不能同时使用,最多只能使用一次。
但是使用super调用父类中的变量和方法时,可以不在第一句

//Creature 类 public class Creature { { System.out.println("Creature非静态初始化代码块"); } public Creature(){ System.out.println("Creature无参构造函数"); } public Creature(String name){ System.out.println("Creature有参构造函数name"+name); } } //Animal 类 public class Animal extends Creature { { System.out.println("Animal非静态初始化代码块"); } public Animal( String name){ super(name); System.out.println("animal无参构造函数"); } public Animal(String name,int age) { this(name); System.out.println("animal有参构造函数 name"+name+""+age); } } //Fox类 public class Fox extends Animal { { System.out.println("fox非静态代码块"); } public Fox(){ super("饿狼传说",12); System.out.println("fox无参构造函数执行"); } public Fox(double weight){ this(); System.out.println("fox有参构造函数执行"); } } //主程序 public class main { public static void main(String[] args) { Fox fox=new Fox(5.6); } }
运行结果:
Creature非静态初始化代码块
Creature有参构造函数name饿狼传说
Animal非静态初始化代码块
animal无参构造函数
animal有参构造函数 name饿狼传说12
fox非静态代码块
fox无参构造函数执行
fox有参构造函数执行
五、访问子类实例变量

public class Base { private int i=2; public Base(){ System.out.println(this.i);//输出值为2 this.display(); //输出值为2 } public void display(){ System.out.println(i); } } //son类 public class Son extends Base { private int i=22; public Son(){ System.out.println("son中的变量i:"+this.i); //输出值为22 i=222; } public void diplay(){ System.out.println(i); } } //主程序 public class main { public static void main(String[] args) { new Son(); } } 运行结果为: 2 2 son中的变量i:22