Java程序设计与应用开发(第3版)
上QQ阅读APP看书,第一时间看更新

2.1 变量

所谓变量,就是由标识符命名的数据项。每个变量都必须声明数据类型,变量的数据类型决定了它所能表示值的类型以及可以对其进行什么样的操作。变量既可以表示基本数据类型(如整型int、字符型char等)的数据,也可以表示对象类型(如字符串)的数据。当变量是基本数据类型时,变量中存储的是数据的值,而当变量是对象(引用)类型时,变量中存储的是对象的地址,该地址指向对象在内存中的位置,如图2.1所示。

图2.1 变量示意图

在图2.1中,salary是一个基本类型的变量,其中存储的值是197;而employee是一个对象类型的变量,所以其中存储的值是所指向对象在内存中的地址。注意,Java语言中字符类型(char)是基本数据类型,而字符串(string)则是对象类型。本节将介绍Java语言中的几种基本数据类型。

2.1.1 基本数据类型

1. 整型

Java语言中提供了4种整型数据类型:byte、short、int和long,如表2.1所示。

表2.1 整型数据类型

这4种类型都只能表示整数(包括负数),由于占用存储空间大小的不同,所能表示的数值范围也有所不同,占用空间越大,表示的范围越大。此外,在不同的平台上,相同数据类型的大小和格式均是固定的,不会改变。

注意:许多语言中,基本数据类型的格式和大小与程序运行的平台有关,这是产生程序跨平台困难的主要原因之一。Java语言中,对每种基本数据类型都限定了固定的格式和大小,因此消除了数据类型对平台的依赖性。

可以这样给一个整型变量赋值:

     int salary=197;

如果给一个长整型变量赋值,则在数字后面加一个L,表示该数值是长整型:

     long salary=197L;

注意,读者如果需要测试上面的两条赋值语句是否正确,则可以用这两条语句覆盖编程框架TestSketch中的省略号,得到:

     public class TestSketch{
         public static void main(String []args){
             //以下添加测试代码
             int salary=197;
             long salary=197L;
         }
     }

然后编译、运行TestSketch.java即可。

2. 浮点类型

浮点类型用来表示有小数的数值。浮点类型分为单精度浮点类型和双精度浮点类型两类,如表2.2所示。

之所以称double为双精度,是因为double数据类型表示数据的精度是float的两倍。但是double类型的数据在运算时速度低于float,因此在精度要求不高的条件下,如果需要大量存储以及运算数据,则使用float类型。如果精度要求高,则使用double类型。

表2.2 浮点数据类型

double和float基本数据类型有对应的封装类Double和Float,并且在Double和Float封装类中以类变量的方式定义了浮点数的3个特殊值:正无穷、负无穷和非数字。

     Double.POSITIVE_INFINITY  (Float.POSITIVE_INFINITY)
     Double.NEGATIVE_INFINITY  (Float.NEGATIVE_INFINITY)
     Double.NaN (Float.NaN)

可以为变量直接赋这些特殊的值,例如:

     double weight=Double.POSITIVE_INFINITY;

这条语句将变量weight的值置为正无穷。

在Java编程语言中,浮点类型的数值默认为是双精度类型的,那么给单精度类型的变量赋值时需要在数值后面加上F或f,以表示该数值是单精度类型的。如果使用下面的赋值语句:

     float miles=0.9;

编译器将会报错,因为0.9默认为是double类型的,赋值给float类型的变量会丢失精度。正确的赋值方法应该是:

     float miles=0.9f;

或是:

     float miles=0.9F;

但是给double类型的变量赋值时,可以在数值后面加上D(或d),也可以不加,例如:

     double miles=0.9; double miles=0.9D; double miles=0.9d;

这些均是正确的。

3. 字符类型

