5 面向对象上

5.3成员变量和局部变量

  • Java变量分:成员变量和局部变量。
  • 成员变量和局部变量的运行机制存大差异

5.3.1成员变量和局部变量

  • 成员变量
    • 类里定义的变量
  • 局部变量
    • 方法里定义的变量。
  • 第一个单词首字母小写,后面每个单词首字母大写。
  • 类变量从该类的准备阶段起开始存在,
    • 直到系统销毁这个类,类变量的作用域与这个类的生存范围相同:
  • 实例变量从该类的实例被创建起开始存在
    • 直到系统销毁这实例
    • 实例变量的作用域与对应实例的生存范围相同

在这里插入图片描述

在这里插入图片描述

  • 定义Person类,类中定义两成员变量
    • 实例变量:name,类变量: eyenum
  • 创Person实例,通过Person类和Person实例来访问实例变量和类变量

在这里插入图片描述

  • 成员变量无须显式初始化,只要为一个类定义了类变量或实例变量,
  • 系统就在这个类的准备阶段或创建该类的实例时进行默认初始化,
  • 成员变量默认初始化时的赋值规则与
    • 数组动态初始化时数组元素的赋值规则完全相同。

  • 类变量的作用域比实例变量的作用域更大:
    • 实例变量随实例的存在而存在,
    • 类变量则随类的存在而存在。
  • 实例也可访问类变量,同一个类的所有实例访问类变量时,
    • 实际上访问的是该类本身的同一个变量,
    • 同一片内存区。

在这里插入图片描述

  • 局部变量如下三种
  • 形参:在定义方法签名时定义的变量,形参的作用域在整个方法内有效
  • 方法局部变量:
  • 代码块局部变量:在代码块中定义的局部变量,这个局部变量的作用域从定义该变量的地方生效,到该代码块结束时失效

  • 局部变量除形参之外,都必须显式初始化。
  • 须先给方法局部变量和代码块局部变量指定初始值,否则不可访问它们。

在这里插入图片描述

  • 只要离开了代码块局部变量所在的代码块,这个局部变量就立即被销毁,不可见

  • 方法局部变量作用域从定义该变量开始,直到该方法结束

    在这里插入图片描述

  • 当通过类或对象调用某个方法时,
    • 系统会在该方法栈区内为所有的形参分配内存空间,
    • 并将实参的值赋给对应的形参,这就完成了形参的初始化。
    • 形参的传递机制请参阅5.2.2节
  • 同一类里,成员变量的作用范围是整个类内有效,
    • 一个类不能定义两个同名的成员变量
    • 即使一个是类变量,一个是实例变量也不
  • 同一方法中不同代码块内的代码块局部变量可同名
  • 如果先定义代码块局部变量,后定义方法局部变量,
    • 前面定义的代码块局部变量与后面定义的方法局部变量也可同名

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

在这里插入图片描述

  • 局部变量覆盖成员变量时,
    • 依然可在方法中显式指定类名和this作为调用者来访问被覆盖的成员变量
  • 尽量避免这种局部变量和成员变量同名的情形。

5.3.2成员変量的初始化和内存中的运行机制

  • 当系统加载类或创建该类实例时,系统自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值。

在这里插入图片描述

  • Person pl= new Person();时
  • 如果这行代码第一次用Person类,则系统会在第一次使用Person类时加载这个类,并初始化这个类。
  • 在类的准备阶段,系统为该类的类变量分配内存空间,并指定默认初始值。
  • 当Person类初始完成后,如图5.10

在这里插入图片描述

  • 图5.10,当Person类初始化完成后,系统在堆中为Person类分配一块内存区(当Person类初始化完成后,系统为Person类创一个类对象,具体参考18章),这块内存区里含eyenum类变量的内存,并默认初始值:0。

  • 系统接着创建了Person对象,并把这个Person对象赋给p1,Person对象里含名为name的实例变量,实例变量是在创建实例时分配内存空间并指定初始值的。
  • 当创建了第一个 Person对象后,存储示意图如图5.11

在这里插入图片描述

  • 图5.11中
  • eyenum类变量不属于Person对象,它属于Person类,所以创建第
    一个 Person对象时并不需要为 eyenum类变量分配内存,系统只为name实例变量分配了内存空间,并指定默认初始值:null

  • Person p2= new Person();
  • 代码创建第二个 Person对象,此时因为 Person类已经存在于堆
    内存中了,所以不需对 Person类初始化。
  • 创建第二个 Person对象与创建第一个 Person对象并没有什么不同。

  • p1.name="张三"时,将p1的name实例变量赋值,
    • 让图5.11中堆内存中的name指向”张三"字符串。
    • 执行完后,示意图如图5.12

在这里插入图片描述

  • 5.12看出,name实例变量是属于单个Person实例的
  • pl.eyenum=2;时,此时通过Person对象来修改Person的类变量,
    • 图5.12中,Person对象根本没保存eyenum这个变量,
    • 通过p1访问的eyenum类变量,还是Person类的eyenum类变量
    • 此时修改的是 Person类的 eyenum类变量
  • 修改成功后,内存中的存储示意图如图5.13

在这里插入图片描述

  • 图5.13看出,当通过p1访问类变量时,实际上访问的是Person类的 eyenum类变量
  • 事实上,所有的 Person实例访问 eyenum类变量时都将访问到 Person类的 eyenum类变量,也就是图5.13中灰色覆盖的区域。
  • 建议读者,当程序需要访问类变量时,尽量使用类作为主调,而不要使用对象作为主调,这样可以避免程序产生歧义,提高程序的可读性。

在这里插入图片描述

5.3.3局部変量的初始化和内存中的运行机制

here!!!

发布了558 篇原创文章 · 获赞 295 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/zhoutianzi12/article/details/105414610