Java中的变量
2.成员变量:
- 成员变量可以使用Java语言中任何一种数据类型(包括基本类型和引用类型);
- 在定义成员变量时可以对其初始化,如果不初始化,java会使用默认的值对其初始化(引用类型为null,布尔类型为false,其余基本类型的初始值都为0);
分类:(1)类属性(以static修饰):类属性从这个类的准备阶段开始存在,直到系统完全销毁这个类,类属性的作用域与这个类的生存周期相同;类属性可以理解为类成员变量,与类共存亡;只要类存在,程序就可以访问该类的类属性,在程序中可以通过如下格式:类.类属性。一个类属性的内存空间只有一个,多个该类的对象共享该类属性的内存;类属性从这个类的准备阶段起开始存在,直到系统完全销毁这个类,类属性的作用域与这个类的生存范围相同;
(2)实例属性(不以static修饰):实例属性从这个类的实例被创建开始起存在,直到系统完全销毁这个实例,实例属性的作用域与该实例的生存周期相同;实例属性可以理解为实例的成员变量,它作为实例的一个成员,与实例共存亡;只要实例存在,程序就可以访问该实例属性,在程序中可以通过如下格式: 实例.实例属性。每个对象通过对应的类实例化后会有一个实例属性;
提示:一个类在使用之前要经过类加载、类验证、类准备、类解析、类初始化等几个阶段:
A)类加载load:从字节码二进制文件——.class文件将类加载到内存,从而达到类的从硬盘上到内存上的一个迁移,所有的程序必须加载到内存才能工作。将内存中的class放到运行时数据区的方法区内,之后在堆区建立一个java.lang.Class对象,用来封装方法区的数据结构。这个时候就体现出了万事万物皆对象了,干什么事情都得有个对象。就是到了最底层究竟是鸡生蛋,还是蛋生鸡呢?类加载的最终产物就是堆中的一个java.lang.Class对象。
B)连接:连接又分为以下小步骤
验证:出于安全性的考虑,验证内存中的字节码是否符合JVM的规范,类的结构规范、语义检查、字节码操作是否合法、这个是为了防止用户自己建立一个非法的XX.class文件就进行工作了,或者是JVM版本冲突的问题,比如在JDK6下面编译通过的class(其中包含注解特性的类),是不能在JDK1.4的JVM下运行的。
准备:将类的静态变量进行分配内存空间、初始化默认值。(对象还没生成呢,所以这个时候没有实例变量什么事情)
解析:把类的符号引用转为直接引用(保留)
C)类的初始化: 将类的静态变量赋予正确的初始值,这个初始值是开发者自己定义时赋予的初始值,而不是默认值。
3.局部变量:
- 局部变量可以使用java语言中的任何一种数据类型;
- 除了形参外,局部变量都必须进行显式初始化,如果不初始化,编译不会通过;
分类:(1)形参(方法签名中定义的变量):作用域在在整个方法内;当类或对象调用某个方法时,系统会在该方法栈区为所有形参分配内存空间,并将实参的值赋给对应形参,这样就完成了形参的初始化;
(2) 方法局部变量(在方法内定义):作用域从定义该局部变量的地方开始生效,到该方法结束时消失;
(3)代码块局部变量(在代码块内定义):作用域从定义该变量的地方开始生效,到该代码块结束时失效;
class Person{
public String name;
public static int num;
}
…………
Person p1 = new Person(); //创建第一个对象;
Person p2 = new Person(); //创建第二个对象;
…………
系统第一次使用Person这个类时,系统第一次使用就会加载这个类,并初始化;在类的准备阶段,系统会为该类的类
属性分配内存空间,并指定默认初始值,如下图所示:
随后,系统就会在栈内存中为P1开辟一块内存空间,该内存存储的是堆里面的地址,通过P1指向堆内存的具体数据;
当调用这两个代码语句的方法或代码块结束时,P1和P2分配在栈空间的内存就会被回收清除掉。如图所示:
P1.name = "Tom";
P2.name = "Jack";
P1.num = 1;
P2.num = 2;
调用以上语句后,内存变为下图所示: