• 4.3 成员变量和局部变量


    一、定义

    成员变量指的是在类里面定义的变量,也就是前面所说的field;局部变量指的是在方法里定义的变量。
    Java程序里的变量划分为如图所示:

    1.1 成员变量

    成员变量可以不用初始化,系统会为它分配默认初始值。初始化规则与数组初始化规则相同。
    成员变量分为类变量和实例变量两种,定义成员变量时,有static修饰的是类变量,类变量从该类准备阶段起开始存在,知道系统完全销毁这个类,类的作用域与这个类的生存范围相同;无static修饰的是实例变量,实例变量则从该类的实例被创建起开始存在,直到系统完全销毁这个类,实例变量的作用域与对于实例的生存范围相同。
    只要类存在,程序就可以访问类变量,访问类变量的语法格式:

    类名.类变量
    

    只要实例存在,程序就可以访问实例变量,访问实例变量的语法格式:

    实例.实例变量
    

    注意:类变量也可以用该类的实例来访问,但实质上还是通过该类来访问类变量,语法格式:

    实例.类变量
    

    既是说通过一个实例来修改了类变量的值,由于这个类变量并不属于它,而是属于对于的类。因此修改的仍然是类变量,与通过该类来修改类变量完全相同,这也会导致通过其他实例来访问这个类变量也是被修改的值。

    class FieldTest 
    {
    	//定义一个类变量
    	public static String name;
    	//定义一个实例变量
    	public int a;
    
    	public static void main(String[] args) 
    	{
    		//定义两个FieldTest类的实例
    		var p1=new FieldTest();
    		var p2=new FieldTest();
    
    		//访问类变量name;:系统分配默认初始值null
    		System.out.println(FieldTest.name);
    		//下面通过实例方式访问类变量,实质也是通过类来访问
    		System.out.println(p1.name);
    
    		//通过实例p1来修改类变量和实例变量
    		p1.name="Java";
    		p1.a=10;
    
    		//通过实例p1访问类变量和实例变量
    		System.out.println(p1.name);
    		System.out.println(p1.a);
    
    		//通过实例p2访问类变量和实例变量
    		System.out.println(p2.name);//类变量已经被p1进行修改
    		System.out.println(p2.a);
    	}
    }
    ---------- 运行Java捕获输出窗 ----------
    null
    null
    Java
    10
    Java
    0
    
    输出完成 (耗时 0 秒) - 正常终止
    

    从上面可以发现:类变量的作用域比实例变量的作用域大。实例变量也可以访问类变量,同一个类的所有实例变量访问类变量时,实际上都是访问的该类的同一个变量。在以后的编程中,对于static修饰的类变量,最好用类来访问,增加程序的可读性

    1.2 局部变量

    与成员变量不同的是,局部变量除形参以外,必须进行显示初始化,也就是说,必须先给方法局部变量和代码块局部变量指定初始值,否则不可以访问它。局部变量分为三种
    1、形参:在定义方法签名时定义的变量,形参的作用域在整个方法内有效。
    2、方法局部变量:在方法体内定义的局部变量,它的作用域是从定义该变量的地方生效,到该方法结束时失效。
    3、代码块内的局部变量:在代码块定义的局部变量,这个局部变量的作用域从定义改变了的地方生效,到代码块结束的地方失效。

    {
    	public static void main(String[] args) 
    	{
    		{
    			//定义一个代码块局部变量
    			int a;
    			//下面代码将出现错误,因为变量a还未初始化
    			//System.out.println("代码块局部变量a:"+a);
    			//BlockTest.java:9: 错误: 可能尚未初始化变量a
    			a=5;
    			System.out.println("代码块局部变量a:"+a);
    		}
    
    		//在代码块外访问变量a是不存在的,超出了代码块局部变量a的作用域
    		//System.out.println(a);
    		//BlockTest.java:16: 错误: 找不到符号
    	}
    }
    ---------- 运行Java捕获输出窗 ----------
    代码块局部变量a:5
    
    输出完成 (耗时 0 秒) - 正常终止
    

    Java允许局部变量和成员变量同名,如果方法里的局部变量与成员变量同名,局部变量会覆盖成员变量,如果需要在这个方法里引用被覆盖的长远变量,则可以使用this(对于实例)或类名(对于类变量)作为调用者来访问成员变量。

    class  VariableOverrrideTest
    {
    	//定义一个name实例变量
    	private String name="U盘";
    	//定义一个price类变量
    	public static double price=55.0;
    
    	//定义普通方法
    	public void info()
    	{
    		//方法里的局部变量覆盖成员变量
    		var name="孙悟空";
    		//直接访问name变量,将输出name的局部值
    		System.out.println(name);
    
    		//使用this来输出name实例变量的值
    		System.out.println(this.name);
    	}
    	public static void main(String[] args) 
    	{
    		//方法里的局部变量会覆盖成员变量
    		var price=65.0;
    		//直接访问price变量,将输出局部变量的值
    		System.out.println(price);
    		//使用类名访问局部类变量
    		System.out.println(VariableOverrrideTest.price);
    		//运行info()
    		new VariableOverrrideTest().info();
    	}
    }
    ---------- 运行Java捕获输出窗 ----------
    65.0
    55.0
    孙悟空
    U盘
    
    输出完成 (耗时 0 秒) - 正常终止
    

    二、成员变量的初始化和内存中的运行机制

    当系统加载类或创建类的实例时,系统会为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值,初始值的规则与数组相同。

    public class  ProgramRun
    {
    	//这是一个类变量
    	public static int num;
    	//这是一个实例变量
    	public String name;
    	
    
    	public static void main(String[] args) 
    	{
    		//创建两个实例变量
    		var p1=new ProgramRun();
    		var p2=new ProgramRun();
    
    		//分别为两个Person对象的name变量赋值
    		p1.name="张三";
    		p2.name="孙悟空";
    		
    		p1.num=2;
    		System.out.println(p2.num);
    	}
    }
    ---------- 运行Java捕获输出窗 ----------
    2
    
    输出完成 (耗时 0 秒) - 正常终止
    

    (1)当程序执行到var p1=new ProgramRun();时,这行代码第一次使用Person类,则系统通常会在第一次使用Person类时加载这个类,并初始化这个类。系统为该类的类变量分配内存空间,并指定默认初始值。

    当ProgramRun类初始化完成后,系统会在堆内存中为类变量num分配一块内存区,并设置num的默认值0。
    (2)接着创建两个ProgramRun对象p1,p2,类里面包含了名为name的实例变量,实例变量在创建实例时分配内存空间并指定初始值的。

    (3)分别为两个Person对象的name变量赋值
    p1.name="张三";
    p2.name="孙悟空";

    (4)当执行到p1.num=2;时,此时通过ProgramRun对象来修改ProgramRun类的类变量,其实通过ProgramRun对象p1来访问类变量num,实质上还是通过类来访问,故通过对象p2来访问变量num,还是访问的同一块区域。

    三、局部变量的初始化和在内存中的运行机制

    局部变量定义后,必须经过显式的初始化后才能使用,系统不会为局部变量执行初始化,这意味着定义局部变量时,系统并未为其分配内存空间,知道等到程序为这个变量赋初始值时,系统才会为局部变量分配内存,并将初始值保存到这块内存中。
    局部变量不属于任何类或实例,因此它总是保存在栈内存中。栈内存中的变量无需系统垃圾回收,往往随方法或代码块的运行结束而结束。因此局部变量的作用域是从初始化该变量开始,知道该方法或代码块完成而结束。由于局部变量只保存基本类型或者对象的引用,因此局部变量所占的内存空间很小。

  • 相关阅读:
    ILockBytes Windows Mobile 6.5
    C# 中 in,out,ref 的作用与区别
    riched32.dll riched20.dll msftedit.dll 解析
    C# 解决窗体假死的状态
    testform
    ParallelProgramming-多消费者,多生产者同时运行并行
    C# 多线程控制 通讯
    C# 多线程
    iSpy免费的开源视频监控平台
    核心J2EE模式
  • 原文地址:https://www.cnblogs.com/weststar/p/12347859.html
Copyright © 2020-2023  润新知