成员变量被分为类变量和实例变量两种,定义成员变量时没有static修饰的就是实例变量,有static修饰的就是类变量。其中类变量从该类的准备阶段起开始存在,直到系统完全销毁这个类,类变量的作用域与这个类的生存范围相同;而实例变量则从该类的实例被创建起开始存在,直到系统完全销毁这个实例,实例变量的作用域与对应实例的生存范围相同。
可以把类变量和实例变量统称为成员变量,其中类变量可以理解为类成员变量,它作为类本身的一个成员,与类本身共存亡;实例变量则可理解为实例成员变量,它作为实例的一个成员,与实例共存亡。
  只要类存在,程序就可以访问该类的类变量。在程序中访问类变量通过如下语法:
  类.类变量
  只要实例存在,程序就可以访问该实例的实例变量。在程序中访问实例变量通过如下语法:
  实例.实例变量
  当然,类变量也可以让该类的实例来访问。通过实例来访问类变量的语法如下:
  实例.类变量
  但由于这个实例并不拥有这个类变量,因此它访问的并不是这个实例的变量,依然是访问它对应类的类变量。也就是说,如果通过一个实例修改了类变量的值,由于这个类变量并不属于它,而是属于它对应的类。因此,修改的依然是类的类变量,与通过该类来修改类变量的结果完全相同,这会导致该类的其他实例来访问这个类变量时也将获得这个被修改过的值。
  

class Person{public String name;public static int eyeNum;
}public class PersonTest {public static void main(String[] args) {System.out.println("Person的eyeNum类变量值:" + Person.eyeNum);Person p = new Person();System.out.println("p变量的name变量值是: " + p.name + " p对象的eyeNum变量值是: " + p.eyeNum);p.name = "孙悟空";p.eyeNum = 2;System.out.println("p变量的name变量值是: " + p.name + " p对象的eyeNum变量值是: " + p.eyeNum);System.out.println("Person的eyeNum类变量值:" + Person.eyeNum);Person p2 = new Person();p2.name = "张三";p2.eyeNum = 3;Person p3 = new Person();p3.name = "李四";p2.eyeNum = 4;System.out.println("p1对象的eyeNum类变量值:" + p.eyeNum);System.out.println("Person的eyeNum类变量值:" + Person.eyeNum);System.out.println("p2对象的eyeNum类变量值:" + p2.eyeNum);System.out.println("p1对象的name类变量值:" + p.name);System.out.println("p2对象的name类变量值:" + p2.name);System.out.println("p3对象的name类变量值:" + p3.name);}
}

outputs:

Person的eyeNum类变量值:0
p变量的name变量值是: null p对象的eyeNum变量值是: 0
p变量的name变量值是: 孙悟空 p对象的eyeNum变量值是: 2
Person的eyeNum类变量值:2
p1对象的eyeNum类变量值:4
Person的eyeNum类变量值:4
p2对象的eyeNum类变量值:4
p1对象的name类变量值:孙悟空
p3对象的name类变量值:李四
p2对象的name类变量值:张三

  当Person类初始化完成后,系统将在堆内存中为Person类分配一块内存区,在这块内存区里包含了保存eyeNum类变量的内存,并设置eyeNum的默认初始值:0.
系统接着创建了一个Person对象,并把这个Person对象赋给p变量,Person对象里包含了名为name的实例变量,实例变量是在创建实例时分配内存空间并指定初始值的。
eyeNum类变量并不属于Person对象,它是属于Person类的,所以创建第一个Person对象时并不需要为eyeNum类变量分配内存,系统只是为name实例变量分配了内存空间,并指定默认初始值:null.
  接着执行Person p2 = new Person();代码创建第二个Person 对象,此时因为Person 类已经存在于对内存中了,所以不再需要对Person 类进行初始化。创建第二个Person 对象与创建第一个Person 对象并没有什么不同。
  name实例变量是属于单个Person实例的,因此修改第一个Person对象的name实例变量时仅仅与该对象有关,与Person类和其他Person对象没有任何关系。同样,修改第二个Person对象的name实例变量时,也与Person类和其他Person对象无关。
执行p.eyeNum = 2;代码时,此时通过Person对象来修改Person的类变量,Person对象根本没有保存eyeNum这个变量,通过p访问的eyeNum类变量,其实还是Person类的eyeNum类变量。因此,此时修改的是Person类的eyeNum类变量。
  当通过p来访问类变量时,实际上访问的是Person类的eyeNum类变量。事实上,所有的Person实例访问eyeNum类变量时都将访问到Person类的eyeNum类变量,本质其实还是通过Person类来访问eyeNum类变量时,他们所访问的是同一块内存。因此,建议当程序需要访问类变量时,尽量使用类作为主调,而不要使用对象作为主调,这样可以避免程序产生歧义,提高程序的可读性。

