第2章 Java语言的基本语法
本章要点
了解Java中的标识符和关键字
理解Java中的常量和变量
了解Java中的数据类型
掌握数组的创建和使用
任何知识都要从基础学起,同样,Java语言也要从基本语法学起。本章将详细介绍Java语言的基本语法,建议初学者不要急于求成,要认真学习本章的内容,以便为后面的学习打下坚实的基础。
2.1 关键字和标识符
2.1.1 Unicode字符集
Java语言使用Unicode标准字符集,该字符集由Unicode协会管理并接受其技术上的修改,它最多可以识别65536个字符。在Unicode字符集中,前128个字符刚好是ASCII码,但大部分国家的“字母表”中的字母都是Unicode字符集中的一个字母,因此,Java所使用的字母不仅包括通常的拉丁字母,还包括汉字、俄文、希腊字母等。
关键字和标识符
2.1.2 关键字
Java语言中还定义了一些专有词汇,统称为关键字,如public、class、int等,它们都具有特定的含义,只能用于特定的位置。表2-1中列出了Java语言的所有关键字。
表2-1 Java语言的所有关键字
abstract |
const |
finally |
int |
public |
this |
boolean |
continue |
float |
interface |
return |
throw |
break |
default |
for |
long |
short |
throws |
byte |
do |
goto |
native |
static |
transient |
case |
double |
if |
new |
strictfp |
try |
catch |
else |
implements |
package |
super |
void |
char |
extends |
import |
private |
switch |
volatile |
class |
final |
instanceof |
protected |
synchronized |
while |
2.1.3 标识符
Java语言中的类名、对象名、方法名、常量名和变量名统称为标识符。
为了提高程序的可读性,在定义标识符时,要尽量遵循“见其名知其意”的原则。Java标识符的具体命名规则如下:
(1)一个标识符可以由几个单词连接而成,以表明它的意思;
(2)标识符由一个或多个字母、数字、下划线(_)和美元符号($)组成,没有长度限制;
(3)标识符中的第一个字符不能为数字;
(4)标识符不能是关键字;
(5)标识符不能是true、false和null;
(6)对于类名,每个单词的首字母都要大写,其他字母则小写,如RecordInfo;
(7)对于方法名和变量名,与类名有些相似,除了第一个单词的首字母小写外,其他单词的首字母都要大写,如getRecordName()、recordName;
(8)对于常量名,每个单词的每个字母都要大写,如果由多个单词组成,通常情况下单词之间用下划线(_)分隔,如MAX_VALUE;
(9)对于包名,每个单词的每个字母都要小写,如com.frame。
Java语言区分字母的大小写。
2.2 常量与变量
常量和变量在程序代码中随处可见,下面就来学习常量和变量的概念及使用要点,从而达到区别常量和变量的目的。
常量与变量
2.2.1 常量的概念及使用要点
所谓常量,就是值永远不允许被改变的量。如果要声明一个常量,就必须用关键字final修饰,声明常量的具体方式如下:
final 常量类型 常量标识符;
例如:
final int YOUTH_AGE; // 声明一个int型常量
final float PIE; // 声明一个float型常量
在定义常量标识符时,按照Java的命名规则,所有的字符都要大写,如果常量标识符由多个单词组成,则在各个单词之间用下划线(_)分隔,如“YOUTH_AGE”、“PIE”。
在声明常量时,通常情况下立即为其赋值,即立即对常量进行初始化。声明并初始化常量的具体方式如下:
final 常量类型 常量标识符 = 常量值;
例如:
final int YOUTH_AGE = 18; // 声明一个int型常量,并初始化为18
final float PIE = 3.14F; // 声明一个float型常量,并初始化为3.14
在为float型常量赋值时,需要在数值的后面加上一个字母“F”(或“f”),说明数值为float型。
如果需要声明多个同一类型的常量,也可以采用下面的形式:
final 常量类型 常量标识符1, 常量标识符2, 常量标识符3;
final 常量类型 常量标识符4 = 常量值4, 常量标识符5 = 常量值5, 常量标识符6 = 常量值6;
例如:
final int A, B, C; // 声明3个int型常量
final int D = 4, E = 5, F = 6; // 声明3个int型常量,并分别初始化为4、5、6
如果在声明常量时并没有对其进行初始化,也可以在需要时进行初始化,例如:
final int YOUTH_AGE; // 声明一个int型常量
final float PIE; // 声明一个float型常量
YOUTH_AGE = 18; // 初始化常量YOUTH_AGE为18
PIE = 3.14F; // 初始化常量PIE为3.14
但是,如果在声明常量时已经对其进行了初始化,常量的值则不允许再被修改。例如若尝试执行下面的代码,将在控制台输出常量值不能被修改的错误提示。
final int YOUTH_AGE = 18; // 声明一个int型常量,并初始化为18
YOUTH_AGE = 16; // 尝试修改已经被初始化的常量
2.2.2 变量的概念及使用要点
所谓变量,就是值可以被改变的量。如果要声明一个变量,并不需要使用任何关键字进行修饰,声明变量的具体方式如下:
变量类型 变量标识符;
例如:
String name; // 声明一个String型变量
int partyMemberAge; // 声明一个int型变量
在定义变量标识符时,按照Java的命名规则,第一个单词的首字母小写,其他单词的首字母大写,其他字母则一律小写,如“name”“partyMemberAge”。
在声明变量时,也可以立即为其赋值,即立即对变量进行初始化。声明并初始化变量的具体方式如下:
变量类型 变量标识符 = 变量值;
例如:
String name = "MWQ"; // 声明一个String型变量
int partyMemberAge = 26; // 声明一个int型变量
Student s1=new Student(); // 声明一个Student型变量
如果需要声明多个同一类型的变量,也可以采用下面的形式:
变量类型 变量标识符1, 变量标识符2, 变量标识符3;
变量类型 变量标识符 4 = 变量值4, 变量标识符5 = 变量值5, 变量标识符6 = 变量值6;
例如:
int A, B, C; // 声明3个int型变量
int D = 4, E = 5, F = 6; // 声明3个int型变量,并分别初始化为4、5、6
变量与常量的区别是,变量的值允许被改变。例如,下面的代码是正确的:
String name = "MWQ"; // 声明一个String型常量,并初始化为"MWQ"
name = "MaWenQiang"; // 尝试修改已经被初始化的变量
关于变量的更多内容,本书第4章将进行详细讲解。
2.3 数据类型
Java是强类型的编程语言,Java语言中的数据类型分类情况如图2-1所示。
图2-1 Java中的数据类型分类情况
Java语言中的数据类型分为两大类,分别是基本数据类型和引用数据类型。其中基本数据类型由Java语言定义,其数据占用内存的大小固定,在内存中存入的是数值本身;而引用数据类型在内存中存入的是引用数据的存放地址,并不是数据本身。
2.3.1 基本数据类型
基本数据类型分为整数型、浮点数型、字符型和逻辑型,分别用来存储整数、小数、字符和逻辑值。下面将依次讲解这4个基本数据类型的特征及使用方法。
整数型
1.整数型
声明为整数型的常量或变量用来存储整数,整数型包括字节型(byte)、短整型(short)、整型(int)和长整型(long)4个基本数据类型。这4个数据类型的区别是它们在内存中所占用的字节数不同,因此,它们所能够存储的整数的取值范围也不同,如表2-2所示。
表2-2 整数型数据占用内存的字节数以及取值范围
数据类型 |
关键字 |
占用内存字节数 |
取值范围 |
---|---|---|---|
字节型 |
byte |
1个字节 |
-128~127 |
短整型 |
short |
2个字节 |
-32 768~32 767 |
整型 |
int |
4个字节 |
-2 147 483 648~2 147 483 647 |
长整型 |
long |
8个字节 |
-9 223 372 036 854 775 808~9 223 372 036 854 775 807 |
在为这4个数据类型的常量或变量赋值时,所赋的值不能超出对应数据类型允许的取值范围。例如,在下面的代码中依次将byte、short和int型的变量赋值为9 412、794 125和9 876 543 210是不允许的,即下面的代码均是错误的:
byte b = 9412; // 声明一个byte型变量,并初始化为9412
short s = 794125; // 声明一个short型变量,并初始化为794125
int i = 9876543210; // 声明一个int型变量,并初始化为9876543210
在为long型常量或变量赋值时,需要在所赋值的后面加上一个字母“L”(或“l”),说明所赋的值为long型。如果所赋的值未超出int型的取值范围,也可以省略字母“L”(或“l”)。例如,下面的代码均是正确的:
long la = 9876543210L; // 所赋值超出了int型的取值范围,必须加上字母"L"
long lb = 987654321L; // 所赋值未超出int型的取值范围,可以加上字母"L"
long lc = 987654321; // 所赋值未超出int型的取值范围,也可以省略字母"L"
但是下面的代码就是错误的:
long l = 9876543210; // 所赋值超出了int型的取值范围,不加字母"L"是错误的
【例2-1】 使用基本数据类型定义员工的年龄。
public class BasicMessage {
private int id;
private String name;
private int age;//使用基本数据类型定义员工的年龄
private int dept;
private int headship;
private String sex;
…//省略部分代码
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setHeadship(int headship) {
this.headship = headship;
}
}
2.浮点数型
声明为浮点数型的常量或变量用来存储小数(也可以存储整数)。浮点数型包括单精度型(float)和双精度型(double)2个基本数据类型。这2个数据类型的区别是它们在内存中所占用的字节数不同,因此,它们所能够存储的浮点数的取值范围也不同,如表2-3所示。
浮点数型
表2-3 浮点数型数据占用内存的字节数以及取值范围
数 据 类 型 |
关 键 字 |
占用内存字节数 |
取 值 范 围 |
---|---|---|---|
单精度型 |
float |
4个字节 |
1.4E-45~3.402 823 5E38 |
双精度型 |
double |
8个字节 |
4.9E-324~1.797 693 134 862 315 7E308 |
在为float型常量或变量赋值时,需要在所赋值的后面加上一个字母“F”(或“f”),说明所赋的值为float型。如果所赋的值为整数,并且未超出int型的取值范围,也可以省略字母“F”(或“f”)。例如,下面的代码均是正确的:
float fa = 9412.75F; // 所赋值为小数,必须加上字母"F"
float fb = 9876543210F; // 所赋值超出了int型的取值范围,必须加上字母"F"
float fc = 9412F; // 所赋值未超出int型的取值范围,可以加上字母"F"
float fd = 9412; // 所赋值未超出int型的取值范围,也可以省略字母"F"
但是下面的代码就是错误的:
float fa = 9412.75; // 所赋值为小数,不加字母"F"是错误的
float fb = 9876543210; // 所赋值超出了int型的取值范围,不加字母"F"是错误的
在为double型常量或变量赋值时,需要在所赋值的后面加上一个字母“D”(或“d”),说明所赋的值为double型。如果所赋的值为小数,或者所赋的值为整数并且未超出int型的取值范围,也可以省略字母“D”(或“d”)。例如,下面的代码均是正确的:
double da = 9412.75D; // 所赋值为小数,可以加上字母"D"
double db = 9412.75; // 所赋值为小数,也可以省略字母"D"
double dc = 9412D; // 所赋值为整数,并且未超出int型的取值范围,可以加上字母"D"
double dd = 9412; // 所赋值为整数,并且未超出int型的取值范围,也可以省略字母"D"
double de = 9876543210D; // 所赋值为整数,并且超出了int型的取值范围,必须加上字母"D"
Java默认小数为double型,所以在将小数赋值给double型常量或变量时,可以不加上字母“D”(或“d”)。
但是下面的代码就是错误的:
double d = 9876543210; // 所赋值为整数,并且超出了int型的取值范围,不加字母"D"是错误的
3.字符型
声明为字符型的常量或变量用来存储单个字符,它占用内存的2个字节来存储,字符型利用关键字“char”进行声明。
因为计算机只能存储二进制数据,所以需要将字符通过一串二进制数据来表示,也就是通常所说的字符编码。Java采用Unicode字符编码,Unicode使用2个字节表示1个字符,并且Unicode字符集中的前128个字符与ASCII字符集兼容。例如,字符“a”的ASCII编码的二进制数据形式为01100001,Unicode字符编码的二进制数据形式为00000000 01100001,它们都表示十进制数97,因此,Java与C、C++一样,同样把字符作为整数对待。
字符型
ASCII是用来表示英文字符的一种编码,每个字符占用一个字节,所以最多可表示256个字符。但英文字符并没有那么多,ASCII使用前128个(字节中最高位为0)来存放包括控制符、数字、大小写英文字母和其他一些符号的字符。而字节的最高位为1的另外128个字符称为“扩展ASCII”,通常存放英文的制表符、部分音标字符等其他一些符号。使用ASCII编码无法表示多国语言文字。
Java中的字符通过Unicode字符编码,以二进制的形式存储到计算机中,计算机可通过数据类型判断要输出的是一个字符还是一个整数。Unicode编码采用无符号编码,一共可存储65 536个字符(0x0000~0xffff),所以Java中的字符几乎可以处理所有国家的语言文字。
在为char型常量或变量赋值时,如果所赋的值为一个英文字母、符号或汉字,必须将所赋的值放在英文状态下的一对单引号中。例如,下面的代码分别将字母“M”、符号“*”和汉字“男” 赋值给char型变量ca、cb和cc:
char ca = 'M'; // 将大写字母"M"赋值给char型变量
char cb = '*'; // 将符号"*"赋值给char型变量
char cc = ' 男'; // 将汉字"男"赋值给char型变量
在为char型常量或变量赋值时,无论所赋的值为字母、符号还是汉字,都只能为一个字符。
因为Java把字符作为整数对待,并且可以存储65 536个字符,所以也可以将0~65 535的整数赋值给char型常量或变量,但是在输出时得到的并不是所赋的整数。例如,下面的代码将整数88赋值给char型变量c,在输出变量c时得到的是大写字母“X”:
char c = 88; // 将整数88赋值给char型变量c
System.out.println(c); // 输出char型变量c,将得到大写字母"X"
代码“System.out.println();”用来将指定的内容输出到控制台,并且在输出后换行;代码“System.out.print();”用来将指定的内容输出到控制台,但是在输出后不换行。
也可以将数字0~9以字符的形式赋值给char型常量或变量,赋值方式为将数字0~9放在英文状态下的一对单引号中。例如,下面的代码将数字“6”赋值给char型变量c:
char c = ' 6 '; // 将数字"6"赋值给char型变量
4.逻辑型
声明为逻辑型的常量或变量用来存储逻辑值,逻辑值只有true和false,分别用来代表逻辑判断中的“真”和“假”,逻辑型利用关键字“boolean”进行声明。
逻辑型
【例2-2】 为boolean型变量赋值并输出。
利用Eclipse编写本实例的具体步骤如下。
(1)新建Java项目。
① 在Eclipse中选择“文件”/“新建”/“项目”菜单项,打开“新建项目”对话框。
② 选择“Java项目”,单击“下一步”按钮,在弹出的对话框中设置项目名称为“SimpleExample”。
③ 单击“下一步”按钮,进入Java项目构建对话框,这里可以采用默认设置,直接单击“完成”按钮,完成Java项目的创建。
(2)新建Java类。
新建Java项目以后,可以在项目中创建Java类,具体步骤如下。
① 在包资源管理器中,在要创建Java类的项目上单击鼠标右键,从弹出的快捷菜单中选择“新建”/“类”菜单项。
② 在弹出的创建Java类对话框中设置包名(这里为“com”)和要创建的Java类的名称(这里为“Example”)。
③ 单击“完成”按钮,完成Java类的创建。
(3)编写Java代码。
使用向导建立Example类之后,Eclipse会自动打开该类的源代码编辑器,在该编辑器中可以编写Java程序代码。
可以将逻辑值true和false赋值给boolean型变量,例如下面的代码分别将逻辑值true和逻辑值false赋值给boolean型变量ba和bb:
package com;
public class Example {
public static void main(String[] args) {
boolean ba = true; // 将逻辑值true赋值给boolean型变量
boolean bb = false; // 将逻辑值false赋值给boolean型变量
System.out.println("ba is " + ba); // 输出boolean型变量ba
System.out.println("bb is " + bb); // 输出boolean型变量bb
}
}
执行上面的代码,在控制台将输出图2-2所示的内容。
图2-2 将逻辑值赋值给boolean型变量
也可以将逻辑表达式赋值给boolean型变量,例如下面的代码分别将逻辑表达式“6<8”和逻辑表达式“6 > 8”赋值给boolean型变量bc和bd:
package com;
public class Example {
public static void main(String[] args) {
boolean bc = 6 < 8; // 将逻辑表达式"6 < 8"赋值给boolean型变量
boolean bd = 6 > 8; // 将逻辑表达式"6 > 8"赋值给boolean型变量
System.out.println("6 < 8 is " + bc); // 输出boolean型变量bc
System.out.println("6 > 8 is " + bd); // 输出boolean型变量bd
}
}
执行上面的代码,在控制台将输出图2-3所示的内容。
图2-3 将逻辑表达式赋值给boolean型变量
2.3.2 引用数据类型
引用数据类型包括类引用、接口引用和数组引用。下面的代码分别声明一个java.lang.Object类的引用、java.util.List接口的引用和一个int型数组的引用:
引用数据类型
Object object = null; // 声明一个java.lang.Object类的引用,并初始化为null
List list = null; // 声明一个java.util.List接口的引用,并初始化为null
int[] months = null; // 声明一个int型数组的引用,并初始化为null
System.out.println("object is " + object); // 输出类引用object
System.out.println("list is " + list); // 输出接口引用list
System.out.println("months is " + months); // 输出数组引用months
当将引用数据类型的常量或变量初始化为null时,表示引用数据类型的常量或变量不引用任何对象。
执行上面的代码,在控制台将输出如下内容:
object is null
list is null
months is null
在具体初始化引用数据类型时需要注意的是,对接口引用的初始化需要通过接口的相应实现类实现。例如,下面的代码在具体初始化接口引用list时,是通过接口java.util.List的实现类java.util.ArrayList实现的:
Object object = new Object(); // 声明并具体初始化一个java.lang.Object类的引用
List list = new ArrayList(); // 声明并具体初始化一个java.util.List接口的引用
int[] months = new int[12]; // 声明并具体初始化一个int型数组的引用
System.out.println("object is " + object); // 输出类引用object
System.out.println("list is " + list); // 输出接口引用list
System.out.println("months is " + months); // 输出数组引用months
执行上面的代码,在控制台将输出如下内容:
object is java.lang.Object@de6ced
list is [ ]
months is [I@c17164
【例2-3】 使用引用类型定义员工的姓名。
public class BasicMessage {
private int id;
private String name; //使用引用类型定义员工姓名
private int age;
private int dept;
private int headship;
private String sex;
…//省略部分代码
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setHeadship(int headship) {
this.headship = headship;
}
}
2.3.3 基本类型与引用类型的区别
基本数据类型与引用数据类型的主要区别在以下两个方面:
基本类型与引用类型的区别
(1)基本数据类型与引用数据类型的组成;
(2)Java虚拟机处理基本数据类型变量与引用数据类型变量的方式。
1.组成
基本数据类型是一个单纯的数据类型,它表示的是一个具体的数字、字符或逻辑值,如68、'M'或true。对于引用数据类型,若一个变量引用的是一个复杂的数据结构的实例,则该变量的类型就属于引用数据类型。在引用数据类型变量所引用的实例中,不仅可以包含基本数据类型的变量,还可以包含对这些变量的具体操作行为,甚至是包含其他引用数据类型的变量。
【例2-4】 基本数据类型与引用数据类型。
创建一个档案类Record,在该类中利用引用类型变量name存储姓名,利用char型变量sex存储性别,利用int型变量age存储年龄,利用boolean型变量married存储婚姻状况,并提供了一些操作这些变量的方法,Record类的具体代码如下:
public class Record {
String name; // 姓名
char sex; // 性别
int age; // 年龄
boolean married; // 婚姻状况
public int getAge() { // 获得年龄
return age;
}
public void setAge(int age) { // 设置年龄
this.age = age;
}
public boolean isMarried() { // 获得婚姻状况
return married;
}
public void setMarried(boolean married) { // 设置婚姻状况
this.married = married;
}
public String getName() { // 获得姓名
return name;
}
public void setName(String name) { // 设置姓名
this.name = name;
}
public char getSex() { // 获得性别
return sex;
}
public void setSex(char sex) { // 设置性别
this.sex = sex;
}
}
下面创建两个Record类的实例,并分别通过变量you和me进行引用,具体代码如下:
public class Example {
public static void main(String[] args) {
Record you = new Record(); // 创建代表读者的对象
Record me = new Record(); // 创建代表作者的对象
}
}
对于上面的变量you和me,就属于引用数据类型,并且引用的是类的实例,所以也是类引用类型。
下面继续在Example类的main()方法中编写如下代码,通过Record类中的相应方法,依次初始化代表读者和作者的变量you和me中的姓名、性别、年龄和婚姻状况:
you.setName("读者"); // 设置读者的姓名
you.setSex('女'); // 设置读者的性别
you.setAge(22); // 设置读者的年龄
you.setMarried(false); // 设置读者的婚姻状况
me.setName("作者"); // 设置作者的姓名
me.setSex('男'); // 设置作者的性别
me.setAge(26); // 设置作者的年龄
me.setMarried(true); // 设置作者的婚姻状况
下面继续在Example类的main()方法中编写如下代码,通过Record类中的相应方法,依次获得读者和作者的姓名、性别、年龄和婚姻状况,并将得到的信息输出到控制台:
System.out.print(you.getName() + " "); // 获得并输出读者的姓名
System.out.print(you.getSex() + " "); // 获得并输出读者的性别
System.out.print(you.getAge() + " "); // 获得并输出读者的年龄
System.out.println(you.isMarried() + " "); // 获得并输出读者的婚姻状况
System.out.print(me.getName() + " "); // 获得并输出作者的姓名
System.out.print(me.getSex() + " "); // 获得并输出作者的性别
System.out.print(me.getAge() + " "); // 获得并输出作者的年龄
System.out.println(me.isMarried() + " "); // 获得并输出作者的婚姻状况
执行上面的代码,在控制台将输出如图2-4所示信息。
2.Java虚拟机的处理方式
对于基本数据类型的变量,Java虚拟机会根据变量的实际类型为其分配实际的内存空间,例如,为int型变量分配一个4字节的内存空间来存储变量的值。而对于引用数据类型的变量,Java虚拟机同样要为其分配内存空间,但在内存空间中存放的并不是变量所引用的对象,而是对象在堆区存放的地址,所以引用变量最终只是指向被引用的对象,而不是存储了被引用的对象。因此,两个引用变量之间的赋值,实际上就是将一个引用变量存储的地址复制给另一个引用变量,从而使两个变量指向同一个对象。
图2-4 例2-2的运行结果
例如,创建一个图书类Book,具体代码如下:
public class Book {
String isbn = "978-7-115-16451-3";
String name = "Hibernate应用开发完全手册";
String author = "明日科技";
float price = 59.00F;
}
下面声明两个Book类的实例,分别通过变量book1和book2进行引用,对book1进行了具体的初始化,而将book2初始化为null,具体代码如下:
Book book1 = new Book();
Book book2 = null;
Java虚拟机为引用变量book1、book2及book1所引用对象的成员变量分配的内存空间如图2-5所示。
图2-5 未具体初始化book2时的内存空间分配情况
从图2-5可以看出,变量book1引用了Book类的实例,book2没有引用任何实例。下面对变量book2进行具体的初始化,将book1引用实例的地址复制给book2变量,即令book2与book1引用同一个Book类的实例,具体代码如下:
book2 = book1;
此时Java虚拟机的内存空间分配情况如图2-6所示。
图2-6 具体初始化book2后的内存空间分配情况
2.3.4 数据类型之间的相互转换
所谓数据类型之间的相互转换,就是将变量从当前的数据类型转换为其他数据类型。在Java中,数据类型之间的相互转换可以分为以下3种情况:
数据类型之间的相互转换
(1)基本数据类型之间的相互转换;
(2)字符串与其他数据类型之间的相互转换;
(3)引用数据类型之间的相互转换。
在这里只介绍基本数据类型之间的相互转换,其他两种情况将在相关的章节中介绍。
在对多个基本数据类型的数据进行混合运算时,如果这几个数据并不属于同一基本数据类型,例如在一个表达式中同时包含整数型、浮点型和字符型的数据,需要先将它们转换为统一的数据类型,然后才能进行计算。
基本数据类型之间的相互转换又分为两种情况,分别是自动类型转换和强制类型转换。
1.自动类型转换
当需要从低级类型向高级类型转换时,编程人员无须进行任何操作,Java会自动完成从低级类型向高级类型转换。低级类型是指取值范围相对较小的数据类型,高级类型则指取值范围相对较大的数据类型,如long型相对于float型是低级数据类型,但是相对于int型则是高级数据类型。在基本数据类型中,除了boolean型外均可参与算术运算,这些数据类型从低到高的排序如图2-7所示。
图2-7 数据类型从低到高的排序
在不同数据类型间的算术运算中,可以分为两种情况进行考虑,一种情况是在算术表达式中含有int、long、float或double型的数据,另一种情况是不含有上述4种类型的数据,即只含有byte、short或char型的数据。
(1)在算术表达式中含有int、long、float或double型的数据。
如果在算术表达式中含有int、long、float或double型的数据,Java首先会将所有数据类型相对较低的变量自动转换为表达式中数据类型最高的数据类型,然后再进行计算,并且计算结果的数据类型也为表达式中数据类型相对最高的数据类型。
例如在下面的代码中,Java首先会自动将表达式“b * c - i + l”中的变量b、c和i的数据类型转换为long型,然后再进行计算,并且计算结果的数据类型为long型。所以将表达式“b * c - i + l”直接赋值给数据类型相对小于long型(例如int型)的变量是不允许的,但是可以直接赋值给数据类型相对大于long型(例如float型)的变量。
byte b = 75;
char c = 'c';
int i = 794215;
long l = 9876543210L;
long result = b * c - i + l;
而在下面的代码中,Java首先会自动将表达式“b * c - i + d”中的变量b、c和i的数据类型转换为double型,然后再进行计算,并且计算结果的数据类型为double型。所以将表达式“b * c - i + d”直接赋值给数据类型相对小于double型(例如long型)的变量是不允许的。
byte b = 75;
char c = 'c';
int i = 794215;
double d = 11.17;
double result = b * c - i + d;
(2)在算术表达式中只含有byte、short或char型的数据。
如果在算术表达式中只含有byte、short或char型的数据,Java首先会将所有变量的类型自动转换为int型,然后再进行计算,并且计算结果的数据类型也为int型。
例如在下面的代码中,Java首先会自动将表达式“b + s * c”中的变量b、s和c的数据类型转换为int型,然后再进行计算,并且计算结果的数据类型为int型。所以将表达式“b + s * c”直接赋值给数据类型相对小于int型(例如char型)的变量是不允许的,但是可以直接赋值给数据类型相对大于int型(例如long型)的变量。
byte b = 75;
short s = 9412;
char c = 'c';
int result = b + s * c;
即使是在下面的代码中,Java首先也会自动将表达式“s1 * s2”中的变量s1和s2的数据类型转换为int型,然后再进行计算,并且计算结果的数据类型也为int型。
short s1 = 75;
short s2 = 9412;
int result = s1 * s2;
对于数据类型为byte、short、int、long、float和double的变量,可以将数据类型相对较小的数据或变量,直接赋值给数据类型相对较大的变量,例如可以将数据类型为short的变量直接赋值给数据类型为float的变量;但是不可以将数据类型相对较大的数据或变量,直接赋值给数据类型相对较小的变量,例如不可以将数据类型为float的变量直接赋值给数据类型为short的变量。
对于数据类型为char的变量,不可以将数据类型为byte或short的变量直接赋值给char型变量;但是可以将char型变量直接赋值给int、long、float或double的变量。
2.强制类型转换
如果需要把数据类型相对较高的数据或变量赋值给数据类型相对较低的变量,就必须进行强制类型转换。例如,将Java默认为double型的数据“7.5”,赋值给数据类型为int型变量的方式如下:
int i = (int) 7.5;
上面代码中,在数据“7.5”的前方添加了代码“(int)”,意思就是将数据“7.5”的类型强制转换为int型。
在执行强制类型转换时,可能会导致数据溢出或精度降低。例如,上面代码中最终变量i的值为7,导致数据精度降低。如果将Java默认为int型的数据“774”赋值给数据类型为byte型变量,方法如下:
byte b = (byte) 774;
最终变量b的值为6,导致数据溢出,原因是整数774超出了byte型的取值范围,在进行强制类型转换时,表示整数774的二进制数据流的前24位将被舍弃,所以最终赋值给变量b的数值是后8位的二进制数据流表示的数据,如图2-8所示。
图2-8 将十进制数774强制类型转换为byte型
在编程的过程中,对可能导致数据溢出或精度降低的强制类型转换,建议读者要谨慎使用。
2.4 数组
数组是一种最为常见的数据结构,通过数组可以保存一组相同数据类型的数据,数组一旦创建,它的长度就固定了。数组的类型可以为基本数据类型,也可以为引用数据类型,可以是一维数组、二维数组,甚至是多维数组。
数组
2.4.1 声明数组
声明数组包括数组类型和数组标识符。
声明一维数组的方式如下:
数组类型[] 数组标识符;
数组类型 数组标识符[];
上面两种声明数组格式的作用是相同的,相比之下,前一种方式更符合规范要求,但是后一种方式更符合原始编程习惯。例如,分别声明一个int型和boolean型一维数组,具体代码如下:
int[] months;
boolean members[];
Java语言中的二维数组是一种特殊的一维数组,即数组的每个元素又是一个一维数组,Java语言并不直接支持二维数组。声明二维数组的方式如下:
数组类型[][] 数组标识符;
数组类型 数组标识符[][];
例如,分别声明一个int型和boolean型二维数组,具体代码如下:
int[][] days;
boolean holidays[][];
2.4.2 创建数组
创建数组,实质上就是在内存中为数组分配相应的存储空间。
创建一维数组:
int[] months = new int[12];
创建二维数组:
int[][] days = new int[2][3];
可以将二维数组看成是一个表格,例如上面创建的数组days可以看成表2-4所示的表格。
表2-4 二维数组内部结构表
|
列索引0 |
列索引1 |
列索引2 |
---|---|---|---|
行索引0 |
days[0][0] |
days[0][1] |
days[0][2] |
行索引1 |
days[1][0] |
days[1][1] |
days[1][2] |
2.4.3 初始化数组
在声明数组的同时,也可以给数组元素一个初始值。一维数组初始化的代码如下:
int boy [] ={2,45,36,7,69};
上述语句等价于:
int boy [] = new int [5]
二维数组初始化的代码如下:
boolean holidays[][] = { { true, false, true }, { false, true, false } };
2.4.4 数组长度
数组元素的个数称作数组的长度。对于一维数组,“数组名.length”的值就是数组中元素的个数;对于二维数组,“数组名.length”的值是它含有的一维数组的个数。
int [] months = new int [12]; //一维数组months
Boolean [] members = {false,true,true,false}; //一维数组members
int[][] days = new int[2][3]; //二维数组days
boolean holidays[][] = { { true, false, true }, { false, true, false } };
//二维数组holidays
如果需要获得一维数组的长度,可以通过下面的方式:
System.out.println(months.length); // 输出值为12
System.out.println(members.length); // 输出值为4
如果是通过下面的方式获得二维数组的长度,得到的是二维数组的行数:
System.out.println(days.length); // 输出值为2
System.out.println(holidays.length); // 输出值为2
如果需要获得二维数组的列数,可以通过下面的方式:
System.out.println(days[0].length); // 输出值为3
System.out.println(holidays[0].length); // 输出值为3
如果是通过“{}”创建的数组,数组中每一行的列数也可以不相同,例如:
boolean holidays[][] = {
{ true, false, true }, // 二维数组的第1行为3列
{ false, true }, // 二维数组的第2行为2列
{ true, false, true, false } }; // 二维数组的第3行为4列
在这种情况下,通过下面的方式得到的只是第1行拥有的列数:
System.out.println(holidays[0].length); // 输出值为3
如果需要获得二维数组中第2行和第3行拥有的列数,可以通过下面的方式:
System.out.println(holidays[1].length); // 输出值为2
System.out.println(holidays[2].length); // 输出值为4
2.4.5 使用数组元素
一维数组通过索引符来访问自己的元素,如months[0]、months[1]等。需要注意的是,索引是从0开始,而不是从1开始。如果数组中有4个元素,那么索引到3为止。
在访问数组中的元素时,需要同时指定数组标识符和元素在数组中的索引。例如,访问前面代码中创建的数组,输出索引位置为2的元素,具体代码如下:
System.out.println(months[2]);
System.out.println(members[2]);
二维数组也是通过索引符访问自己的元素,在访问数组中的元素时,需要同时指定数组标识符和元素在数组中的索引。例如,访问2.4.4节代码中创建的二维数组,输出位于第2行、第3列的元素,具体代码如下:
System.out.println(days[1][2]);
System.out.println(holidays[1][2]);
小结
本章深入学习了Java语言的基础知识,其中主要包括关键字与标识符,常量和变量的区别;基本数据类型、引用数据类型、基本类型与引用类型的区别,以及不同数据类型之间相互转换的方法和需要注意的一些事项;最后还讲解了一维数组和二维数组的使用方法,尤其是对二维数组的操作。
习题
2-1 简述常量和变量的区别。
2-2 编写一个程序,获得整数型的默认值。
2-3 请指出下面表达式中的错误,并说出错误的原因。
short s = '6';
char c = 168;
int i = (int) true;
long l = 0123;
float f = -68;
double d = 0x1234567;
2-4 请说出下面程序的运行结果,并编译执行,验证自己的结论是否正确。
public class Test {
int i1 = 1;
int i2;
public static void main(String[] args) {
int i = 3;
Test test = new Test();
System.out.println(i + test.i1 + test.i2);
}
}