3.4 数据类型处理

第2章讨论了基本数据类型的应用,如整数、浮点数、字符和布尔类型,以及它们的定义、运算、转换等操作。本章讨论面向对象编程的内容。那么,在应用开发中,如何合理地处理这些数据类型呢?

本节就讨论相关内容,首先来看基本数据类型及其包装类的使用。

3.4.1 基本数据类型与包装类

第2章讨论过的基本数据类型在java.lang包中都提供了一个面向对象的包装类,其对应关系如表3-1所示。

表3-1 基本数据类型与包装类

开发中,应该如何使用基本数据类型和包装类呢?当基本类型的数据需要面向对象操作时,就可以将其转换为对象来使用,如下面的代码所示。

代码中,以int类型为例,使用Integer类的构造函数代入一个整数,从而创建一个值为10的Integer对象。然后,通过toString()方法显示其内容。实际上,还可以使用更加简单的方式创建Integer对象,如下面的代码所示。

    Integer objY = 99;
    System.out.println(objY.toString());  // 99

这里,直接将整数赋值给Integer类型的objY对象,此时,编译器会自动完成转换工作。

示例中,objX和objY就是Integer类型的对象,可以使用Integer类中定义的成员来处理数据。接下来,还可以使用Integer类中的一系列方法将数据转换为所需要的类型,如下面的代码所示。

    public static void main(String[] args) {
        Integer objX = new Integer(10);
        System.out.println(objX.intValue());
        System.out.println(objX.floatValue());
    }

代码中,分别使用intValue()和floatValue()方法将objX对象中的数据转换为整数和浮点数,执行结果如图3-18所示。

图3-18 使用基本数据类型与包装类

3.4.2 数据的传递

基本数据类型称为值类型,而所有的类称为引用类型。它们在使用中有什么区别呢?接下来着重讨论值类型与引用类型在数据传递过程中的一些特点。

下面的代码在JavaDemo类中创建三个数据改装方法,它们定义在main()方法的外面。

代码中创建的三方法分别如下所示。

□ intModification()方法,其中将参数(int类型)的值修改为99。

□ stringModification()方法,其中会修改String类型参数的内容。

□ autoModification()方法,其中会对CAuto对象进行修改。

首先,测试int类型的改装,如下面的代码所示。

代码执行结果如图3-19所示。

现实可能和你想象的不一样,代码执行结果是,intModification()方法并没有改变x变量的值,这是为什么呢?原因很简单,因为int是值类型,而值类型的参数在传递时会产生一个副本。也就是说,在intModification()方法中处理的并不是main()方法中定义的x变量,而是x变量的副本,而修改副本的值并不会影响原变量中的数据。

图3-19 值类型参数的传递

下面的代码改装汽车。

    public static void main(String[] args) {
    CAuto auto = new CAuto("X9", 4);
        System.out.println(auto.model);
        System.out.println(auto.getDoors());
        System.out.println("*** 对汽车进行改装 ***");
        autoModification(auto);
        System.out.println(auto.model);
        System.out.println(auto.getDoors());
    }

代码执行结果如图3-20所示。

代码中,在autoModification()方法中成功地对auto对象进行了改造,将型号(model)修改为“改装车”,车门数量变成2。为什么这个操作会成功呢?因为CAuto是一个类类型,也就是一个引用类型,引用类型在传递时,会直接传递其对象位于内存中的位置,所以在autoModification()方法中实际操作的就是main()方法中的auto对象。

最后看引用类型中的异类,即String类型的改装测试,如下面的代码所示。

    public static void main(String[] args) {
        String s = "abc";
        stringModification(s);
        System.out.println(s);
    }

代码执行结果如图3-21所示。

图3-20 引用类型参数的传递

图3-21 String类型参数的传递

String类型是引用类型。那为什么和CAuto对象的表现不一样呢?实际上,不止是在Java中,在C#中也是这样,String类用于处理不可变字符串类型。也就是说,String对象的内容一旦确定就不能改变了,对于字符串内容的任何操作,都会生成一个新的字符串对象。所以,在stringModification()方法中修改字符串对象的内容时,实际上已经生成了一个新的字符串对象,而不是s所指向的字符串对象。

前面的示例中,使用+运算符来连接字符串,这一操作实际上会生成多个字符串对象。对于需要大量拼接字符串的操作来说,其效率是非常低的。解决方案是使用StringBuffer或StringBuilder类来操作字符串,第6章会讨论相关主题。

3.4.3 类型的动态处理

应用开发过程中,为了简化代码,经常会使用Object类或其他通用类型来传递对象,但对象会保留原始类型的相关信息。此时,如何获取对象的真正类型、如何判断对象可以进行什么操作就是一项非常重要的工作。

动态处理对象时,Object类中的一系列成员,以及Class等类型的使用将扮演非常重要的角色。

在讨论继承的过程中,已经使用了Object类中的一些方法。下面再来看一看Object类中的其他常用成员。

□ equals()方法,与参数指定的对象进行比较,当两个对象是同一引用时返回true,否则返回false。

□ toString()方法,返回对象的文本描述。

□ getClass()方法,返回一个Class类型的对象,即对象类型的描述对象。

接下来测试Class类的使用,如下面的代码所示。

代码中,首先定义了CAssaultVechicle类的av对象。然后,使用av对象的getClass()方法获取对象的类型信息,它会返回一个Class类型的对象。

接下来,使用Class类中的getPackage()方法返回类型所在包的名称;使用getName()方法返回类的名称,这是包含包名的完整类名;使用getSuperclass()返回类型的超类信息,同样是Class对象,同样使用getName()显示超类的名称。

最后,使用Class对象的getMethods()方法返回CAssaultVechicle类的所有方法,包括自定义方法和继承的方法。请注意,Method类定义在java.lang.reflect包中,在代码文件的开始处,package语句的下面,需要使用import语句引用这个类,如下面的代码所示。

    import java.lang.reflect.Method;

如果需要引用java.lang.reflect包中的所有资源,可以使用*通配符,如下面的代码所示。

    import java.lang.reflect.*;

此外,关于代码中的for语句结构,会在第5章详细讨论。