转载于:https://www.cnblogs.com/ycyoes/p/6050025.html

成员变量的初始化和内存中的运行机制相关推荐

  1. java成员变量和局部变量的初始化和内存中的运行机制

    成员变量: 当系统加载类或创建类的实例时,系统会自动为成员变量分配内存空间,并在分配内存空间后,自动为成员变量指定初始值. eyeNum是类属性.name是实例属性 所有person实例访问eyeNu ...

  2. 构造方法的调用顺序和成员变量的初始化时机以及动态绑定

    构造方法的调用顺序:子类构造器中,JVM会自动的先调用父类的构造方法,然后再执行子类构造方法.在JVM自动调用父类构造方法的时候,会完成父类中拥有的成员变量的值的初始化操作,此时子类的成员变量并未初始 ...

  3. 1.c++中初始化列表和构造函数初始化的区别是什么?2.类的成员变量的初始化顺序是按照声明顺序吗?

    初始化列表和构造函数初始化的区别是什么? 初始化和赋值对内置类型的成员没有太大的区别,在成员初始化列表和构造函数体内进行,在性能和结果上都是一样的.只有一些需要注意的事项 初始化列表一般情况如下: D ...

  4. C++类中成员变量的初始化有两种方式

    C++类中成员变量的初始化有两种方式: 构造函数初始化列表和构造函数体内赋值.下面看看两种方式有何不同. 成员变量初始化的顺序是按照在那种定义的顺序. 1.内部数据类型(char,int--指针等) ...

  5. C++类中成员变量的初始化总结

    C++类中成员变量的初始化总结 1. 普通的变量: 一般不考虑啥效率的情况下 可以在构造函数中进行赋值.考虑一下效率的可以再构造函数的初始化列表中进行.  1 class CA   2 {   3 p ...

  6. C++中类成员变量在初始化列表中的初始化顺序

    引子:我们知道,C++中类成员变量的初始化顺序与其在类中的声明顺序是有关的. 先看代码: 1 class TestClass1 2 { 3 public: 4 TestClass1() { 5 cou ...

  7. C++成员变量的初始化顺序问题

    C++成员变量的初始化顺序问题 由于面试题中,考官出了一道简单的程序输出结果值的题:如下, [cpp] view plain copy  print? class A { private: int n ...

  8. 【C/C++】成员变量的初始化顺序

    变量的初始化顺序: ① 基类的静态变量或全局变量 ②派生类的静态变量或全局变量 ③基类的成员变量 ④派生类的成员变量 注意: ①成员变量在使用初始化列表初始化时,与构造函数中初始化成员列表的顺序无关, ...

  9. Java面向对象05:创建对象的内存分析成员变量和局部变量的内存分析

    一.创建对象内存分析 代码 public class Pet {//宠物类//类的属性public String name;//宠物名public int age ; //宠物年龄public Str ...

最新文章

  1. 20以内分数化小数表_数与代数之小数
  2. php扩展模块安装-lamp
  3. 使用图片方式自定义iOS导航栏navigationItem的backBarButtonItem
  4. Ambiguous mapping found. Cannot map 'xxxxController' bean method
  5. 8个适合新手入门的python项目2020_8个适合新手入门的Python项目(2020.6)
  6. uva 10110——Light, more light
  7. rocketmq原理_彻底看懂RocketMQ事务实现原理
  8. 【操作系统】进程与程序的比较
  9. 机器学习(八)支持向量机svm终结篇
  10. Linux用户对System76的Darter Pro笔记本电脑的评论
  11. Eplan教学视频合集-百度网盘-收集于网络,供参考
  12. Linux——就业方向选择、学习内容、学习方法
  13. SpringMVC入门运行成功的实例(一)
  14. windows写注册表文件脚本的编写
  15. 传奇服务器人物技能怎么修改,传奇服务端上线0级技能,直接设置3级技能的设置方法...
  16. Cesium PolygonGeometry的移动、拉伸、旋转——拉伸
  17. Allegro创建区域规则
  18. Jenkins Pipeline预研
  19. Linux---C语言连接数据库(1)
  20. 【Python 基础教程】一文理清Python函数的细枝末节

热门文章

  1. transient关键字的作用_ArrayList Vector (transient关键字)--JAVA成长之路
  2. 实战|渗透学校某内网服务器
  3. 使用PHP得到所有的HTTP请求头
  4. python3爬虫初探(八)requests
  5. 从DSSM语义匹配到Google的双塔深度模型召回和广告场景中的双塔模型思考
  6. Hbase总结(八)Hbase中的Coprocessor
  7. H5与企业微信jssdk集成
  8. [转载]Linux下getopt()函数的简单使用
  9. 一张图看懂H5、混合应用、微信小程序
  10. Spring实战6-利用Spring和JDBC访问数据库