第六章 面向对象(下)

第六章 面向对象(下),第1张

第六章 面向对象(下)

除前一章所介绍的关于类、对象的基本语法之外,本章将会继续介绍Java面向对象的特性。Java为8个基本类型提供了对应的包装类,通过这些包装类可以把8个基本类型的值包装成对象使用,JDK1.5提供了自动装箱和自动拆箱功能,允许把基本类型值直接赋给对应的包装类引用变量,也允许把包装类对象直接赋给对应的基本类型变量。
Java提供了final关键字来修饰变量、方法和类,系统不允许为final变量重新赋值,子类不允许覆盖父类的final方法,final类不能派生子类。通过final关键字,允许Java实现不可变类,不可变类会让系统更加安全。
abstract和interface两个关键字分别用于定义抽象类和接口,抽象类和接口都是从多个子类中抽象出来的共同特征。但抽象类主要作为多个类的模板,而接口则定义了多类应该遵循的规则。Lambda表达式是Java8更新的重要内容,本章会详细介绍Lambda表达式的相关内容。enum关键字用于创建枚举类。枚举是一种不能自由创建对象的类,枚举类的对象在定义类时已经固定下来。枚举类特别适合定义像流星、季节这样的类,它们能创建的实例有限且确定的。
本章将进一步介绍对象在内存中的运行机制,并深入介绍对象的几种引用方式,以及垃圾回收机制如何处理具有不同引用的对象,并详细介绍如何使用jar命令来创建JAR包。

包装类

Java是面向对象的编程语言,但它也包含了8种基本数据类型,这8种基本数据类型不支持面向对象的编程机制,基本数据类型的数据也不具备“对象”的特征:没有成员变量、方法可以被调用。Java之所以提供这8种基本数据类型,主要是为了照顾程序员的传统习惯。
这8种基本类型数据带来了一定的方便性,例如可以进行简单、有效的常规数据处理。但在某些时候,基本数据类型会有一些制约,例如所有引用变量类型的变量都继承了Object类,都可以当成Object类型变量使用。但基本数据类型的变量就不可以,如果有个方法需要Object类型的参数,但实际需要的值却是2、3等数值,这就比较难以处理。
为了解决8种基本数据类型的变量不能当成Object类型变量使用的问题,Java提供了包装类(Wrapper Class)的概念,为8种基本数据类型分别定义了相应的引用类型,并称之为基本数据类型的包装类。

从上表可以看出,除int 和 char 有点例外之外,其他的基本数据类型对应的包装类都是将其首字母大写即可。
在JDK1.5以前,把基本数据类型变量鞭策包装类实例需要通过对应包装类的 valueOf()静态方法来实现。在JDK1.5以前,如果希望得到包装类对象种包装的基本类型变量,则可以使用包装类提供的xxx.Value()实例方法。由于这种用法已过时,故此不再给出示例代码。

通过上面介绍不难看出,基本数据类型和包装类对象之间的转换关系。
从上表可以看出,Java提供的基本类型变量和包装类对象之间的转换有些烦琐,但是从JDK1.5之后这种烦琐就消除了,JDK1.5提供了自动装箱(Autoboxing)和自动拆箱(AutoUnboxing)功能。
所谓自动拆箱,就是把一个基本数据类型变量直接赋给对应的包装类变量,或者赋给Objcet变量(Objcet是所有类的父类,子类对象可以直接赋给父类变量);自动拆箱则与之相反,允许直接把包装类对象赋给一个对应的基本类型变量。
下面程序示范了自动装箱和自动拆箱的用法。

public class Demo{
    public static void main(String[] args) {
        Integer inObj = 5;//创建int的包装类对象 直接将5赋给这个对象
        Object boolObj = true;//直接把一个boolean值赋给一个objcet类型的变量
        int it = inObj;//直接把Integer对象赋给 int 类型的变量
        if(boolObj instanceof Boolean){//进行是否可以类型转换判断
            boolean b = (Boolean)boolObj;//将objcet类型强转为Boolean包装类然后赋值给一个boolean数值
            System.out.println(b);//输出布尔值 boolean b变量的值
        }
    }
}


