第三章 数据类型和运算符
3.1 注释
Java语言是一门强类型语言。
强类型包含两方面的含义:
1.所有变量必须先声明、后使用。
2.指定类型的变量只能接受类型与之匹配的值。
3.1 注释
单行注释:将双斜线(//)放在需要注释的内容之前。
多行注释:使用“/*”和“*/”将程序中需要注释的内容包含起来。
文档注释:以斜线后紧跟两个星号(/**)开始,以星号后紧跟一个斜线(*/)结束,中间部分都是文档注释,会被提取到API文档中。
文档注释用于生成API文档,而API文档主要用于说明类、方法、成员变量的功能。(javadoc工具)
javados工具未深入研究
3.2 标识符和关键字
3.2.1 分隔符
分号(;):
作为语句的分隔,因此每个Java语句必须使用分号作为结尾
注:JAVA程序允许一行书写多个语句,每个语句之间以分号隔开即可;一个语句也可以跨多行,只要最后结束的地方使用分号结束即可。
例如,
int age = 25; String name = "ligang";
String hello = "你好!" +
"java";
值得指出的是,一个字符串、变量名不能跨越多行。从可读性角度来看,应该避免在一行书写多个语句。
花括号({}):
定义一个代码块。
类定义部分、方法体部分、条件语句执行体和循环语句中的循环体通常也放在代码块里。
方括号([]):
主要作用是用于访问数组元素,方括号通常紧跟数组变量名,而方括号里指定希望访问的数组元素的索引。
如:
//下面代码试图为名为a的数组的第四个元素赋值
a[3] = 3;
圆括号(()):
功能丰富,后面进一步介绍。
空格:
分隔一条语句的不同部分。
圆点(.):
用作类/对象和它的成员(包括成员变量、方法和内部类)之间的分隔符,表名调用某个类或实例的指定成员。
3.2.2 标识符规则
标志符:用于给程序中变量、类、方法命名的符号。
Java语言的标识符必须以字母、下画线(_)、美元符($)开头,后面可以跟任意数目的字母、数字、下画线(_)和美元符($)。此处的字母并不局限于26个英文字母,而且包含中文字符、日文字符等。
JAVA语言是区分大小写的,因此abc和ABC是两个不同的标识符。
使用标识符时,注意如下规则:
1.标识符可以由字母、数字、下划线(_)和美元符($)组成,数字不能打头。
2.标识符不能是Java关键字和保留字
3.标识符不能含空格
4.标识符只能包含美元符($),不能包含@、#等其他特殊字符。
3.2.3 Java关键字
JAVA中具有特殊用途的单词被称为关键字(keyword)
所有关键字都是小写的,TRUE、FALSE和NULL都不是Java关键字。
1.enum是从Java5新增的关键字,用于定义一个枚举。
2.goto和const这两个关键字也被称为保留字(reserved word),保留字的意思:Java还未使用这两个关键字,可能在未来版本使用。
3.三个特殊直接量(literal):true、false和null;(标识符也不能使用这三个特殊的直接量)。
3.3 数据类型分类语言是一门强类型语言。
Java强类型包含两方面的含义:
1.所有变量必须先声明、后使用。
2.指定类型的变量只能接受类型与之匹配的值。
声明变量的语法非常简单,只要指定变量的类型和变量名即可
如下:
type varName[ = 初始值];
JAVA语言支持的类型分为两类:基本类型和引用类型
基本类型:boolean类型和数值类型。数值类型有整数类型和浮点类型。整数类型包括bytes、short、int、long、char,浮点类型包括float和double。
提示:car代表字符类型,实际也是一种整数类型,相当于无符号整数类型。
引用类型:包括类、接口和数组类型,还有一种特殊的null类型。所谓引用类型就是对一个对象的引用,对象包括实例和数组两种。
空类型:就是null值的类型,这种类型没有名称。实际开发中,可以忽略null类型。不要把一个null赋值给基本数据类型变量,因为空引用(null)只能被转换成引用类型。
3.4 基本数据类型
基本数据类型分为两大类:Boolean类型和数值类型。
数值类型分为:整数类型和浮点类型。
JAVA中基本类型分为4类:
3.4.1 整型
byte:在内存中占8位,表数范围是:-128(-2^7)~127(2^7-1)
short:在内存中占16位,表数范围是:-32768(-2^15)~32767(2^15-1)
int:在内存中占32位,表数范围是:-2147483648(-2^31)~2147483647(2^31-1)
long:在内存中占64位,表数范围是:(-2^63)~(2^63-1)
int是最常用的整数类型,除此以外,有如下两种情形必须指出:
1.如果直接将一个较小的整数值(在byte或short类型的表数范围内)赋给一个byte或short变量,系统会自动把这个整数值当成byte或者short类型来处理。
2.如果使用一个巨大的整数值(超出了int类型的表数范围)时,Java不会自动把这个整数值当成long类型来处理。如果希望系统把一个整数值当成long类型来处理。应该在这个整数值后增加1或者L作为后缀。通常使用L。
如:
//系统会自动把56当成bytes类型处理
byte a = 56;
//在巨大的整数值后使用L后缀,强制使用long类型
long bigValue2 = 92233789994554L;
Java中整数值有4种表示方式:十进制、二进制。八进制和十六进制
二进制整数:以0b或者0B开头。
八进制整数:以0开头。
十六进制整数以0x或者0X开头,其中10~15分别以a~f(a~f不区分大小写)来表示.
如:
//以0开头的整数值是八进制的整数
int octaValue = 013;
//以0x或者0X开头的整数值是十六进制的整数
int hexValue1 = 0x13;
int hexValue2 = 0Xaf;
1 //定义两个8位的二进制整数 2 int binVal1 = 0b11010100; 3 byte binVal2 = 0B01101001; 4 //定义一个32位的二进制整数,最高位是符号位 5 int binVal3 = 0B10000000000000000000000000000000011; 6 System.out.println(binVal1);//输出212 7 System.out.println(binVal2);//输出105 8 System.out.println(binVal3);//输出-2147483645
当定义32位的二进制整数时,最高位其实是符号位,当符号位是1时,表名它是一个负数,负数在计算机里是以补码的形式存在的,因此需要换算成原码。
整数值默认就是int类型,因此使用二进制形式定义整数时,二进制整数默认占32位,其中第32位是符号位;如果在二进制整数后添加l或L后缀,那么这个二进制整数默认占64位,其中第64位是符号位。
如:
/*
定义一个8位的二进制整数,该数值默认占32位,因此它是一个正数
只是强制类型转换成byte时产生了溢出,最终导致binVal4变成了-23
*/
byte binVal4 = (byte)0b11101001;
/*
定义一个32位的二进制整数,最高位是1
但由于数值后添加了L后缀,因此该整数实际占64位,第32位的1不是符号位
因此binVal5的值等于2的31次方+ 2 + 1
1 */ 2 long binVal5 = 0B10000000000000000000000000000011L; 3 System.out.println(binVal4);//输出-23 4 System.out.println(binVal5);//输出2147483651
3.4.2 字符型
字符型通常用于表示单个的字符,字符型值必须使用单引号(')括起来。
Java使用16位Unicode字符集作为编码方式
字符型值有如下三种表示形式:
1.直接通过单个字符来指定字符型值,例如’A‘、’9‘和’0‘等
2.通过转义字符表示特殊字符型值,例如’\n'、'\r'等
3.直接通过使用Unicode值来表示字符型值,格式是'\uXXXX',其中XXXX代表一个十六进制的整数。
Java语言中常用的转义字符如表3.2所示
字符值也可以采用十六进制编码方式来表示,范围是'\u0000'~'\uFFFFF',一共表示65536个字符,其中前256个('\u0000'~'\u00FF')字符和ASCII码中的字符完全重合。
由于计算机实际是保存该字符对应的编码,因此char类型的值也可直接作为整型来使用,它相当于一个16位的无符号整数,表数范围是0~65535.
char类型的变量、值完全可以参与加、减、乘、除等数学运算,也可以比较大小——实际上都是用该字符对应的编码参与运算。
下面程序简单示范了字符型变量的用法:
1 //直接指定单个字符作为字符值 2 char aChar = 'a'; 3 //使用转义字符来作为字符值 4 char enterChar = '\r'; 5 //使用Unicode编码值来指定字符值 6 char ch = '\u9999'; 7 //将输出一个'香'字符 8 System.out.printIn(ch); 9 //定义一个‘疯’字符值 10 char zhong = '疯'; 11 //直接将一个char变量当成int类型变量使用 12 int zhongValue = zhong; 13 System.out.printIn(zhongValue); 14 //直接把一个0~65535范围内的int整数赋给一个char变量 15 char c = 97; 16 System.out.printIn(c);
Java没有提供表示字符串的基本数据类型,而是通过String类来表示字符串,由于字符串由多个字符组成,因此字符串要使用双引号括起来。如下:
//下面代码定义了一个s变量,它是一个字符串实例的引用,它是一个引用类型的变量
String s = "沧海月明珠有泪,蓝田玉暖日生烟。";
注意:char类型使用单引号括起来,而字符串使用双引号括起来。
3.4.3 浮点型
浮点型有两种:float和double
double类型代表双精度浮点数,float类型代表单精度浮点数。
一个double类型的数值占8个字节、64位
一个float类型的数值占4个字节,32位
浮点型两种表现形式:
1.十进制形式:简单的浮点数,例如5.12、512.0、.512.浮点数必须包含一个小数点,否则会当成int类型处理。
2.科学计数法:例如5.12e2(即5.12*10^2),5.12E2(也是5.12*10^2)。
必须指出:只有浮点类型的数值才可以使用科学计数法形式表示。例如,51200是一个int类型的值,但512E2则是浮点类型的值。
Java语言的浮点类型默认是double类型,如果希望Java把一个浮点类型值当成float类型处理,应该在这个浮点类型后紧跟f或F。例如:5.12代表一个double类型的值,占64位的内存空间;5.12f或者5.12F才表示一个float类型的值,占32位的内存空间。当然,也可以在一个浮点数后添加d或F后缀,强制指定是double类型,但通常没必要。
三种特殊的浮点数值:正无穷大、负无穷大和非数,用于表示溢出和出错。
正无穷大:使用一个正数除以0将得到正无穷大。
负无穷大:使用一个负数除以0将得到负无穷大。
非数:0.0除以0.0或对一个负数开方将得到一个非数。
正无穷大:Double或Float类的POSITIVE_INFNITY表示
负无穷大:Double或Float类的NEGATIVE_INFINTY表示
非数:Double或Float类的NAN表示
所有的正无穷大数值都是相等的
所有的负无穷大数值都是相等的
NaN不与任何数值相等,甚至和NaN都不相等
注意:
只有浮点数除以0才可以得到正无穷大和负无穷大
1 package learn001; 2 3 4 /** 5 * Created by 18051581 on 2019/2/11. 6 */ 7 public class learn001 { 8 public static void main(String[] args) { 9 float af = 5.234556f; 10 //下面将看到af的值已经发生了改变 11 // System.out.printIn(af); 12 double a = 0.0; 13 double c = Double.NEGATIVE_INFINITY; 14 float d = Float.NEGATIVE_INFINITY; 15 //看到float和double的负无穷大是相等的 16 System.out.println(c == d); 17 //0.0除以0.0将出现非数 18 System.out.println(a / a); 19 //两个非数之间是不相等的 20 System.out.println(a / a == Float.NaN); 21 //所有正无穷大都是相等的 22 System.out.println(6.0 / 0 == 555.0 / 0); 23 //负数除以0.0得到负无穷大 24 System.out.println(-8 / a); 25 //下面代码将抛出除以0的异常 26 //System.out.printIn(0 / 0); 27 } 28 }
数值中使用下画线分隔
数值位数过多时,可以在数值中使用下画线,不管是整数型数值,还是浮点型数值,都可以使用下画线。
package learn001; /** * Created by 18051581 on 2019/2/11. */ public class UnderscoreTest { public static void main(String[] args) { //定义一个32位的二进制数,最高位是符号位 int binVal = 0B1000_0000_0000_0000_0000_0000_0000_0011; double pi = 3.14_15_92_65_36; System.out.println(binVal); System.out.println(pi); double height = 8_8_4_8.23; System.out.println(height); } }
-2147483645
3.1415926536
8848.23
进程已结束,退出代码0
3.4.5 布尔型
布尔型只有一个boolean类型,用于表示逻辑上的“真”或者“假”。
boolean类型的数值只能是true或false,不能用0或者非0来代表。
其它基本数据类型的值也不能转换成boolean类型。
bit大部分时候实际上占用8位。
下面代码定义了两个boolean类型的变量,并制定初始值。
//定义b1的值为true
boolean b1 = true;
//定义b2的值为false
boolean b2 = false;
字符串"true"和"false"不会直接转换成boolean类型,但是如果使用一个boolean类型的值和字符串进行连接运算,则boolean类型的值将会自动转换成字符串。
如:
//使用boolean类型的值和字符串进行连接运算,boolean类型的值会自动转换成字符串
String str = true + "";
//下面将输出true
System.out.println(str);
boolean类型的值或变量主要用作旗标来进行流程控制,Java语言中使用boolean类型的变量或值控制的流程主要:
1.if条件控制语句
2.while循环控制语句
3.do循环控制语句
4.for循环控制语句
除此以外。boolean类型的变量和值还可在三目运算符(? :)中使用。
3.5 基本类型的类型转换
两种类型转换方式:自动类型转换和强制类型转换
3.5.1 自动类型转换
自动类型转换:把一个表数范围小的数值或变量直接赋给另一个表数范围大的变量时,系统可以进行自动类型转换;否则就需要强制转换。
如同两瓶水,小瓶里的水倒入大瓶中时不会有任何问题。
Java支持自动类型转换的类型如图:
1 package learn001; 2 3 /** 4 * Created by 18051581 on 2019/2/11. 5 */ 6 public class AutoConversion { 7 public static void main(String[] args) { 8 int a = 6; 9 //int类型可以自动转换为float类型 10 float f = a; 11 //下面将输出6.0 12 System.out.println(f); 13 //定义一个byte类型的整数变量 14 byte b = 9; 15 //下面代码将出错,byte类型不能自动类型转换为char类型 16 //char c = b 17 //byte类型变量可以自动转换为double类型 18 double d = b; 19 System.out.println(d); 20 } 21 }
6.0
9.0
进程已结束,退出代码0
任何基本类型和字符串进行连接运算时,基本类型的值将自动类型转换为字符串类型。
如果希望把基本类型的值转换为对应的字符串时,可以把基本类型的值和一个空字符串进行连接。
提示:+不仅可作为加法运算符使用,还可作为字符串连接运算符使用。
1 package learn001; 2 3 /** 4 * Created by 18051581 on 2019/2/11. 5 */ 6 public class PrimitiveAndString { 7 public static void main(String[] args) { 8 //下面代码是错误的,因为5是一个整数,不能直接赋给一个字符串 9 //String str1 = 5; 10 //一个基本类型的值和字符串进行连接运算时,基本类型的值自动转换为字符串 11 String str2 = 3.5f + ""; 12 //下面输出3.5 13 System.out.println(str2); 14 //下面语句输出7Hellow! 15 System.out.println(3 + 4 + "Hello"); 16 //下面语句输出Hello!34,因为Hello!+3会把3当成字符串处理 17 //而后再把4当成字符串处理 18 System.out.println("Hello!" + 3 + 4); 19 } 20 }
3.5.2 强制类型转换
语法格式:(targetType)value,强制类型转换的运算符是圆括号(())
类似于把一个大瓶子里的水倒入一个小瓶子,如果大瓶子里的水不多还好,但是如果大瓶子的水很多就会溢出,从而造成数据的丢失。
1 package learn001; 2 3 /** 4 * Created by 18051581 on 2019/2/11. 5 */ 6 public class NarrowConversion { 7 public static void main(String[] args) 8 { 9 int iValue = 233; 10 //强制把一个int类型的值转换为byte类型的值 11 byte bValue = (byte)iValue; 12 //将输出-23 13 System.out.println(bValue); 14 double dValue = 3.98; 15 //强制把一个double类型的值转换为int类型的值 16 int tol = (int)dValue; 17 //将输出3 18 System.out.println(tol); 19 } 20 }
3.98——》3浮点数转换为整数时,Java直接截断浮点数的小数部分。
233——》23强制把整数233转换为byte类型的整数,从而变成-23,这就是典型的溢出。
生成一个6位的随机字符串,用到后面的循环控制:
1 package learn001; 2 3 /** 4 * Created by 18051581 on 2019/2/11. 5 */ 6 public class RandomStr { 7 public static void main(String[] args) 8 { 9 //定义一个空字符串 10 String result = ""; 11 //进行6次循环 12 for(int i = 0;i < 6 ; i ++) 13 { 14 //生成一个97~122之间的int类型整数 15 int intVal = (int)(Math.random() * 26 + 97); 16 //将intValue强制转换为char类型后连接result后面 17 result = result + (char)intVal; 18 } 19 //输出随机字符串 20 System.out.print(result); 21 } 22 } 23 24 vasrmv 25 进程已结束,退出代码0
//直接把5.6赋值给float类型变量将出现错误,因为5.6默认是double类型
float a = 5.6
5.6默认是double类型的浮点数,因此将5.6赋值给一个float类型变量将导致错误,必须强制转换:
float a=(float)5.6
字符串转换为基本类型:
通过基本类型对应的包装类实现把字符串转换成基本类型
字符串转换成int类型:
String a = "45";
//使用Integer的方法将一个字符串转换成int类型
int iValue = Integer.parseInt(a);
提示:
Java提供了8种基本类型的包装类:
boolean——Boolean
byte——Byte
short——Short
int——Integer
long——Long
char——Character
float——Float
double——Double
都提供了:parseXxx(String str)静态方法
包装类第6章会介绍。
3.5.3 表达式类型的自动提升
自动提升规则:
1.所有的byte类型、short类型和char类型将被提升到int类型
2.整个算数表达式的数据类型自动提升与表达式中最高等级操作数同样的类型。操作数的等级如下图,箭头右边类型的等级高于位于箭头左边类型的等级。
典型的错误:
//定一个short类型变量
short sValue = 5;
//表达式中的sValue将自动提升到int类型,则右边的表达式类型为int
//将一个int类型值赋值给short类型变量将发生错误
sValue = sValue - 2
sValue-2表达式的类型将被提升到int类型,这样就把右边的int类型值赋给左边的short类型变量,从而导致错误。
正确代码:
byte b = 40;
char c = 'a';
int i = 23;
double d = .314;
//右边表达式中最高等级操作数为d(double类型)
//则右边表达式的类型为double类型,故赋给一个double类型变量
double result = b + c + i * d;
//将输出144.222
System.out.println(result);
两个int类型整数进行除法运算,即使无法除尽,也将得到一个int类型结果。
int val = 3;
//右边表达式中两个操作数都是int类型,故右边表达式的类型为int
//虽然23/3不能除尽,但依然得到一个int类型整数
int intResult = 23 / val;
System.out.println(intResult);//将输出7
当两个整数进行除法运算时,如果不能整除,得到的结果将是把小数部分截断取整后的整数。
表达式中包含了字符串:
当把加号(+)放在字符串和基本类型值之间时,这个加号是一个字符串连接运算符,而不是进行加法运算,而不是进行加法运算。
代码:
//输出字符串Hello!a7
System.out.println("Hello!" + 'a' + 7);
//输出字符串104Hello!
System.out.println('a' + 7 + "Hello!");
第一个表达式"Hello!" + 'a' + 7",先进行"Hello!" + 'a' "运算,把'a'转换成字符串,拼接成字符串Hello!a,接着进行"Hello!a"+7运算,也是一个字符串运算,最终得到Hello!a7。
第二个表达式,先进行'a'+7加法运算,其中'a'自动提升到int类型,变成a对应的ASCII值:97,从97+7将得到104,然后进行104+Hello!运算,104会自动转换成字符串,将两个字符串的连接运算,从而得到104Hello!。
3.6 直接量
直接量是指在程序中通过源代码直接给出的值,例如在int a = 5;这行代码中,为变量a所分配的初始值5就是一个直接量。
3.6.1 直接量的类型
能指定直接量的通常只有三种类型:基本类型、字符串类型和null类型。
java支持如下8种类型的直接量:
1.int类型的直接量:程序中直接给出整型数值,分为二进制、十进制、八进制和十六进制4种,二进制需要以0B或0b开头,八进制以0开头,十六进制以0x或0X开头。如123、012(对应十进制的10)、0x12(对应十进制的18)
2.long类型的直接量:在整数值后添加l或L后变成了long类型的直接量、例如3L、0x12L(对应十进制的18L)。
3.float类型的直接量:在一个浮点数后添加f或F就变成了float类型的直接量。这个浮点数可以是标准小数形式,也可以是科学技术形式。例如5.34F、3.14E5f。
4.double类型的直接量:直接给出一个标准小数形式或科学计数法形式的浮点数就是double类型的直接量。例如5.34、3.14E5。
5.boolean类型的直接量:直接量只有true和false
6.char类型的直接量:char类型的直接量有三种形式,分别是用单引号括起来的字符、转义字符和Unicode值表示的字符。例如'a'、'\n'和'\u0061'
7.string类型的直接量:一个用双引号括起来的字符序列就是string类型的直接量。
8.null类型的直接量:只有一个值,即null。这个直接量可以赋给任何引用类型的变量,用以表示这个引用类型变量中保存的地址为空,即还未指向任何有效对象。
3.6.2 直接量的赋值
int a = 5;
char c = 'a';
boolean b = true;
float f = 5.12f;
double d = 4.12;
String author = "李刚";
String book = "疯狂Android讲义";
String类型的直接量不能赋给其他类型的变量,null类型的直接量可以直接赋给任何引用类型的变量,包括String类型。boolean类型的直接量只能赋给boolean类型的变量,不能赋给其他任何类型的变量。
关于字符串直接量有一点需要指出,当程序第一次使用某个字符串直接量时,Java会使用常量池来缓存该直接量,如果程序后面的部分需要用到该字符串直接量,Java会直接使用常量池中的字符串直接量。
提示:
由于String类是一个典型的不可变类,因此String对象创建出来就不可能被改变,因此无须当心共享String对象会导致混乱。
常量池指的是在编译期被确定,并被保存在已编译的class文件中的一些数据。它包括关于类、方法、接口中的常量,也包括字符串直接量。
程序:
String s0 = "hello";
String s1 = "hello";
String s2 = "he" + "llo";
System.out.println( s0 == s1 );
System.out.println( s0 == s2 );
运行结果为:
true
true
Java会确保每个字符串常量只有一个,不会产生多个副本。
例子中:
1.s0和s1中的hello都是字符串常量,它们在编译就被无额定了,所以s0 == s1返回true。
2.he和llo也都是字符常量,当一个字符串由多个字符串连接而成时,它本身也是字符串常量,s2同样在编译期就被解析为一个字符串常量,所以s2也是常量池中hello的引用。
3.因此,程序输出s0 == s1返回true,s1 == s2也返回true
3.7 运算符
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。
运算符分为:
1.算数运算符
2.赋值运算符
3.比较运算符
4.逻辑运算符
5.位运算符
6.类型相关运算符
3.71 算术运算符
7个基本运算符:
+:加法运算符:
double a = 5.2;
double b = 3.1;
double sum = a + b;
//sum的值为8.3
System.out.println(sum);
除此以外,+还可以作为字符串的连接运算符。
-:减法运算符:
double a = 5.2;
double b = 3.1;
double sub = a - b;
//sub的值为2.1
System.out.println(sub);
*:乘法运算符:
double a = 5.2;
double b =3.1;
double sub = a * b;
//multiply的值为16.12
System.out.println(multiply);
/:除法运算符:
1.有点特殊,除法运算符的两个操作都是整数类型,则计算结果也是整数,就是将自然除法的结果截断取整
如:
19/4的结果是4,而不是5.
如果除法运算符的两个操作数都是整数类型,则除数不可以是0,否则将引发除以零异常。
2.除法运算符的两个操作数有一个是浮点数,或者两个都是浮点数,则计算结果也是浮点数,这个结果就是自然除法的结果。而且此时允许除数是0,或者0.0,得到结果是正无穷大或无穷大。
1 public class DivTest { 2 public static void main(String[] args) 3 { 4 double a = 5.2; 5 double b = 3.1; 6 double div = a / b; 7 //div的值将是1.6774193548387097 8 System.out.println("5除以0.0的结果是:" + 5 / 0.0); 9 //输出正无穷大:-Infinty 10 System.out.println("-5除以0.0的结果是:"+ - 5 / 0.0); 11 //下面代码将出现异常 12 //java.lang.ArithmeticException:/by zero 13 System.out.println("-5除以0的结果是:" + -5 / 0); 14 } 15 }
3.%:求余运算符。
1.求余运算的结果不一定总是整数,它的计算结果是使用第一个操作数除以第二个操作数,得到一个整除的结果后剩下的值就是余数。
2.由于求余运算也需要进行除法运算,因此如果求余运算的两个操作数都是整数类型,则求余运算的第二个操作数不能是0,否则将引发除以零异常。
3.求余运算的两个操作数中有一个或者两个都是浮点数,则允许第二个操作数是0或0.0,只是求余运算的结果是非数:NaN。
4.0或0.0对零以外的任何数求余都将得到0或0.0
1 public class ModTest { 2 public static void main(String[] args) 3 { 4 double a = 5.2; 5 double b = 3.1; 6 double mod = a % b; 7 System.out.println(mod);//mod的值为2.1 8 System.out.println("5对0.0求余的结果是:" + 5 % 0.0);//输出非数:NaN 9 System.out.println("-5.0对0求余的结果是:" + -5.0 % 0);//输出非数:NaN 10 System.out.println("0对5.0求余的结果是:" + 0 % 5.0);//输出0.0 11 System.out.println("0对0.0求余的结果是:" + 0 % 0.0);//输出非数:NaN 12 //下面代码将出现异常:java.lang.ArithmeticException:/ by zero 13 System.out.println("-5对0求余的结果是:" + -5 % 0); 14 } 15 }
5.++:自加。
两个要点:
①自加是单目运算符,只能操作一个操作数。
②自加运算符只能操作单个数值型(整数、浮点型都行)的变量,不能操作常量或表达式。
③运算符既可以出现在操作数的左边,也可以出现在操作数的右边。
++放在左边,则先把操作数加1,然后才把操作数放入表达式中运算。
++放在右边,则先把操作数放入表达式中运算,然后才把操作数加1。
如下代码:
int a = 5;
//让a先执行算术运算,然后自加
int b = a++ + 6;
//输出a的值为6,b的值为11
System.out.println(a + "\n" + b);
执行的结果是a的值为6,b的值为11。当++在操作数右边时,先执行a+6的运算(此时a的值为5),然后对a加1。
int a = 5;
//让a先自加,然后执行算术运算
int b = ++a + 6;
//输出a的值为6,b的值为12
System.out.println(a + "\n" + b);
执行的结果是a的值为6,b的值为12。当++在操作数左边时,先对a加1,然后执行a+6的运算(此时a的值为6),因此b为12。
6.--:自减。也是单目运算符,用法与基本相似,只是将操作数的值减1.
注意:自加和自减只能用于操作变量,不能用于操作数值直接量、常量或表达式。例如,5++、6--等写法都是错误的。
java没有提供其他复杂的运算符,需要乘方、开方等运算,则可借助于java.lang.Math类的工具方法完成复杂的数学运算,代码如下:
1 public class MathTest { 2 public static void main(String[] args) 3 { 4 double a = 3.2;//定义a为3.2 5 //求a的5次方,并将计算结果赋给b 6 double b = Math.pow(a,5); 7 System.out.println(b);//输出b的值 8 //求a的平方根,并将结果赋给c 9 double c = Math.sqrt(a); 10 System.out.print(c);//输出c的值 11 //计算随机数,返回一个0~1之间的伪随机数 12 double d = Math.random(); 13 System.out.println(d);//输出随机数d的值 14 //求1.57的sin函数值:1.57被当成弧度数 15 double e = Math.sin(1.57); 16 System.out.println(e);//输出接近1 17 } 18 }
Math类下包含了丰富的静态方法,用于完成各种复杂的数学运算。
注意:
+除了可以作为数学的加法运算符之外,还可以作为字符串的连接运算符。-除了可以作为减法运算符之外,还可以作为求负的运算符。
-作为求负运算符的例子:
//定义double变量x,其值为-5.0
double x = -5.0;
x = -x;//将x求负,其值变为5.0
3.7.2 赋值运算符
赋值运算符用于为变量指定变量值,使用赋值运算符将一个直接量值赋给变量。如下代码:
String str = "Java";//为变量str赋值Java
double pi = 3.14;//为变量pi赋值3.14
boolean visited = true;//为变量visited赋值true
使用赋值运算符讲一个变量的值赋给另一个变量。如:
String str2 = str;//将变量str的值赋给str2
提示:
赋值运算符是从右向左执行计算的,程序先计算得到=右边的值,然后将该值“装入”=左边的变量,因此赋值运算符(=)左边只能是变量。
赋值表达式是有值得,赋值表达式的值就是右边被赋的值。赋值运算符支持连续赋值,通过使用多个赋值运算符,可以一次为多个变量赋值。代码如下:(可行,但不推荐)
int a;
int b;
int c;
//通过为a,b,c赋值,三个变量的值都是7
a = b = c = 7;
//输出三个变量的值
System.out.println(a + "\n" + b + "\n" + c);
赋值运算还可用于将表达式的值赋给变量。代码如下:
double d1 = 12.34;
double d2 = d1 + 5;//将表达式的值给d2
System.out.println(d2);//输出d2的值,将输出17.34
赋值运算符还可与其他运算符结合,扩展成功能更加强大的赋值运算符。
3.7.3 位运算符
位运算符7个:
1.&:按位与。当两位同时为1时才返回1。
2.|:按位或。只要有一位为1即可返回1。
3.~:按位非。单目运算符,将操作数的每个位(包括符号位)全部取反。
4.^:按位异或。当两位相同时返回0,不同时返回1。
5.<<:左移运算符。
6.>>:右移运算符
7.>>>:无符号右移运算符。
一般来说,位运算符只能操作整数类型的变量或值。
按位非只需要一个操作数,这个运算符将把操作数在计算机底层的二进制码按位(包括符号位)取反。如下代码测试了按位与和按位或运算的运行结果。
System.out.println(5 & 9);//将输出1
System.out.println(5 | 9);//将输出13
5的二进制码00000101(省略了前面的24个0),而9的二进制码是00001001(省略了前面的24个0)。运算过程如下图:
下面是按位异或和按位取反的执行代码:
System.out.println(~-5);//将输出4
System.out.println(5 ^ 9);//将输出12
程序执行~-5的结果是4,执行5^9的结果是12。下面通过图3.13来介绍运算原理。
左移运算符是将操作数的二进制码整体左移指定位数,左移后右边空出来的位以0填充。例如:
System.out.println(5 << 2);//输出20
System.out.println(-5 << 2);//输出-20
以-5为例来介绍左移运算的运算过程:
上面的32位数是-5的补码,左移两位后得到一个二进制补码,这个二进制补码的最高位时1,表明是一个负数,换算成十进制数就是-20。
JAVA的右移运算符有两个:>>和>>>,对于>>运算符而言,把第一个操作数的二进制码右移指定位数后,左边空出来的位以原来的符号位填充,即如果第一个操作数原来是正数,则左边补0;如果第一个操作数是负数,则左边补1。>>>是无符号右移运算符,它把第一个操作数的二进制码右移指定位数后,左边空出来的位总是以0填充。
代码如下:
System.out.println(-5 >> 2);//输出-2
System.out.println(-5 >>> 2);//输出1073741822
下面用示意图来说明>>和>>>运算符的运算过程。
-5右移2位后左边空出2位,空出来的2位以符号位补充。从图中可以看出,右移运算后得到的结果的正负与第一操作数的正负相同。右移后的结果依然是一个负数,这是一个二进制补码,换算成十进制数就是-2。
从图3.17来看,-5无符号右移2位后左边空出2位,空出来的2位以0补充。从图中看出,无符号右移运算后的结果总是得到一个正数。图3.17中下面的正数是10733741822(2^30 -2)
进行移位时还要遵循如下规则:
1.对于低于int类型(如byte、short和char)的操作数总是先自动类型转换为int类型后再移位。
2.对于int类型的正数移位a>>b,当b>32时,系统先用b对32求余(因为int类型只有32位),得到结果才是真正移位的位数。例如,a>>33和a>>1的结果完全一样,而a>>32的结果和a相同。
3.对于long类型的整数移位a>>b,当b>64时,总是先用b对64求余(因为long类型是64位),得到的结果才是真正移位的位数。
注意:
当进行移位运算时,只要被移位的二进制码没有发生有效为的数字丢失(对于正数而言,通常指被移出的位全部都是0),不难发现左移n位就相当于乘以2的n次方,右移n位则是除以2的n次方。不仅如此,进行移位运算不会改变操作数本身,只是得到一个新的运算结果,而原来的操作数本身是不会改变的。
3.7.7 三目运算符
三目运算符只有一个:?:,三目运算符的语法格式如下:
(exoression) ? if-true-statement : if-false-statement
规则:先对逻辑表达式expression求值,如果逻辑表达式返回true,则返回第二个操作数的值,如果逻辑表达式返回false,则返回第三个操作数的值。
代码如下:
String str = 5 > 3 ? "5大于3" : "5大于3";
System.out.println(str);//输出"5大于3"
大部分时候,三目运算符都是作为if else精简写法。因此上面代码换成if else的写法。则代码如下:
String str2 = null;
if (5 > 3)
{
str2 = "5大于3";
}
else
{
str2 = "5不大于2";
}
三目运算符可以处理更复杂的情况,如下程序所示:
int a = 11;
int b = 12;
//三目运算符支持镶嵌
System.out.println(a > b ?
"a大于b" : (a < b ? "a小于b" : "a等于b"));
上面程序是由三目运算符构成的表达式,这个表达式本身又被嵌套在三目运算符中。
3.7.8 运算符的结合性和优先级
Java大部分运算符从左向右结合结合的,只有单目运算符、赋值运算符和三目运算符例外,其中,单目运算符、赋值运算符和三目运算符是从右向左结合的,也就是从右向左运算。
运算符优先级:
分析下int a = 3;int b = a + 2 * 2语句的执行过程。
程序先执行2*a得到6,再执行a + 6得到9
int b = (a +2 ) * 2,先执行a + 2得到结果5,再执行5 * 2,得到15。
表中还提到两个类型的相关的运算符instanceof和(type),这两个运算符与类、继承有关,此处不作介绍。
公司面试:
int a = 5;int b = 4;int c = 4;int c = a++ - --b* ++a/b-- >>2%a--;,c的值是多少?
代码不要这么写,源代码就是一份文档,源代码的可读性比代码运行效率更重要。
提醒读者:
1.不要把一个表达式写得过于复杂,如果一个不表达式过于复杂,则把它分成几步来完成;
2不要过多地依赖运算符的优先级来控制的执行顺序,这样可读性太差,尽量使用()来控制表达式的执行顺序。
3.8 本章小结
1.定义学生、老师、教室三个类,为三个类编写文档注释,并使用javados工具来生成API文档。
2.使用8种基本数据类型声明多个变量,并使用不同方式为8种基本类型的变量赋值,熟悉每种数据类型的赋值规则和表达式方式。
3.在数值型的变量之间进行类型转换,包括低位向高位的自动转换、高位向低位的强制转换。
4.使用数学运算符、逻辑运算符编写40个表达式,先自行计算各表达式的值,然后通过程序输出这些表达式的值进行对比,看看能否做到一切尽在掌握。