Java初始化顺序

来源:互联网 发布:西门子编程电缆用不了 编辑:程序博客网 时间:2024/06/07 07:19


实例变量的实例化

 

三个地方:

  1. 定义实例变量指定初始值
  2. 非静态初始化块中对实例变量指定初始值
  3. 构造器中对实例变量指定初始值

 

其中,1、2中方式比第三种方式更早执行,1、2种执行顺序与它们在源程序中的排列顺序相同。

 

 

类变量的初始化

 

两个地方:

  1. 定义是指定
  2. 静态初始化块中指定

 

这两种方式的执行顺序与它们在源程序中的排列顺序相同

 

复制代码
public class StaticInitTest {    static int count = 2;        static {        System.out.println("StaticInitTest静态初始化块");        name = "Java编程";    }        static String name = "疯狂java讲义";        public static void main(String[] args) {                System.out.println("count类变量的值:" + StaticInitTest.count);        System.out.println("name类变量的值:" + StaticInitTest.name);    }}
复制代码

输出:

StaticInitTest静态初始化块

count类变量的值:2

name类变量的值:疯狂java讲义

解析:name刚开始赋值为Java编程

 

 

 

 

从内存看Java实例化

复制代码
class Price {    final  static Price INSTANCE = new Price(2.8);        static double initPrice = 20;        double currentPrice;    public Price(double discount){                currentPrice = initPrice - discount;    }    }public class PriceTest{        public static void main(String[] args) {                System.out.println(Price.INSTANCE.currentPrice);                Price p = new Price(2.8);                System.out.println(p.currentPrice);    }}
复制代码

输出:-2.8

17.2

 

解析:

初始化分为以下两个阶段:

1.  系统为Price的两个类变量分配内存空间

2.  按初始化代码的排列顺序执行初始化

 

Java初始化的内存分配

(注意java在继承变量和方法的时候是有区别的)

当变量的编译时类型和运行时类型不同时,通过该变量访问它引用的对象的实例变量时,该实例变量的值由声明该变量的类型决定。但通过该变量调用它引用的对象的实例方法时,该方法的行为将由它实际所引用的对象来决定。

 

原因:Java编译器会将父类的方法加到子类中去,而父类中的实例变量则不会。

 

结论:当一个程序创建一个子类对象时,系统不仅会为该类中定义的实例变量分配内存,也会为其父类中定义的所有实例变量分配内存。

 

复制代码
public class Test {    public static void main(String[] args) {                new Derived();    }}class Base{        private int i = 2;    public Base(){        //要弄清楚这里的this指向的是子类        //可以通过this.getClass开看        //所以this.display()调用的是子类的,输出的i当然就是子类的i了        this.display();    }        public void display(){        System.out.println(i);    }}class Derived extends Base{        private int i = 22;        public Derived(){        i = 222;    }        public void display(){        System.out.println(i);    }}输出:0
复制代码

 

复制代码
例子2:class Animal{        private String desc;    public Animal(){        this.desc = getDesc();    }        public String getDesc(){            System.out.println("Animal");        return "Animal";    }}public class Wolf extends Animal{    private String name;    private double weight;        public Wolf(String name, double weight){                this.name = name;        this.weight = weight;    }        @Override    public String getDesc(){                System.out.println("Wolf[name=" + name + " ,weight=" + weight +"]");        return "Wolf[name=" + name + " ,weight=" + weight +"]";    }        public static void main(String[] args) {                System.out.println(new Wolf("灰太狼", 32.3));    }}
复制代码

 

 

输出:Wolf[name=null ,weight=0.0]

javaSyntax.Wolf@770848b9

 

解析:因为子类重写了父类的方法,所以实例化子类实例时,不会把父类的那个方法复制过来,所以getDesc()调用的是子类的重写方法

 

 

例子3:

 

复制代码
class Fruit{        String color = "未确定颜色";        public Fruit getThis(){                return this;    }        public void info(){                System.out.println("Fruit 方法");    }}public class Apple extends Fruit{    @Override    public void info(){                System.out.println("Apple 方法");    }        //通过super调用父类的info()方法    public void AccessSuperInfo(){                super.info();    }        //尝试返回super关键子代表的内容    public Fruit getSuper(){                return super.getThis();    }        String color = "红色 ";        public static void main(String[] args) {                Apple a = new Apple();        Fruit f = a.getSuper();                System.out.println("a和f所引用的对象是否相同:" + (a == f));        System.out.println("访问a所引用对象的color实例变量: " + a.color);        System.out.println("访问f所引用对象的color实例变量:" + f.color);                a.info();        f.info();                //调用AccessSuperInfo来调用父类的info()方法        a.AccessSuperInfo();            }}
0 0
原创粉丝点击