深化Java基础之——对象与内存控制

来源:互联网 发布:二手域名 编辑:程序博客网 时间:2024/04/24 01:10
Java是一门面向对象语言,作为Java程序员,对于对象的使用一定不陌生,本文就总结一下创建对象时发生的一些事情。

1.实例变量和类变量

  看到这个标题大家一定想到的是static关键字,没错,被static关键字修饰的变量,方法,内部类,初始化块,这些都属于类,而不具体属于某个实例对象,可以直接通过类名来调用。关于static可能造成的内存泄漏,在后面的JVM文章里总结。这里我就简单通过两个程序总结一下类成员和实例成员的区别,以及创建一个对象后初始化的顺序。

  实例变量属于对象,每实例化一个对象,就会为其在内存中分配一块空间。类变量只会在第一次使用该类时为其分配一份内存空间,无论创建了多少个该类的对象,static变量永远只有一份内存空间。一个类在使用之前,就会在JVM中对该类进行加载-连接-初始化,在连接时就会给类变量分配相应的内存空间。

 1 public class B extends A { 2     public int m = method3(); 3     public static int n = method4(); 4     public int t = 0; 5     public B(){ 6         System.out.println(4); 7     } 8     public int method3(){ 9         System.out.println(5);10         return 5;11     }12     public static int method4(){13         System.out.println(6);14         return 6;15     }16     public static void main(String[] args) {17         System.out.println(7);18         A a = new B();19     }20 }21 22 class A {23     public int i = method();24     public static int j = method2();25     public int k = 0;26     public A(){27         System.out.println(1);28     }29     public int method(){30         System.out.println(2);31         return 2;32     }33     public static int method2(){34         System.out.println(3);35         return 3;36     }37 }

A、7 3 2 1 6 4 5        B、3 6 7 2 1 5 4         C、7 3 6 2 1 5 4        D、3 2 1 7 6 5 4

看看上述代码的输出结果应该选哪个呢?

让我们一步一步来分析:A类是B类的父类,在执行程序时,A类先被加载,并且为其类变量分配内存空间,所以先为24行的 j 分配内存,初始化为methond2()方法的返回值,这里的method2()也必须被static修饰,才能被调用,所以先输出3;同理,接下来为B类的类变量分配空间,输出6;然后执行16行main()方法,输出7;实例化B类的对象,先执行其父类(A)的非静态初始化(代码23行),method()方法输出2;然后是父类(A)的构造方法,输出1;然后是B类同理,依次输出5和4,程序结束,所以最终答案是B。

这个代码大家可以复制下来进行单步debug来细细体会。

 

再来看一个有趣的代码,细细品味。

 1 public class PriceTest { 2  3     public static void main(String[] args) { 4         System.out.println(Price.instance.currentPrice); 5         //显示的创建Price对象 6         Price p = new Price(2.8); 7         System.out.println(p.currentPrice); 8     } 9 }10 11 class Price{12     //类变量13     final static Price instance = new Price(2.8);14     //类变量15     static double initPrice = 20;16     //实例变量17     double currentPrice;18     public Price(double discount){19         currentPrice = initPrice - discount;20     }21 }

上述代码输出了两次currentPrice,而且都是通过new Price(2.8)来创建实例,看起来应该是输出两次17.2,亲自运行一下这个代码,会发现结果却是-2.8和17.2。

下面从内存层面上来看看到底发生了什么,当然,首先还是先为Price类的类变量分配内存空间,这个时候两个static变量instance和initPrice值为null和0.0,接下来按这个顺序为它们初始化,instance的值为new Price(2.8),立即执行18行,所以这时的currentPrice是等于0.0 - 2.8的,instance初始化完毕,然后是initPrice初始化为20。所以第4行输出-2.8,执行第6行时,类变量initPrice已经为20,所以第7行输出17.2。

0 0
原创粉丝点击