读者可能对ASCII码都已经比较熟悉了,ASCII码的长度是8位,最多只能表示128个字符,扩展的ASCII编码也只能处理256个字符。因此,如果想用ASCII码来对世界上所有语言中的字符进行统一编码是不可能的。而Unicode编码采用16位的编码方式,因此可以对65536种字符进行编码,能够容纳目前世界上已知的字符集。Java编程语言中所有的字符均使用Unicode编码,Unicode编码值通常用十六进制表示,如'\u0049'是'I'的Unicode编码。'\u'表示是Unicode值,也称为转义字符。

字符类型只能表示单个字符,如表2.3所示。表示字符类型的值是在字符两端加上单引号,如'g'。注意'g'和"g"是不同的,前者是一个字符,属于基本数据类型;后者表示的是一个字符串(只是该字符串中只有一个字符),属于一个对象数据类型。

表2.3 字符数据类型

下面的例子是给一个字符类型的变量赋值:

     char kind='I';          //给字符变量kind赋值'I'

也可以给字符类型的变量直接赋Unicode编码值,例如:

     //给字符变量kind赋'I'的Unicode编码值,等价于char kind='I';
     char kind ='\u0049';

读者还要特别注意的是一些常用的转义字符,如表2.4所示。

表2.4 常用转义字符

例如,要在屏幕上输出"This is a char test"(双引号也要输出),如果使用语句:

     System.out.println(""This is a char test"");

那么编译会通不过,因为编译器将前面一对引号作为一个字符串,后面一对引号也作为字符串,这样就产生了语法错误。这时候就要使用转义字符了,正确的语句可以是:

     System.out.println("\"This is a char test\"");

4. 布尔类型

布尔类型(boolean)的值只有两个:true或是false,分别表示真或者假,用于逻辑条件的判断。

注意:在C/C++中,数值也可以充当布尔类型的值:0相当于false,非零值相当于true。这就很容易在程序中引入bug,例如下面的if语句:

           if(age=0) //判断age是否为0

在C/C++中是可以编译运行的。但是该语句隐含了一个bug,因为不管age的实际值是什么,总是判定if语句不成立。而在Java中,该语句是不能编译通过的,必须使用:

           if(age==0) //判断age是否为0

2.1.2 变量

Java编程语言中,要使用变量,必须先声明变量。按照如下方式声明变量:

     VariableType  variableName;

例如:

     int  length;
     float  miles;
     boolean flag;

Java语言中,通过变量名来引用变量的值。因此必须给每个变量定义合法的变量名。

变量名的定义必须符合以下几条规则:

•变量名是由Unicode字母或是数字组成的不间断序列(中间不能有空格),长度不限,并且必须以字母开头。

•变量名不能是系统关键字(如int)、布尔值(true或false)或保留字(null)。

•在相同的作用域内(参看2.1.3小节),不能重复声明同一变量名。

注意:由于Unicode字符集非常庞大,当需要判断一个字符是否可以用作变量名的起始字母时,使用Character.isJavaIdentifierStart(char),如果返回值为true,表示该字符可以作为变量名的字母;要判断一个字符是否可以作为变量名的组成部分,使用Character.isJavaIdentifierPart(char)。

习惯上,变量名以小写的字母开头,类名以大写的字母开头。如果变量名称由多个单词组成,那么首单词的字母全部小写,后续所有单词的首字母大写,其余部分小写,例如:mySalaryThisYear。

变量名是区分大小写的,例如mySalary和mysalary就是不同的变量。建议不要同时声明类似的容易混淆的变量。

2.1.3 变量的作用域

变量总是在一定的区域内起作用,这个区域就是变量的作用域。实际上,在定义变量时,变量的作用域就随之确定了,变量的作用域与变量定义所处的位置是密切相关的。

这里为了比较全面地介绍变量作用域的概念,涉及类以及异常处理的概念(详细内容请参阅后续章节)。初学者可以暂时忽略关于类成员变量和异常处理参数变量作用域的介绍(图2.2中的①和④),重点掌握方法参数变量和局部变量的作用域(图2.2中的②、③和⑤)。

