您的位置:首页 > 其它

对象与内存控制之实例变量与类变量

2016-09-06 14:06 253 查看
工作中,不仅仅要停留在代码层次写程序,还要考虑每行代码对系统内存的影响,要熟悉java对象内存分配机制!

1 java内存管理分为内存分配和内存回收

1.1 内存分配

创建java对象是jvm为该对象在堆内存中所分配的内存空间

1.2 内存回收

当改java对象失去引用,变成垃圾是,jvm垃圾回收机制自动清理该对象,并回收该对象所占用的内存。

注:jvm垃圾回收机制由一条后台线程完成,本身也是非常消耗性能的。如果随便的创建对象,让系统分配内存,有垃圾回收机制回收,这样有两个问题

1.不断分配内存使得系统中可用内存减少,从而降低程序运行性能

2.大量已分配内存的回收使得垃圾的负担加重,降低程序的运行性能

2. 实例变量和类变量

1.实例变量属于Java对象

java程序变量可分为成员变量和局部变量,

局部变量可分为三类

1)形参

2)方法内的局部变量

3)代码块的局部变量

局部变量的作用时间短,他们都被存储在方法的栈内存中。

成员变量

类变量属于类本身

static关键字:静态,作用是将实例成员变成类成员

java要求定义成员变量是必须采用合法的向前引用。

1)

package qianglih;

public class ErrorDef {
//下面代码将提示:非法向前引用
int num1=num2+2;
int num2=20;

}

2)

package qianglih;

public class ErrorDef {
//下面代码将提示:非法向前引用
static int num1=num2+2;
static int num2=20;

}

3)但如果是一个实例变量,一个类变量,则实例变量总是可以引用类变量

package qianglih;

public class ErrorDef {
//下面代码将正确编译
int num1=num2+2;
static int num2=20;

}

注:这是因为类变量的初始化时机总是处在实例变量的初始化时机之前。

2.1 实例变量和类变量的属性。

由于同一个jvm内每个类只对应一个class对象,因此同一个jvm内的一个类的类变量只需一块内存空间;但对于实例变量而言,

该类每创建一次实例。就需要为实例变量分配一块内存空间。

package qianglih;

public class FieldTest {
public static void main(String[] args) {
//类变量属于该类本身,主要该类初始化完成,程序即可使用类变量
Person.eyeNum=2;
//创建一个Person对象
Person p=new Person();
p.name="pig";
p.age=200;
System.out.println("通过p变量访问eyeNum类变量:"+p.eyeNum);//2
//创建第二个Person对象
Person p2=new Person();
p2.name="moneky";
p2.age=500;
p2.eyeNum=3;
System.out.println("通过p变量访问eyeNum类变量:"+p.eyeNum);//3
System.out.println("通过p2变量访问eyeNum类变量:"+p2.eyeNum);//3
System.out.println("通过Person变量访问eyeNum类变量:"+Person.eyeNum);//3

}

}
class Person{
String name;
int age;
static int eyeNum;
}

注:一旦Person类初始化完成,程序即可通过Person类访问eyeNum类变量,除此之外,java还允许通过Person类的任意实例来访问eyeNum类变量------个人认为这是java设计不合理的地方,既然属于Person类的实例,那就应该禁止通过Person实例来访问eyeNum类变量。

虽然Java允许通过Person对象来访问Person类的eyeNum类变量,但低层依然会转化为通过Person访问eyeNum类变量。





2.2.实例变量的初始化的细节

每次创建java对象都会为实例变量分配内存空间,程序可以在三个地方对实例变量执行初始化

1)定义实例变量时指定初始值

2)非静态初始化中对实例变量指定初始值

3)构造器中对实例变量指定初始值

注:定义变量时指定的初始值和初始块中指定的初始值得执行顺序,与他们在源程序中的排列顺序相同,且都先与构造器方法。

类经过编译处理之后,初始块消失了,构造器包含了初始块里的语句,而且该类中定义的实例变量不再有初始值,其指定的初始化代码也被提取到了构造器里!

2.3类变量的初始化时机

1)定义类变量时指定初始化

2)静态初始块中对类变量指定初始值

package qianglih;

public class PriceTest {

public static void main(String[] args) {
//通过Price的INSTANCE访问currentPrice实例变量
System.out.println(Price.INSTANCE.currentPrice);//-2.8
//显示创建Price实例
Price p=new Price(2.8);
//通过显示创建的Price实例访问currentPrice实例变量
System.out.println(p.currentPrice);//17.2
}

}
class Price{
//类成员是Price实例
final static Price INSTANCE= new Price(2.8);
//再定义一个类变量
static double initPrice=20;
//定义该Price的currentPrice实例变量
double currentPrice;
public Price(double discount){
currentPrice=initPrice-discount;
}
}

输出 -2.8和17.2.

从内存角度来分析:

初始化第一阶段,系统为INSTANCE,intPrice两个类变量分配内存空间,此时INSTANCE、initPrice的值为默认值null,0.0。接着初始化进去第二个阶段,程序按顺序依次为INSTANCE、initPrice进行赋值。对INSTANCE赋值时调用Price(2.8),创建Price实例,此时initPrice类变量为0,所以currentPrice为-2.8,接着程序给initPrice赋值为20;

当再次创建Price实例时,该Price实例的currentPrice实例变量的值才等于20.0-discount。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