基本知识《一》继承初始化过程

一、动态语言与静态语言的区别

静态类型语言是指在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型,某些具有类型推导能力的现代语言可能能够部分减轻这个要求. 动态类型语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。
动态语言目前非常具有活力。众所周知的ECMAScriptJavaScript)便是一个动态语言,除此之外如PHPRubyPython等也都属于动态语言,而CC++等语言则不属于动态语言。

二、对象与内存控制

成员变量:实例变量和类变量
局部变量:形参,方法中的变量,代码块中的变量
一个类只为一个类变量分配一块内存,二实例变量在每次实例化对象时都会分配一块内存空间
三种初始化的方式
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 + "\n" + "age:" + age + 
                "\n" + "weight:" + weight+ "\n" + "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());
    }
}
View Code

 

三、构建器的初始化

为什么要引入构建器,为了方便程序更加灵活,在运行期间也可以对变量进行赋值,从而“现场”决定初始值。在一个类里,初始化的顺序是由变量在类中的顺序决定的,即使变量定义大量遍布在方法定义的中间,那些变量的初始化仍然会调用任何方法之前得到初始化,---甚至在构建器之前。

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()
View Code

 

四、类变量和实例变量的初始化

类变量的初始化在一个类被初始化时,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
View Code

总结: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)
View Code

总结:

初始化的顺序是首先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();
    }
}
View Code

运行结果为:

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);
    }
}
View Code

 运行结果:

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
View Code

 

posted @ 2015-01-17 20:24  藤露  阅读(221)  评论(0编辑  收藏  举报