Java学习笔记
第三章——数据类型与运算符
数据类型分类
- Java语言是强类型(strongly typed)语言,其包含两个含义:1. 所有变量必须先声明后使用;2. 指定类型的变量只能接受类型与之匹配的值。这意味着每个变量和每个表达式都有一个在编译时就已确定的类型。类型限制了一个变量能被赋的值,限制了一个表达式可以产生的值,限制了在这些值上可以进行的操作,并确定了这些操作的含义。
- 强类型语言可以在编译时进行更严格的语法检查,从而减少编程错误。
- 声明变量的语法非常简单,只要制定变量的类型和变量名即可,如:
type varName [ = 初始值];
- Java语言支持的类型包含两种,基本类型(Primitive Type)和引用类型(Reference Type)
- 基本类型包括了boolean类型和数值类型。数值类型有整数类型和浮点类型。整数类型包括byte(1)、short(2)、int(4)、long(8)、char(2),浮点类型包括float(4)、double(8)。
- 引用类型包括类、接口和数组类型,还有一种特殊的null类型。因为null类型没有名称,所以不可能声明一个null类型的变量或者转换到null类型。空引用(null)是null类型变量唯一的值。空引用可以转换为任何引用类型。
整型
- int是最常用的整数类型,因此在通常情况下,直接给出一个整数默认就是int类型。除此之外有如下两种情形必须指出
- 如果直接将一个较小的整数值(在byte或short类型的表数范围内)赋给一个byte或short变量,系统会自动把这个整数值当成byte或short类型来处理。
- 如果使用一个较大的整数值(超出了int的表数范围)时,Java不会自动把这个整数当做long类型处理。如果希望一个系统把一个整数值当成long类型来处理,应在这个整数值后面增加l或者L作为后缀。通常推荐使用L。因为英文字母l很容易和数字1混淆。
- Java整数值有四种表达方式,十进制、二进制、八进制和十六进制。其中二进制的整数以0b或0B开头,八进制的整数以0开头,十六进制的整数以0x或0X开头。
int binval = 0b10000000000000000000000000000011;
System.out.println(binval);
- 运行结果是
-2147483645
。 - 上面这个数的运行原理是:输入的是补码,补码减一得到反码,符号位不变,其他位取反得到原码,该原码的值就是-2147483645。
//定义一个八位的二进制整数,该数值默认占32位,因此它是一个正数
//只是强制类型转换转换成byte时产生了溢出,最终导致binval2变成了-23
int binval2= (byte)0b11101001;
long binval3= 0B10000000000000000000000000000011L;
System.out.println(binval2);//输出-23
System.out.println(binval3);//输出2147483651
- 上述程序中粗体字代码与前面程序片段的粗体字代码基本相同,只是在定义二进制增速是添加了一个L后缀,这就表明把它当成long类型来处理,因此该整数实际占64位。此时第32位不再是符号位,因此他依然是一个整数。
字符型
- 字符型通常用于表示单个字符,字符型值必须使用单引号
'
括起来。Java语言使用16位的Unicode字符集作为编码方式,而Unicode被设计成支持世界上所有书面语言的字符,包括中文字符,因此Java语言支持各种语言的字符。 - 字符整型有三种表述方式
- 直接用过单个字符来指定字符型值,例如’A’,‘9’,'0’等。
- 通过转义字符表示特殊字符型值,例如’\n’,’\t’等。
- 直接使用Unicode值来表示字符型值,格式是
\uXXXX
,其中XXXX代表一个十六进制的整数。Java语言中常用的转义字符如下所示。
转义字符 | 说明 | Unicode表示方式 |
---|---|---|
\b | 退格符 | \u0008 |
\n | 换行符 | \u000a |
\r | 回车符 | \u000d |
\t | 制表符 | \u0009 |
\" | 双引号 | \u0022 |
\’ | 单引号 | \u0027 |
\\ | 反斜线 | \u005c |
- 字符型值也可以采用十六进制编码的方式来表示,范围是
'\u0000'~'\u00FF'
,一共可以表示65536个字符,,其中前256个'\u0000'~'\u00FF'
与ASCII字符完全重合。 - 由于计算机底层保存字符时,实际上是保存该字符对应的编号,因此char类型的值也可以直接作为整型值来使用,它相当于一个16位的无符号整数,表数范围是0~65535。
public class chartest {
public static void main (String[] args)
{
char ch = '\u9999';
System.out.println(ch);
char zhong = '张';
System.out.println(zhong);
int a = zhong;
System.out.println(a);
char c = 97;
System.out.println(c);
}
}
- Java没有提供表示字符串的基本数据类型,而是通过String类来表示字符串,由于字符串由多个字符组成,因此字符串要使用双引号括起来,如下代码。
String a = "123321";
- 应值得注意的是,Java语言中的单引号,双引号和反斜线都有特殊的用途,如果一个字符串中包含了这些特殊用途,则应使用转义字符的表示形式。例如:在Java程序中表示一个绝对路径时,要以双反斜线表示真正的反斜线。
浮点型
- Java的浮点型有两种,float和double。Java的浮点类型有固定的表数范围和字段长度,字段长度和表数范围与机器无关。对于float型数值,第一位是符号位,接下来八位表示指数,在接下来的23位表示尾数。对于double类型的数值,第一位也是符号位,接下来的11位表示指数,再接下来的52位表示尾数。
- 一个double类型的数值占8字节、64位,一个float类型的数值占4字节,32位。
- Java语言的浮点数有两种表示形式。
- 十进制数形式:这种形式就是简单的浮点数,例如5.12、512.0、.512浮点数必须包含一个小数点,否则会被当成int类型处理。
- 科学计数法形式:例如5.12e2,5.12E2。
- 必须指出的是,只有浮点类型的数据才可以使用科学计数法来表示。例如:51200是一个int类型的数值,但512E2是浮点类型的值。
- Java默认的浮点数值是double类型,如果希望把一个浮点类型值当成float类型的值则应该在其后面紧跟f或F。当然也可以在一个浮点数后面添加d或D后缀,强制指定是double类型,但通常没必要。
- Java还提供了三个特殊的浮点数值:正无穷大、负无穷大和非数,用于表示溢出和出错。例如,用一个正数除以0将得到正无穷大,使用一个负数除以0将得到负无穷大,0.0除以0.0或对一个负数开方将得到一个非数。正无穷大通过Double或Float类的POSITIVE_INFINITY表示;负无穷大通常用Double或Float类的NEGATIVE_INFINITY表示,非数通过Double或Float类的NaN表示。
- 必须指出的是,所有的正无穷大数值都是相等的,所有的负无穷大都是相等的;而NaN不和任何值相等,甚至和NaN都不相等。
只有浮点数除以0才可以得到正无穷大或负无穷大,因为Java语言会自动把和浮点数运算的0(整数)当成0.0(浮点数)处理。如果一个整数值除以0,则会抛出一个异常:ArithmeticException:/by zero(除以0异常)
- 下面程序示范了上面介绍的关于浮点数的各个知识点:
public class floattest {
public static void main(String[] args)
{
float af = 5.2345556F;
// 下面将看到af的值已经发生了改变
System.out.println(af);
double a = 0.0;
double c = Double.NEGATIVE_INFINITY;
float d = Float.NEGATIVE_INFINITY;
// 看到float和double的负无穷是相等的
System.out.println(c==d);
//0.0除以0.0将出现非数
System.out.println(a/a);
//两个非数是不相等的
System.out.println(a/a == Float.NaN);
//所有正无穷大是相等的
System.out.println(6.0/0 == 555.0/0);
//负数除以0.0得到负无穷大
System.out.println(-8/a);
//下面代码将抛出除以0的异常
//System.out.println(0/0);
}
}
数值中使用下画线分隔
- 正如前面程序中看到的,当程序中用到的数字位数特别多时,可以在数值中使用下划线,无论是整型数值,还是浮点型数值,都可以自由地使用下划线。通过使用下划线分隔,可以更直观的分辨数值中到底包含多少位。如下面程序所示:
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);
}
}
布尔型
- 布尔型只有一个boolean类型,用于表示逻辑上的“真”或“假”。在Java语言中,boolean类型的数值只能是true或false,不能用0或者非0来代表。其他基本数据类型的值也不能转换成boolean类型。
- 字符串“true”和“false”不会直接转成boolean类型,但如果使用一个boolean类型的值和字符串进行连接运算,则boolean类型的值将会自动转换为字符串,如下代码:
// 使用boolean类型的值和字符串进行连接运算,boolean类型的值将会自动转换成字符串
String str = true + "";
System.out.println(str);
- 将输出true
- boolean类型的值或变量主要用作旗标来进行流程控制,Java语言中使用的boolean类型的变量或值控制的流程主要有有如下几种:
- if条件控制语句
- while循环控制语句
- do while循环控制语句
- for循环控制语句
- 除此之外,boolean类型的变量和值还可以再三目运算符(?:)中使用。
基本类型的类型转换
- 在Java程序中,不同的基本类型的值经常需要相互转换。Java语言所提供的7种数值类型之间可以相互进行转换,有两种类型转换方式,自动类型转换和强制类型转换。
自动类型转换
- Java所有的数值型变量都可以相互进行转换,如果系统支持把某种基本类型的值直接赋给另一种基本类型的变量,着这种方式被称为自动类型转换。当把一个表数范围小的数值或变量直接赋给另一个表数范围大的变量时,系统将可以进行自动类型转换;否则就需要强制类型转换。
- byte可以转换为short,short和char都可以转换为int,int->long->float->double
public class AutoConversion {
public static void main(String[] args){
int a = 6;
//int类型可以自动转为float类型
float f = a;
System.out.println(f);//输出6.0
//定义一个byte类型的整数变量
byte b = 9;
//下面代码将出错,因为byte类型不能自动类型转换为char类型
// char c = b;
//byte类型变量可以自动类型转换为double类型变量
double d = b;
System.out.println(d);//输出9.0
}
}
- 不仅如此,当把任何基本类型的值和字符串值进行连接运算时,基本类型的值将自动类型转换为字符串类型,虽然字符串类型不是基本类型,而是引用类型。因此,如果希望把基本类型的值转换为对应的字符串时,可以把基本类型的值和一个空字符串进行连接。
+不仅可以作为加法运算符使用,还可以作为字符串连接运算符使用。
public class PrimitiveAndString {
public static void main (String[] args){
//一个基本类型的值和字符串进行连接运算时,基本类型的值自动转换为字符串
String str1 = 3.5f + "";
//输出3.5
System.out.println(str1);
//下面语句输出7Hello!
System.out.println(3+4+"Hello!");
//下面语句输出Hello!34
System.out.println("Hello!"+3+4);
}
}
强制类型转换
- 如果希望以相反的方向进行类型转换,则必须进行强制类型转换,强制类型转换的格式是:
(targetType)value
,强制类型转换的运算符是圆括号()。当进行强制类型转换时,类似于把一个大瓶子里的水倒入小瓶子,这样如果大瓶子里的水很多,将会引起溢出,从而造成数据丢失。这种转换也被称为“缩小转换”(Narrow Conversion)。 - 下面程序示范了强制类型转换
public class NarrowConversion {
public static void main(String[] args){
int iValue = 233;
//强制把一个int类型的值转换为byte类型的值
byte bValue = (byte)iValue;
//将输出-23
System.out.println(bValue);
double dValue = 3.98;
//强制把一个double类型的值转换为int类型的值
int tol = (int)dValue;
//将输出3
System.out.println(tol);
}
}
- 下面的程序用于生成一个6位的随机字符串
public class RandomStr {
public static void main(String[] args){
//定义一个空字符串
String result = "";
//进行六次循环
for (int i = 0 ; i < 6 ; i ++)
{
//生成一个97~122之间的int类型整数
int intVal = (int)(Math.random() * 26 + 97);
//将intValue强制转换为char类型后连接到result后面
result = result + (char)intVal;
}
System.out.println(result);
}
}
- Java为8种基本类型都提供了对应的包装类:boolean对应Boolean、byte对应Byte、short对应Short、int对应Integer、long对应Long、char对应Character、float对应Float、double对应Double,八个类都提供了一个parseXxx(String str)静态方法用于将字符串转换成基本类型。
表达式类型的自动提升
- 当一个算术表达式中包含多个基本类型的值时,整个算术表达式的数据类型将发生自动提升。Java定义了如下的自动提升规则。
- 所有的byte类型、short类型、char类型都将被提升到int类型
- 整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型。
- 下面代码是表达式类型自动提升的正确示例代码
byte b = 40;
char c = 'a';
int i = 23;
double d = .314;
double result = b+c+i*d;
System.out.println(result);//将输出144.222
- 表达式的类型将严格保持和表达式中最高等级操作数相同的类型。下面代码中两个int类型整数进行除法运算,即使无法除尽,也将得到一个int类型的结果
int val = 3;
//右边表达式中两个操作数都是int类型,故左边表达式类型应该为int
//虽然23/3不能除尽,但依然能得到一个int类型整数
int intResult = 23/val;
System.out.println(intResult);//输出7
直接量
- 直接量是指在程序中通过源代码直接给出的值,例如在
int a = 5;
这行代码中,为变量a所分配的初始值就是一个直接量。
直接量的类型
- 并不是所有的数据类型都可以指定直接量,能指定直接量的通常只有三种类型:基本类型、字符串类型和null类型。具体而言,Java支持如下八种类型直接量:
- int类型的直接量
- long类型的直接量(在整型数值后添加l或L)
- float类型的直接量(在一个浮点数后添加f或F)
- double类型的直接量
- boolean类型的直接量,只有true和false
- char类型的直接量
- String类型的直接量
- null类型的直接量,只有null
运算符
- 运算符是一种特殊的符号,用以表示数据的运算、赋值、比较等。Java语言使用运算符将一个或多个操作数连缀成执行性语句,用以实现特定功能:
- 算术运算符:
+ - * / %
,要注意除法运算符如果两个操作数都是整数则计算结果也是整数,注意是截断取整。还有自加自减运算符++ --
该运算符如果在操作数的左边,则先加一,再放入表达式运算;如果放在右边,则先在表达式中运算再加一。 - 赋值运算符:
=
。与C语言不同的是赋值运算符可以将一个变量的值赋给另一个变量。如String str2 = str;
这是没有问题的 - 位运算符:一共有如下七个
- &:按位与,两位同时为1才为1。
- |:按位或,有一位为1就为1。
- ~:按位非,单目运算符,将操作数的每位全部取反
- ^:按位异或,两位相同返回0,不相同返回1
- <<:左移运算符
- >>:右移运算符
- >>>:无符号右移运算符,区别就是右移运算符的符号与原操作数相同。
- 扩展后的赋值运算符
- 比较运算符:结果一定是一个布尔值(true或false),包括了
>= <= < > == !=
- 逻辑运算符
- &&:与
- &:不短路与
- ||:或
- |:不短路或
- !:非
- ^:异或
- 算术运算符:
短路与否的区别是,如果使用了短路的运算符,例如
&&
,若前半部分的布尔值已为0,则后半部分不进行执行,而不短路运算符仍然执行