图2.2 变量作用域示意图

在介绍作用域之前,有必要了解一下块(block)的概念。块是用一对花括号“{}”括起来的任意数量的Java语句,块允许嵌套。例如图2.2中所示的区域②就是一个块,称为方法块;同样区域①也是一个块,称为类块。④和⑤也均是一个代码块。

变量定义所在的位置决定了变量的作用域,根据变量定义所在的位置不同,可以分为以下4类:

•类成员变量。

•局部变量。

•方法参数变量。

•异常处理参数变量。

类成员变量的作用域是整个类块。图2.2中,类ScopeDemo的类成员变量a,在类块①中的任何地方均可以使用变量a。

编程人员可以在一个块中声明局部变量,例如类ScopeDemo中的变量c和f都是局部变量。局部变量的作用域是从该变量的声明处起至所在块的结束。例如变量c的作用域是块③,即变量c在块③内都是有效的;而同样是局部变量的f的作用域是块⑤,作用域要比变量c小。

方法参数变量是用来传递参数值到方法中去的,它的作用域是所在方法的整个方法块。例如类ScopeDemo中的方法参数变量b,其作用域是整个方法块②。

异常处理参数变量类似于方法参数变量,只是其作用域仅限于捕获异常的catch块。例如类ScopeDemo中的异常处理参数变量e,其作用域仅限于块④。

下面的一段代码是变量作用域实例,请读者阅读后结合本节内容指出代码中几处访问变量出错的原因。

例2.1 ScopeDemo.java

     public class ScopeDemo{
       int a=50;
       public void add(int b){
         System.out.println(a);                        //正确
         System.out.println(b);                        //正确
         System.out.println(c);                        //错误
         int c=100;
         try{
              int c;                                   //错误
              System.out.println(b);                   //正确
              System.out.println(c);                   //正确
                int f=200;
              System.out.println(f);                   //正确
         }catch(Exception e){
              System.out.println(e.toString());        //正确
              System.out.println(b);                   //正确
              System.out.println(c);                   //正确
              }
              System.out.println(c);                   //正确
              System.out.println(f);                   //错误
              System.out.println(e.toString());        //错误
              System.out.println(b);                   //正确
              System.out.println(a);                   //正确
        }
     }

2.1.4 变量的初始化

变量在声明后,可以通过赋值语句对其进行初始化。初始化后的变量仍然可以通过赋值语句赋以其他不同的值。例如:

     double salary;  //变量声明
     salary=200d;    //初始化赋值
     ...
     salary=400d;    //重新赋值,但不是初始化

变量还可以声明及初始化同时进行:

     double salary=200d;  //变量声明的同时进行初始化

需要注意的是,给变量赋值类型必须要匹配,即变量的数据类型要和所赋值的数据类型一致。

注意:方法参数变量和异常处理参数变量不能以上述方式来进行赋值与初始化。这两种类型的变量值是在方法调用或是抛出异常时传递进来的。

Java语言中还有一种特殊的final类型的变量,称作常量。final类型的变量在初始化后就不能再重新对其赋值,常用于表示一些固定不变的值。使用final关键字来定义常量的例子如下:

     final double PI=3.1415926;  //声明并初始化一个常量
     PI=3.14;                    //出错,不能修改已经初始化的常量的值

PI被定义为一个常量,并初始化为3.1415926,以后在程序的任何地方都不能改变PI的值。

有的时候会存在这样一种情形:我们需要一个常量,但是在声明它的时候还不能确定其值是多少。这时候,可以使用滞后初始化的方法,即声明常量时不进行初始化,在适当的时候再初始化。例如:

     final double A_CONSTANT;  //声明,未初始化
     ...
     A_CONSTANT=0.9;           //滞后初始化

同样,该变量一旦初始化后,值也不允许修改。

注意:常量一旦初始化,不能对其重新赋值。习惯上,常量名中所有的字符均大写。