Java复习之Java深入解析五(包装器类型的缓存、嵌套类)

1.Java中的八种基本数据类型不是对象,之所以这样设计,是因为其使用方便,效率高于对象类型。但是集合类并不支持对基本数据类型的操作。因此就引入了包装器类。在JDK1.5之后加入了自动拆装箱机制。装箱时调用valueOf方法,这是个静态方法,返回包装器类型,值为形参的值。拆箱时调用xxxvalue方法,返回基本数据类型。
包装器类型参与运算时用到符合赋值运算可能会报错:

Short sh1=Short.valueOf((short) 1);
Short sh2=2;
//sh1+=sh2;//相当于 sh1=(Short)(sh1+sh2);

第三行会报错。相加时先拆箱,后提升至int类型,在转化为Integer类型。在将Integer类型强转为Short类型时出错。因为参与运算的类型时int类型,所以将Short类型转换为Integer时可以通过编译。

Integer i1=1;
Integer i2=2;
i1+=i2;
System.out.println(i1);

先拆箱,后运算,再装箱。
包装类的缓存:在java中,String和包装器类型都是有final修饰的。因此,对象一经创建后就不可修改。对此,String类提供了常量池,包装器类提供了对象的缓存,具体实现是在类中预先创建频繁使用的包装类对象。当需要某个包装类对象时,如果该对象的值在缓存的值的范围内,就返回包装类的对象,否则就创建新的并返回。缓存的优点:

  • 当频繁使用包装类对象时,可以直接返回缓存类中事先创建好的对象。节省创建对象的时间开销。因为包装类是不可变的,因此,它的对象可以自由共享。

缓存的范围:

  • 数字类型(Byte、Short、Integer、Long)都是-128~127;
  • Character类:0~127;
  • Boolean类:true和false都有;
  • 浮点类型(Float、Double):没有缓存值。

Integer i1=127;//自动装箱,调用Integer.valueOf()方法
Integer i2=127;//不能new,new会在堆上创建新对象。地址一定不一样。这一点和字符串一样

  public class Maintest extends Super{
    public static void main(String[] args) {
        Integer i1=127;//自动装箱,调用Integer.valueOf()方法
        Integer i2=127;//不能new,new会在堆上创建新对象。地址一定不一样。这一点和字符串一样
        System.out.println("i1.equals(i2):"+i1.equals(i2));
        System.out.println("i1==i2:"+(i1==i2));
        Integer i3=128;
        Integer i4=128;
        System.out.println("i3.equals(i4):"+i3.equals(i4));
        System.out.println("i3==i4:"+(i3==i4));
    }
}

运行结果为:

i1.equals(i2):true
i1==i2:true
i3.equals(i4):true
i3==i4:false

i1和i2没有超过缓存的范围,因此时同一个对象。i3和i4超过范围了,因此会创建新对象。
Integer的缓存下限时-127,是固定的。但是上限是可以自己修改的。修改后的值不能小于127。如果小于,那么修改无效。上限依然是127。
2.数组:在java中,数组也是一种类型,有成员变量和方法。多维数组中的元素为低纬数组。Java中的数组可以不是矩阵数组。数组一经创建,其长度就不可改变。其内部的length时final修饰的。数组重写了Object中的clone方法,x.clone()!=x。但是,数组的克隆是浅克隆,仅能保证clone()返回的数组与原数组的地址不同。如果数组中存放的是引用数据类型,那么复制的数组中的元素依然指向相同的对象。

public class Maintest{
    public static void main(String[] args) {
        Super[] supers=new Super[2];
        supers[0]=new Super();
        supers[1]=new Super();
        Super[] supers1=supers.clone();
        System.out.println("supers1==supers:"+(supers1==supers));
        System.out.println("supers1[1]==supers[1]:"+(supers1[1]==supers[1]));
    }
}

运行结果:

supers1==supers:false//只保证引用的地址不一样
supers1[1]==supers[1]:true//但内部的元素的引用都一样。

高维数组复制时,内部元素的引用指向的对象(低纬数组)一样。
数组输出时,除了char类型以外,其余都是调用了Object中的toString方法,输出地址。
3.接口:接口中的方法都是abstract 修饰的,目的就是要类去实现它,实现多态调用。因此接口中不能声明static修饰的方法,可以声明static修饰的变量。如果有static修饰变量,那么变量最好在声明处赋初始值。当两个接口中存在同名变量的时候,访问时要加限定名称。接口可以实现多继承其他的接口,接口和接口之间不存在实现关系。综上:

  • 继承关系可以存在类和类、接口和接口(多继承)之间。
  • 实现只能出现在类与接口之间。

4.嵌套类型:
静态成员类:在类中定义了一个用static修饰的类,该类可以访问外围的private成员变量,但是如果是非静态的,需要通过对象名来引用。

public class Maintest {
    private String string="内部类的成员变量";
    public static class staticclass{
        public static void main(String[] args) {
            System.out.println(new Maintest().string);//如果在类的内部,是可以直接通过对象名来访问私有成员变量的
        }
    }
}

静态类不依赖于外围类的实例对象而存在。因为是静态,可以通过外围类的类名来访问。在访问权限够的情况下,静态类可以继承任何类,任何类也都可以继承静态类。
内部成员类:内部成员类必须通过对象来访问,而静态成员变量又是不需要对象可以直接通过类名来访问。如果内部成员类中有静态,会存在这样的矛盾。因此内部成员类中不能声明静态(变量、方法、类、静态初始化块)。但是可以有final修饰的变量。
内部类绑定外围类对象:创建内部类对象时,编译器会为内部类隐式声明一个final修饰的外围类引用,调用构造时,系统会传参(外围类对象)将该引用指向外围类对象。
局部类:局部类是在方法、构造器、初始化块中声明的类,不能使用访问权限修饰符来访问,也不能使用static修饰。

上一篇
---The End---
...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章