变量分类和运行机制及自动装拆箱


成员变量和局部变量及运行机制

两者的区别在于定义变量的位置不同,运行的机制也有差异。成员变量定义在类中,局部变量定义在定义在方法中。

成员变量分为类变量和实例变量两种,局部变量分为形参(方法内)、方法局部变量和代码块内局部变量,比如循环内的。
变量分类
类变量的生命周期和类一样,从类准备阶段开始,到完全销毁这个类,作用域则与类的生存范围相同。而实例变量从实例被创建起开始存在,直到实例被销毁,作用域对应实例作用域。可以发现,成员变量之所以称为成员变量,是因为其与所在的整体共存亡的。

注意:类变量是属于类的,通过实例.类变量访问的依然是类变量,如果该实例修改了变量值,则其他实例访问时也将使用修改过的变量值。即访问了同一片内存区!

与成员变量不同,局部变量除了形参外,都必须显式初始化;而上面的成员变量可以进行默认初始化,赋值规则与数组动态初始化时赋值规则相同。

当通过类或对象调用某个方法时,系统1会在调用该方法栈区内为所有形参分配内存,并将实参值赋值给对应形参,即完成形参初始化。

Java允许局部变量和成员变量同名,如果需要在方法内引用被覆盖的成员变量(局部变量和成员变量同名),可以使用this关键字。

public class Test{
    public String name = "猴子";
    public static int age = 500;
    public void outPut(){
        String name = "悟空";
        System.out.println(name);//"悟空"
        System.out.println(this.name);//"猴子"
    }
    public static void main(String[] args){
        double age = 100000.0;
        System.out.println(age);//100000.0
        System.out.println(Test.age);//500
        new Test().outPut();
    }
}

成员、局部变量初始化及运行机制

在类初始化或对象初始化时,系统会为成员变量分配内存空间,并指定默认初始值。需要关注的是,在创建一个对象时,不需要给类变量分配内存空间,只是为实例变量分配内存空间,因为类初始化时已经分配好了。在创建多个对象时,同样如此,也需要为实例变量分配内存空间,而且,实例变量是单个实例的,与类或其他实例无关。

局部变量定义后,必须经过显式初始化后才能使用,系统不会为局部变量执行初始化,就不会为变量分配内存空间,直到变量被初始化。与成员变量不同,局部变量不属于任何实例或类,因此它被保存在所在的方法栈中。如果变量是基本类型的变量,则会把值直接保存在对应内存中;但是变量是引用类型,则它存放的是地址,地址是所引用的对象或数组的地址。

局部变量的生命周期是和方法或代码块一致,但所在栈内存无需垃圾回收,因为局部变量只保存基本类型的值或引用,所以所占内存比较小。

包装类

基本数据类型不具备对象特性:无成员变量,方法被调用。但有些时候显得不那么好,比如方法需要object类型的参数,并且需要提供实际值,像2,3,4,这就麻烦了。Java提供了包装类概念,并为8种基本数据类型定义了引用类型(基本数据类型的包装类)。

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean

上述除Character外,其他包装类可传入参数创建一个包装类对象,

由于基本数据类型和包装类对象之间转换麻烦,JDK1.5提供了自动装箱和拆箱功能,去解决该问题。

自动装箱:基本类型变量赋值给包装类(或者Object变量);自动拆箱:包装类对象赋值给基本类型变量

Integer a = 5;//基本类型赋值给Integer对象
Object b = true;//把布尔类型赋值给Object对象
int c = a;//Integer对象拆箱赋值给基本类型

虽然包装类是引用类型,但是实例是可以与数值比较的,比较时直接取出包装类的值进行比较。而包装类对象之间比较,只有指向同一对象时返回true。

System.out.println(new Integer(1) == new Integer(1));//false
Integer a = 6;
Integer b = 6;
System.out.println(a == b);//true,待会解释
//注意,Integer数据范围在-128~127之间,若不在会重新创建实例

从上面来看,系统将整数装箱成实例,会放入一个cache数组(长度为256,Java就是这样设计的)中缓存起来,以后如需自动装箱则直接指向数组元素(若在-128~127之间),即引用同一个实例对象。这样的缓存设计有利程序的运行性能,节省开销。

字符串与基本类型的转换

字符串转基本类型有两种方式:

  1. 包装类的parseXxx(String s)方法(除了Character包装类外)
  2. 对应的构造器方法,Xxx(String s)

基本类型转字符串则使用String的多个重载valueOf方法。上述代码示例:

String str = "123";
int a = Integer.parseInt(str);//第一种方法
int b = new Integer(str);//构造器创建对象,之后拆箱赋值给变量b
//基本数据类型转字符串
String str1 = String.valueOf(3.14159f);
String str2 = String.valueOf(true);

Java7、8增强包装类

Java7开始为所有包装类提供静态的compare(v1,v2)方法,则可以通过该方法比较基本值的大小。比如:

System.out.println(Boolean.compare(true,false));//1
System.out.println(Boolean.compare(true,true));//0
System.out.println(Boolean.compare(false,true));//-1

Java8再次增强,开始支持无符号算术运算。如为Integer、Long增强了静态的toUnsignedString(int/long v)整型转化成无符号整数对应的字符串、toUnsignedString(int/long v,int radix)转化成指定进制无符号整数对应的字符串。

无符号整数的二进制最高位不再当作符号位看,即最小值为0。例如-2,对应的无符号整数为252


公众号: 菜鸡干Java
流浪舟 https://index.maliaoblog.cn


文章作者: 流浪舟
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 流浪舟 !
评论
 上一篇
Java构造器和初始化块 Java构造器和初始化块
Java构造器和初始化块构造器是一个特殊的方法,但定义构造器和普通方法没什么太大区别,该有的都有。不过为了区分还是看看不一样的地方。 方法名:构造器方法名需要和类名一样 返回值:构造器不定义返回值,也不用返回void,但是它会返回一个对象
2020-09-24
下一篇 
继承和组合、单例类及不可变类 继承和组合、单例类及不可变类
继承和组合、单例类及不可变类继承 inheritance:继承是实现类复用的重要手段,所谓复用,就是可以多次使用,或者再次利用,不用继续重写成员变量和方法。但不代表没有缺点,最不好的地方:破坏封装。子类拓展父类时,若访问权限允许,则可直接访
2020-09-17
  目录