当JDK提供了自动装箱和自动拆箱后,大大简化了基本数据类型和包装类对象之间转换过程。但值得指出的是,进行自动装箱和自动拆箱时必须注意类型匹配,例如 Integer 只能自动拆箱成 int 类型变量,不要试图拆箱成boolean类型变量;与此类似的是, int 类型变量只能自动装箱成 Integer对象(即使赋给Object类型变量,那也只是利用了Java的向上自动转型特性),不要试图装箱成Boolean对象。
借助于包装类的帮助,再加上JDK1.5提供的自动装箱、自动拆箱功能,开发者可以把基本类型的变量“近似”地当成对象使用(所有装箱、拆箱过程都由系统自动完成,无须程序员理会);反过来,开发者也可以把包装类的实例近似地当成基本类型的变量使用。
除此之外,包装类还可以实现基本类型变量和字符串之间的转换。把字符串类型的值转换为基本类型的值由两种方式。

利用包装类提供的parseXxxx(String s)静态方法(除Character之外所有的包装类都提供了该方法)。利用包装类提供的valueOf(String s)静态方法。
String类也提供了多个重载的方法 valueOf()方法,用于将基本类型变量转换成字符串,下面程序示范了这种转换关系。

public class Demo{
    public static void main(String[] args) {
        var intStr = "123";//创建一个用于做转换的字符串
        var it1 = Integer.parseInt(intStr);//使用parseInt方法转换为数值
        var it2 = Integer.valueOf(intStr);//使用ValueOf方法进行转换;
        System.out.println(it2);
        var floatStr = "4.56";
        var ft1 = Float.parseFloat(floatStr);
        var ft2 = Float.valueOf(floatStr);
        System.out.println(ft2);
        var ftStr = String.valueOf(2.345f);
        System.out.println(ftStr);
        var dbStr = String.valueOf(3.344);
        System.out.println(dbStr);
        var boolStr = String.valueOf(true);
        System.out.println(boolStr.toUpperCase());
    }
}



通过上面程序可以看出基本类型变量和字符串之间的转换关系。
如果希望把基本类型变量转换成字符串,还有一种更简单的方法:将基本类型变量和""进行连接运算,系统会自动把基本类型变量转换成字符串。例如下图代码:

var itStr = 5+"";
//itStr的值为 "5"

此处要指出的是,虽然包装类的变量时引用数据类型,但包装类的实例可以与数值类型的值进行比较,这种比较是直接取出包装类实例所包装的值来进行比较的。
看下面代码。

public class Demo{
    public static void main(String[] args) {
        var a = Integer.valueOf(6);
        System.out.println("6的包装类实例是否大于5.0:"+(a>5.0));
        System.out.println("自动类型提升:"+(a-5.0));
    }
}


这里还顺便重温了一下自动类型提升的知识点

两个包装类的实例进行比较的情况就比较复杂,因为包装类的实例实际上是引用类型,只有两个包装类引用指向同一个对象才会返回true。下面代码示范了这种效果。

public class Demo{
    public static void main(String[] args) {
        System.out.println("比较2个包装类的实例是否相等:"+(Integer.valueOf(2)==Integer.valueOf(2)));
    }
}


但JDK1.5以后支持所谓的自动装箱,自动装箱就是可以把直接一个基本类型赋值给一个包装类实例,但这种情况下可能出现一些特殊的情形。看如下代码。

public class Demo{
    public static void main(String[] args) {
        Integer ina = 2;
        Integer inb = 2;
        System.out.println("两个2自动装箱后是否相等:"+(ina==inb));
        Integer biga = 128;
        Integer bigb = 128;
        System.out.println("两个128自动装箱后是否相等:"+(biga==bigb));
    }
}


上面程序让人比较费解:同样是两个int类型的的数值自动装箱Integer实例后,如果是两个2自动装箱后就相等;但如果是两个128自动装箱就不相等,这是为什么呢?这与Java的Integer类的设计有关,查看Java系统中java.lang.Integer类的源代码,如下所示:

static final Integer[]cache = new Integer[-(-128)+127+1];
static{
	for(int i = 0; i < cache.length; i++){
		cache[i] = new Integer(i - 128);
	}
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5719415.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存