Android系统下Java编程详解
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.4数据类型

3.4.1 知识准备:简单类型

Java有8种简单类型:四种整型、两种浮点型、一种字符型、一种用于表示true/false的布尔类型。表3-3列出了这8种简单数据类型。

表3-3 简单数据类型

在这些数据类型中,int、short、byte、long都是整型数据,而double和float是浮点型数据。char也可以看成是整型数据,但它是无符号的(没有负数)。

1.布尔类型

与 C语言不同,Java 定义了专门的布尔类型,用于表示逻辑上的“真”或“假”。布尔类型用关键字boolean来定义,数据只能取值true或false,注意不能用整型的0或1来替代。布尔类型不是数值型变量,它不能被转化成任意一种类型。布尔类型常常用在条件判断语句中。

    boolean sendMsg = true;
    boolean recieveMsg = false;

注意:

这里的true和false是不能用双引号引起来的,如果用双引号引起来,就成了String类型的数据了。

2.字符类型

字符(Char)类型数据用来表示通常意义上的“字符”。字符常量是用单引号括起来的单个字符。

Java 与众不同的特征之一就是Java对各种字符的支持,这是因为Java中的字符采用16位的Unicode编码格式,Unicode被设计用来表示世界上所有书面语言的字符。Char简单类型保存一个16位的Unicode字符。Unicode字符通常用十六进制编码形式表示,范围是“\u0000”~“\Uffff”,其中前缀“\u”标志着这是一个Unicode编码字符,其中前256个(“\u0000”~“\u00FF”)字符与ASCII码中的字符完全重合。

下面来看一个字符型数据的应用实例:

源文件:CharTest.java

    public class CharTest {
    public static void main(String args[]) {
        char Msg1 = 'M';
        char Msg2 = '中';
        char Msg3 = '5';
        char Msg4 = '\u0001';
        System.out.println(Msg1);
        System.out.println(Msg2);
        System.out.println(Msg3);
        System.out.println(Msg4);
    }
    }

char 型数据只能记录单个的字符值,不能表述更多的文字信息,Java语言还提供了String类型——记录由多个字符组成的字符串。String常量的表达形式为双引号引起来的0~多个字符,例如:

    String s = "Java小能手";
    System.out.println("Hello,Android!");

注意:

String不是基本数据类型,而属于引用类型。

char类型的数据用单引号表示,注意它和String类型数据的区别,例如,“A”表示的是一个char类型的数据,而“A”表示的是一个String类型的数据,它们的含义是不同的。

Java语言中还允许使用转义字符“\”来将其后的字符转变为其他的含义,例如,如果需要在输出结果时换行,应给编译器换行指令 n,但是如果直接在程序中写System.out.println("n");则不会起到换行的效果。此时,需要在n之前输入“\”,这时编译器会知道“n”是被转义的字符。

还有一种特殊情况,在Java中使用一个绝对路径:c:\learning\java,如果直接在程序中写String path = “c:\learning\java”,则不会得到你期望的结果,因为Java将“\”当成转义符了。所以,这时候应该这样写:

    String path = "c:\\learning\\java";

这时,第一和第三个“\”都是表示转义符,表示后面的那个字符(此处都为“\”)有特殊的含义。

3.整数类型

整数类型分为4类:byte、short、int及long,它们的差别在于所占用的内存空间和表数范围不同。表3-4列出了这4种整数类型数据的存储空间及表数范围。

表3-4 整数类型的存储空间和表数范围

通常情况下,int是最常用的一种整型数据,它也是Java中整数常量的默认类型。在表示非常巨大的数字时,则需要用到更大范围的long。对于前面3种整数数据类型的数据,只需要直接写出数据就可以了,而对于长整形(long)数据,需要在长整型数据后面加上L或l来表示。

整型常量虽然默认为int类型,但在不超过其表数范围的情况下,可以将int类型的数据直接赋给char、byte、short类型的变量。

下面是这些整形数据类型的一些例子:

    byte b = 12;
    short s = 12345;
    int i = 1000000;
    long l = 1000000000L;

Java中允许使用3种不同的进制形式表示整型变量:八进制、十进制、十六进制。

(1)十进制整数,如123、-456、0。

(2)八进制整数,以0开头,如0123表示十进制数83,-011表示十进制数-9。

(3)十六进制整数,以0x或0X开头,如0x123表示十进制数291,-0X12表示十进制数-18。

4.浮点类型

Java浮点类型有两种:float和double。Java浮点类型有固定的表数范围和字段长度。和整数类型一样,在Java中,浮点类型的字段长度和表数范围与机器无关。表3-5列出了符点类型数据的存储空间和表数范围。

表3-5 符点类型数据的存储空间和表数范围

double类型的浮点类型数据正如它的名字所揭示的,它表示精度是float的两倍(因此也将double类型的数据称为双精度类型的数据)。表示float类型的数据需要在数字后面加上F,用于和double类型数据相区别。

