java局部变量与成员变量相关问题总结
2013-02-03 12:39 156人阅读 评论(0) 收藏 举报
一、Java中的所有变量可以分成局部变量和成员变量。他们的区别:
1. 定义
成员变量:在类体里面定义的变量称为成员变量;
局部变量:形参、方法、代码块中定义的变量,都属于局部变量。
(注:局部变量定义必须在方法里面!)
2. 详细分类
成员变量:1)类变量(静态变量)——有static修饰;
2)实例变量(非静态变量)——没有static修饰。
局部变量:1)形参——方法签名中定义的变量;
2)方法局部变量——在方法(函数)内定义;
3)代码块局部变量——在代码块内定义(例如for循环里面的变量)。
3. 初始化
成员变量:无需显式初始化,只要为一个类定义了类变量或实例变量,则系统会在这
个类的准备阶段或创建这个类的实例时进行默认初始化。
局部变量:除了形参之外,都必须显式初始化。
4. 作用范围
成员变量:作用于整个类中;
局部变量:作用于方法(函数)中,或者语句中。
5. 在内存中的位置
成员变量:在堆内存中。因为类或对象的存在,才在内存中存在;
局部变量:在栈内存中。因为他不属于任何类或实例,因此他总是保存在其所在方法的栈内存中的。如果局部变量是基本类型的变量,则直接把这个变量的值保存在该变量对应的内存中;如果是引用类型的变量,则这个变量存放的是地址,通过该地址引用到该变量实际引用的对象或数组。
二、类变量和实例变量的区别:
1. 引用
类变量:可以向前引用;
实例变量:不可以向前引用,如果向前引用,则成为非法向前引用。
2. 归属及生命周期
类变量:属于类本身。可以理解为类成员变量。它作为类的一个成员,与类共存亡;
实例变量:属于类的实例对象。可以理解为实例成员变量。它作为实例的一个成员,
与实例共存亡。
3. 空间分配
类变量:不依赖类的实例,只在初始化时在栈内存中被分配一次空间。无论类的实例
被创建几次,都不再为类变量分配空间;
实例变量:在创建实例时分配内存空间
4. 存放位置
类变量:随着类的加载而存在于方法区中;
实例变量:随着对象的建立而存在于堆内存中。
示例代码如下:
[java] view plaincopyprint?
- class Person
- {
- String name;//实例变量
- static String country = "CN";//类变量
- public static void country()//静态成员函数
- {
- System.out.println("my country is " + country);
- }
- public void shout()
- {
- System.out.println("my name is " + name);
- }
- public void calculation(int num)//num为形参
- {
- int sum = 0;//sum为方法局部变量
- for(int i=0;i<=num;i++)//i为代码块局部变量
- {
- sum = sum + i;
- }
- System.out.println("the result is " + sum);
- }
- }
- class StaticDemo
- {
- public static void main(String[] args)
- {
- Person.country();//类可以直接访问类变量
- Person p = new Person();
- p.name = "zhagnsan";
- p.shout();
- p.calculation(100);
- }
- }
class Person { String name;//实例变量 static String country = "CN";//类变量 public static void country()//静态成员函数 { System.out.println("my country is " + country); } public void shout() { System.out.println("my name is " + name); } public void calculation(int num)//num为形参 { int sum = 0;//sum为方法局部变量 for(int i=0;i<=num;i++)//i为代码块局部变量 { sum = sum + i; } System.out.println("the result is " + sum); } } class StaticDemo { public static void main(String[] args) { Person.country();//类可以直接访问类变量 Person p = new Person(); p.name = "zhagnsan"; p.shout(); p.calculation(100); } }
三、各变量的一些要点:
1. 成员变量的初始化和在内存中的运行机制:在类的准备阶段,系统将会为该类的类变量分配内存空间(堆内存),并制定默认初始值。初始化完成后,会在堆内存中分
配一块内存区。
2. 成员变量的考虑使用情形:
1)描述某个对象的固有信息的变量,例如人的身高;
2)保存某个类,或某个实例状态信息的变量;
3)如果某个信息需要在某个类的多个方法之间进行共享,则这个信息应该使用成员变量。
3. 当成员变量的作用域扩大到类存在范围或者对象存在范围,这种范围的扩大有两个害处:
1)增大了变量的生存时间,这将导致更大的系统开销;
2)扩大了变量的作用域,这不利于提高程序的内聚性。
4.java允许局部变量和成员变量同名,如果方法里的局部变量和成员变量同名,那么局部变量会覆盖成员变量,如果需要在这个方法里使用成员变量,那么需要this(对于
实例属性)或类名(对于类属性)作为调用者来限定访问这个成员变量。
5. 类变量也可以用该类的实例来访问:实例.类变量。 (这其实是一个假象,其实是类.类变量这样来访问) 也就是说,如果通过一个实例修改了类变量的值,由于这个类
变量并不属于它,而是属于它对应的类。因此,修改的依然是类的类变量,与通过该类来修改类变量的结果完全相同,这样导致该类的其他实例在访问这个类变量时也将获
得这个被修改过的值。
6. 三种局部变量的作用域:
1)形参:在整个方法内有效;
2)方法局部变量:从定义该变量的地方生效,到该方法结束时失效;
3)代码块局部变量:从定义该变量的地方生效,到该代码块结束时失效。
7. 在java中,一个方法里面不能定义两个同名的局部变量,即使一个是方法变量,一个是代码块变量或者形参也不行。
8. 形参的初始化过程:当通过类或对象调用某个方法时,系统会在该方法区内为所有形参分配内存空间,并将实参的值赋给对应的形参,这就完成了形参的初始化。
9. 成员变量在堆内存中,因为对象的存在,才在内存中存在;而局部变量存在于栈内存中;成员函数不在堆内存中,而是在java的方法区中,成员函数的局部变量在堆内存中。
四、栈内存和堆内存小结:
1. 栈内存:某一个函数被调用时,这个函数会在栈内存里面申请一片空间,以后在这个函数内部定义的变量,都会分配到这个函数所申请到的栈。当函数运行结束时,分配给函数的栈空间被收回,在这个函数中被定义的变量也随之被释放和消失。 2. 堆内存:通过new产生的数组和对象分配在堆内存中。堆内存中分配的内存,由JVM提供的GC(垃圾回收机制)来管理。在堆内存中产生了一个数组对象后,我们还可以在栈中定义一个变量,这个栈中变量的取值等于堆中对象的首地址。栈内存中的变量就成了堆内存中数组或者对象的引用变量。我们以后就可以在程序中直接使用栈中的这个变量来访问我们在堆中分配的数组或者对象,引用变量相当于数组或者对象起的一个别名,或者代号。
五、引用变量: 引用变量是一个普通的变量,定义时在栈中分配;引用变量在被运行到它的作用域之外时就被释放,而我们的数组和对象本身是在堆中分配的,即使程序运行到使用new产生对象的语句所在的函数或者代码之后,我们刚才被产生的数组和对象也不会被释放。数组和对象只是在没有引用变量指向它,也就是没有任何引用变量的值等于它的首地址,它才会变成垃圾不会被使用,但是它任然占据着内存空间不放(这也就是我们Java比较吃内存的一个原因),在随后一个不确定的时间被垃圾回收器收走。
} public void calculation(int num)//num为形参 { int sum = 0;//sum为方法局部变量 for(int i=0;i<=num;i++)//i为代码块局部变量 { sum = sum + i; } System.out.println("the result is " + sum); } } class StaticDemo { public static void main(String[] args) { Person.country();//类可以直接访问类变量 Person p = new Person(); p.name = "zhagnsan"; p.shout(); p.calculation(100); } }
三、各变量的一些要点:
1. 成员变量的初始化和在内存中的运行机制:在类的准备阶段,系统将会为该类的类变量分配内存空间(堆内存),并制定默认初始值。初始化完成后,会在堆内存中分
配一块内存区。
2. 成员变量的考虑使用情形:
1)描述某个对象的固有信息的变量,例如人的身高;
2)保存某个类,或某个实例状态信息的变量;
3)如果某个信息需要在某个类的多个方法之间进行共享,则这个信息应该使用成员变量。
3. 当成员变量的作用域扩大到类存在范围或者对象存在范围,这种范围的扩大有两个害处:
1)增大了变量的生存时间,这将导致更大的系统开销;
2)扩大了变量的作用域,这不利于提高程序的内聚性。
4.java允许局部变量和成员变量同名,如果方法里的局部变量和成员变量同名,那么局部变量会覆盖成员变量,如果需要在这个方法里使用成员变量,那么需要this(对于
实例属性)或类名(对于类属性)作为调用者来限定访问这个成员变量。
5. 类变量也可以用该类的实例来访问:实例.类变量。 (这其实是一个假象,其实是类.类变量这样来访问) 也就是说,如果通过一个实例修改了类变量的值,由于这个类
变量并不属于它,而是属于它对应的类。因此,修改的依然是类的类变量,与通过该类来修改类变量的结果完全相同,这样导致该类的其他实例在访问这个类变量时也将获
得这个被修改过的值。
6. 三种局部变量的作用域:
1)形参:在整个方法内有效;
2)方法局部变量:从定义该变量的地方生效,到该方法结束时失效;
3)代码块局部变量:从定义该变量的地方生效,到该代码块结束时失效。
7. 在java中,一个方法里面不能定义两个同名的局部变量,即使一个是方法变量,一个是代码块变量或者形参也不行。
8. 形参的初始化过程:当通过类或对象调用某个方法时,系统会在该方法区内为所有形参分配内存空间,并将实参的值赋给对应的形参,这就完成了形参的初始化。
9. 成员变量在堆内存中,因为对象的存在,才在内存中存在;而局部变量存在于栈内存中;成员函数不在堆内存中,而是在java的方法区中,成员函数的局部变量在堆内存中。
四、栈内存和堆内存小结:
1. 栈内存:某一个函数被调用时,这个函数会在栈内存里面申请一片空间,以后在这个函数内部定义的变量,都会分配到这个函数所申请到的栈。当函数运行结束时,分配给函数的栈空间被收回,在这个函数中被定义的变量也随之被释放和消失。 2. 堆内存:通过new产生的数组和对象分配在堆内存中。堆内存中分配的内存,由JVM提供的GC(垃圾回收机制)来管理。在堆内存中产生了一个数组对象后,我们还可以在栈中定义一个变量,这个栈中变量的取值等于堆中对象的首地址。栈内存中的变量就成了堆内存中数组或者对象的引用变量。我们以后就可以在程序中直接使用栈中的这个变量来访问我们在堆中分配的数组或者对象,引用变量相当于数组或者对象起的一个别名,或者代号。
五、引用变量: 引用变量是一个普通的变量,定义时在栈中分配;引用变量在被运行到它的作用域之外时就被释放,而我们的数组和对象本身是在堆中分配的,即使程序运行到使用new产生对象的语句所在的函数或者代码之后,我们刚才被产生的数组和对象也不会被释放。数组和对象只是在没有引用变量指向它,也就是没有任何引用变量的值等于它的首地址,它才会变成垃圾不会被使用,但是它任然占据着内存空间不放(这也就是我们Java比较吃内存的一个原因),在随后一个不确定的时间被垃圾回收器收走。