对象与内存控制之实例变量与类变量
2016-09-06 14:06
253 查看
工作中,不仅仅要停留在代码层次写程序,还要考虑每行代码对系统内存的影响,要熟悉java对象内存分配机制!
1.1 内存分配
创建java对象是jvm为该对象在堆内存中所分配的内存空间
注:jvm垃圾回收机制由一条后台线程完成,本身也是非常消耗性能的。如果随便的创建对象,让系统分配内存,有垃圾回收机制回收,这样有两个问题
1.不断分配内存使得系统中可用内存减少,从而降低程序运行性能
2.大量已分配内存的回收使得垃圾的负担加重,降低程序的运行性能
java程序变量可分为成员变量和局部变量,
局部变量可分为三类
1)形参
2)方法内的局部变量
3)代码块的局部变量
局部变量的作用时间短,他们都被存储在方法的栈内存中。
成员变量
类变量属于类本身
static关键字:静态,作用是将实例成员变成类成员
java要求定义成员变量是必须采用合法的向前引用。
1)
2)
3)但如果是一个实例变量,一个类变量,则实例变量总是可以引用类变量
注:这是因为类变量的初始化时机总是处在实例变量的初始化时机之前。
该类每创建一次实例。就需要为实例变量分配一块内存空间。
注:一旦Person类初始化完成,程序即可通过Person类访问eyeNum类变量,除此之外,java还允许通过Person类的任意实例来访问eyeNum类变量------个人认为这是java设计不合理的地方,既然属于Person类的实例,那就应该禁止通过Person实例来访问eyeNum类变量。
虽然Java允许通过Person对象来访问Person类的eyeNum类变量,但低层依然会转化为通过Person访问eyeNum类变量。
1)定义实例变量时指定初始值
2)非静态初始化中对实例变量指定初始值
3)构造器中对实例变量指定初始值
注:定义变量时指定的初始值和初始块中指定的初始值得执行顺序,与他们在源程序中的排列顺序相同,且都先与构造器方法。
类经过编译处理之后,初始块消失了,构造器包含了初始块里的语句,而且该类中定义的实例变量不再有初始值,其指定的初始化代码也被提取到了构造器里!
2)静态初始块中对类变量指定初始值
输出 -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。
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。
相关文章推荐
- 对象与内存控制1---实例变量和类变量
- java中如何理解多个对象共享同一个静态成员变量(多个实例的static变量会共享同一块内存区域)
- 父子实例的内存控制--继承成员变量和继承方法的区别
- 对象及内存管理——实例变量与类变量
- Java 对象中变量属性的初始化时机与内存控制
- 9.面向对象:类和对象、实例变量、类变量
- java 父子实例的内存控制 继承变量和继承方法的区别
- 【面试宝典】从对象深入分析 Java 中实例变量和类变量的区别
- 类变量(静态变量)与实例变量(对象变量)
- 从对象深入分析 Java 中实例变量和类变量的区别
- 对象及内存管理——父类与子类实例的内存控制
- 能被某个类的所有实例对象共享,这样的变量称之为类变量
- python中类变量和实例变量__之类对象属性(类变量和函数)
- java的对象、对象句柄、变量等在内存的分布
- C++程序运行时内存布局之----------简单类实例,成员变量,成员函数,静态成员变量,静态成员函数
- Objective-C 2.0 with Cocoa Foundation--- 7,对象的初始化以及实例变量的作用域
- C++程序运行时内存布局之----------简单类实例,成员变量,成员函数,静态成员变量,静态成员函数
- 什么是类变量(Class Variable),对象变量(Object Variable)
- GridBagConstraints对象的11个实例变量
- Objective-C 2.0 with Cocoa Foundation---对象的初始化以及实例变量的作用域(1)