Java语言浮点类型常量有两种表示形式:

□ 十进制数形式,必须含有小数点,例如3.14、314.0、0.314。否则将被当做int型常量处理,例如314。

□ 科学计数法形式,如3.14e2、3.14E2、314E2。注意,只有浮点类型才能采用科学计数法表示,因此,314E2也是浮点型常量,而不是int型。

Java语言的浮点型常量默认为double型,要声明一个常量为float型,则要在它数字的后面加f或F。例如:

3.0表示一个double型常量,占64位内存空间。

3.0f表示一个float型常量,占32位内存空间。

3.4.2 知识准备:非boolean简单数据类型之间的转换

在Java程序中,一些不同的数据类型之间可以进行数据类型的相互转换。简单数据类型的转换一般分为两种:

(1)低级到高级的自动转换。

(2)高级到低级的强制类型转换。

二者的区别主要在于数据类型的表述范围是不同的。比如,有一个int类型的数据,赋给一个long类型的变量,或者反之。这就类似于将水(数据)从一个容器(某种数据类型)倒入到另一个容器(另一种数据类型)一样,因为容器的大小不同,能够装盛的水也是不同的。如果将从小容器中的水倒入到大容器中,不会有什么问题,但是,如果将大容器中的水倒入到小容器中,就可能会造成部分水溢出。同样的,在数据类型转换上面,也有类似的问题,如果将表数范围比较小的数据类型数据转换成表数范围大的数据类型,则可以顺利转换;反之,则有可能发生数据的溢出(损失一部分信息)。

在图3-3所示的数据类型的转换中,实线条表示这种转换不会引起信息的损失,而虚线条表示此种转换可能会引起信息的损失。

图3-3 不同数据类型之间的合法数据转换

如果数据的转换按照图3-3中箭头所示的方式来完成,则程序会自动转换,不需要在程序中干预,这种转换是低级到高级的自动转换,也成为“扩展转换(Widening Conversion)”。但是,如果不按照图中的方向来转换,则可以通过“强制类型转换”的方式来完成,此时,可能会引起信息的丢失。当按照图3-3中箭头所示的反方向来转换时,非常有可能造成数据精度的损失,这种转换也经常称为“缩小转换(Narrowing Conversion)”。

例如。int类型的数据在必要时可以自动转换成double的数据,但是,如果需要将double类型的数据转换成int类型的数据,则需要通过强制类型转换来完成。下面这条语句可以实现这个功能:

    double d = 1.2345;
    int i = (int)d;

这样,就可以将double类型的数据d转换成int类型的数据,此时,i的值为1,显然,小数后面的值都丢失了。

3.4.3 任务三:简单数据类型转换实例

1.任务描述

编写程序验证低级到高级的自动转换和高级到低级的强制类型转换。

2.技能要点

□ 理解类型转换的原理。

□ 掌握强制类型转换的方法和用途。

3.任务实现过程

(1)编写源文件:DataOper.java,使int类型变量自动转化为double类型变量,double类型变量强制转化为int类型变量。

源文件:DataOper.java

    public class DataOper {
    public static void main(String[] args) {
        // int类型数据将会自动转换成double类型
        double db1;
        int i = 123;
        db1 = i;
        System.out.println("db1=" + db1);
        // double类型数据转换成int时,将会损失精度
        double db2 = 1.234;
        int j = (int) db2;
        System.out.println("j=" + j);
    }
    }

(2)编译并运行这个程序,可以得到如下的输出:

    Db1=123.0
    j=1

int类型的数据已经自动转换成了double类型的数据,而double类型数据在强制转换成int类型数据的时候,小数点后面的值已经损失了。

3.4.4 知识准备:引用类型

Java语言中除了8种基本数据类型以外的数据类型称为引用类型,或复合数据类型。如第2章中所述,引用类型的数据都是以某个类的对象的形式存在的,在程序中声明的引用类型变量只是为该对象起的一个名字,或者说是对该对象的引用,变量的值是对象在内存空间中的存储地址而不是对象本身。

Java中的所有对象都要通过对象引用访问,引用类型数据以对象的形式存在,其构造和初始化及赋值的机制都与基本数据类型的变量有所不同。声明基本数据类型的变量时,系统同时为该变量分配存储器空间,此空间将直接保存基本数据类型的值。而声明引用类型变量时,系统只为该变量分配引用空间,并未创建一个具体的对象或者说并没有为对象分配存储器空间,将来在创建一个该引用类型的对象后,再使变量和对象建立对应关系。

这就好比用遥控器(引用)操纵电视机(对象),只要控制遥控器就可以保持与电视机的连接。如果需要换台,实际上操控的是遥控器(引用),再用遥控器操作电视机(对象)。此外,即使没有电视机,遥控器也可以独立存在。也就是说,你拥有一个引用,并不是一定需要有一个对象与它关联。因此,如果想操纵一个词,可以创建一个String引用:

    String s;

这里所创建的只是引用,并不是对象。如果此时向 s 发送一个消息,就会返回一个运行时的错误,因此,一种比较安全的做法是创建引用的同时就进行初始化。

    String s = "Hello android";

在这里用到了Java语言的一个特性:字符串可以用带引号的文本初始化。通常,对其他对象需要一种更通用的初始化方法。参看任务四的引用过程。

3.4.5 任务四:引用类型程序示例

1.任务描述

编写程序定义引用类型变量,了解引用类型的使用方法和特点。

2.技能要点

□ 声明引用类型。

□ 了解引用类型和普通类型在使用上的区别。

3.任务实现过程

(1)构造有引用类型成员变量的类Email,在这个类中,定义了3个属性:address、title、group,以及一个具有3个参数的构造器,用于在创建对象时初始化3个属性。通过定义这个类,也就定义了一个引用类型的数据类型:Email。

源文件: Email.java

    public class Email {
    // 定义属性
    String address;
    String title;
    int group;
    // 定义一个构造器
    public Student(String Email_address, String Email_title, int Email_group)
    {
        address = Email_address;
        title = Email_title;
        group = Email_group;
        }
    // 定义属性“address”的设置方法
    public void setAddress (String Email_address) {
        address = Email_address;
    }
    // 定义属性“title”的获取方法
    public String getTitle() {
        return title;
    }
    // 其他属性的设置和读取方法从略
    }

(2)再定义一个TestEmail.java类,用于说明引用类型的用法。

源文件:TestEmail.java

    public class TestEmail {
    public static void main(String[] args) {
        Email e1;
        e1 = new Email("Android@gmail.com", "capter 3", 2);
        System.out.println("第一封邮件地址是:" + e1.getAddress());
        Email e2;
        e2 = e1;
        e1.setAddress("Java@gmail.com");
        System.out.println("第二封邮件地址是:" + e2.getAddress());
    }
    }

执行上面的TestEmail应用程序,可以在控制台上得到如下的输出结果:

第一封邮件地址是:Android@gmail.com。

第二封邮件地址是:Java@gmail.com。

3.4.6 技能拓展任务:分析对象的构造和初始化

1.任务描述

分析任务四的代码,了解对象的构造和初始化的原理和过程。

2.技能要点

□ 理解引用类型变量的初始化过程和内存分配过程。

3.任务实现过程

分析一下TestEmail.java中的代码段:

        Email e1;
        e1 = new Email("Android@gmail.com", "capter 3", 2);
        System.out.println("第一封邮件地址是:" + e1.getAddress());
        Email e2;
        e2 = e1;
        e1.setAddress("Java@gmail.com");
        System.out.println("第二封邮件地址是:" + e2.getAddress());

这个代码段的作用是建立并初始化了两个Email引用类型数据,以对象e1为例讲解引用类型数据的初始化过程(对象的初始化过程)。

(1)执行语句“Email e1;”时,系统为引用类型变量e1分配引用空间(定长32位),此时只是定义了变量e1,还未进行初始化等工作,因此还不能调用Email类中定义的方法,如图3-4所示为此时内存的分配情况。

图3-4 步骤(1)执行后的内存情况

(2)执行语句“e1 = new Email("Android@gmail.com", "capter 3", 2);”,先调用构造方法创建一个Email类的对象——新对象分配的内存空间用来存储该对象所有属性(address, title,group)的值,并对各属性的值进行默认的初始化(关于默认初始化请参考3.5节内容)。注意,在这个程序中,因为address和title的类型是String类型,也是属于引用类型,所以它们的默认初始值也为null,图3-5为此时内存中的情况。

图3-5 步骤(2)执行后的内存情况

(3)接下来执行Email类的构造方法,继续此新对象的初始化工作,构造方法中又要求对新构造的对象的成员变量进行赋值,因此,此时 address、title、group的值变成了"Android@gmail.com"、"capter 3"和2,图3-6所示为此时的内存情况。

图3-6 步骤(3)执行后的内存情况

(4)至此,一个Email类的新的对象的构造和初始化构成已完成。最后再执行“e1 = new Email("Android@gmail.com", "capter 3", 2)”中的“=”号赋值操作,将新创建对象存储空间的首地址赋值给Email类型变量e1,如图3-7所示为此时的内存情况。

图3-7 执行步骤(4)的内存情况

于是引用类型变量e1和一个具体的对象建立了联系,称s1是对该对象的一个引用。最后,总结一下对象的构造及初始化程序的步骤:

(1)分配内存空间。

(2)进行属性的默认初始化。

(3)进行属性的显式初始化。

(4)执行构造方法。

(5)为引用型变量赋值。