二、数据类型和运算符
Java是一门强类型语言,而强类型语言可以在编译过程中发现源代码的错误,从而保证代码的健壮性。
强类型语言含义:
- 所有变量必须先声明,再使用;
- 指定类型的变量只能接受类型与之匹配的值。
Java提供的基本类型大致可分为两种:数值类型和布尔类型,所有数值类型间可进行类型转换,类型转换包括自动类型转换和强制类型转换。
2.1数据类型分类
Java语言支持的类型分为两种:基本类型和引用类型。
- 基本类型指的就是Java语言中八种数据基本类型;
- 引用类型包括类、接口和数组类型、还有特殊的null类型,null类型可以转换为任何引用类型。
- 实际上,引用类型变量就是一个指针,只是Java中不再使用指针这个说法。
2.2基本数据类型
2.2.1整型
- byte:一个 byte 类型整数在内存中占8位,表数范围:-128~127——128,2的七次方
- short:一个 short 类型整数在内存中占16位,表数范围:-32768~32767——32768,2的十五次方
- int:一个 int 类型整数在内存中占32位,表数范围:-2147473648~2147473647——2147473648,2的三十一次方
- long:一个 byte 类型整数在内存中占64位,表数范围:-2的六十三次方~2的六十三次方-1
int类型是最常用的类型,通常情况下直接给出一个整数值默认为int类型。以下两种类型必须指出:
- 如果直接将一个较小的整数值(在byte、short表数范围内),赋给byte或short变量,则系统会按照byte或short变量;
- 如果使用一个巨大的整数值(超过int表数范围),Java不会自动将其当做long类型处理,必须在这个整数值后增加“l”或“L”作为后缀,一般为了好区分采用“L”作为后缀。
public class dataType {
public static void main(String[] args) {
//系统直接将56当成byte类型处理
byte a = 56;
//需在末尾加上L,否则会报错——'Integer number too large'
long b = 9999999999999L;
System.out.print(a+"\t"+b);
}
}
/*res:56 9999999999999
Java 中整数值4中表示方式:十进制、二进制、八进制、十六进制以下是其代码展示。
public static void main(String[] args) {
//以0开头的整数值是八进制整数
int a = 013;
//以0x或0X开头的整数值是十六进制
int b = 0x13;
int c = 0XaF;
System.out.print(a+"\t"+b+"\t"+c);
}
/*res:11 19 175
public static void main(String[] args) {
//二进制整数以0b或者0B开头
int a = 0b101;
int b = 0B101;
//int型是32位,最高位是符号位,最高位为1时,表明是一个负数,而负数在计算机中是以补码形式存 在,需要转换成原码
int c = 0B1000_0000_0000_0000_0000_0000_0000_0011;
System.out.print(a+"\t"+b+"\t"+c);
}
/*res:5 5 -2147483645
二进制补码转原码的过程:
2.2.2浮点型
Java 中的浮点数有两种表示类型
- 十进制数形式:这种事简单的浮点数,例 5.12,512.0,.512,浮点数必须包含小数点,否则会被当成 int 类型进行处理。
- 科学计数法形式:例如5.12e2(即5.12*10^2),或者5.12E2。只有浮点类型的数值才可以使用科学计数法形式表示。
Java 提供了三个特殊的浮点数值:正无穷大、负无穷大、非数,用于表示溢出和出错
-
正无穷大,通过一个正整数除以 0 得到,可使用 Double 和 Float 类的 POSITIVE_INFINITY 表示
-
负无穷大,通过一个负数除以 0 得到,可使用 Double 和 Float 类的 NEGATIVE_INFINITY 表示
-
非数,通过 0.0 除以 0.0 或对一个负数开方得到,可使用 Double 和 Float 类中的NaN表示
-
注:所有正无穷大数值都是相等的,所有负无穷大数值都是相等的;而NaN不与任何值相等,甚至和NaN都不相等。
只有浮点数除以 0 才可得到无穷,如果一个整数除以 0,则会抛出异常——.ArithmeticException: / by zero
public static void main(String[] args) {
double a =0.0;
//看一下Double和Float中的负无穷是否相等
double c = Double.NEGATIVE_INFINITY;
float d = Float.NEGATIVE_INFINITY;
System.out.println("输出1:double、float的负无穷是不是一样的\t"+ (c == d));
System.out.println("输出2::0.0/0.0得到非数\t"+a / a);
System.out.println("输出3:NaN不等于NaN\t"+(a / a == Float.NaN));
}
/*res:
输出1:double、float的负无穷是不是一样的 true
输出2::0.0/0.0得到非数 NaN
输出3:NaN不等于NaN false
2.2.3布尔型
布尔型只有一个 boolean 类型,并且其数值只能为 true 或 false ,不能用 0 或非 0 表示,且不允许其它数据类型的转换。
public static void main(String[] args) {
boolean a1 = true;
boolean a2 = false;
System.out.println(a1);
System.out.println(a2);
//boolean 类型的值和字符串进行连接运算,则 boolean 类型的值会自动转换成字符串
String str = a1 + " " + a2;
System.out.println(str);
//输出str的数据类型
System.out.println(str.getClass());
}
/*res:
true
false
true false
class java.lang.String
2.3基本类型的类型转换
Java 提供了两种类型转换方式
当把一个表数范围小的数值或变量直接赋给另一个表数范围大的变量时,系统可以进行自动类型转换,否则就需要强制转换。
2.3.1自动类型转换
//自动类型转换
public static void main(String[] args) {
int a = 6;
//自动转换int->float
float b = a;
System.out.println(b);
byte c = 9;
//以下代码会报错,byte类型不能自动转换成char类型
//char d = c;
//自动转换byte->double
double e = c;
System.out.println(e);
}
/*res:
6.0
9.0
2.3.2强制类型转换(会造成数据丢失)
//强制转换
public static void main(String[] args) {
//强制转换int->byte
int a = 129;
byte b = (byte) a;
System.out.println(b);
//强制转换double->int
double c = 2.99;
int d =(int)c;
System.out.println(d);
}
/*res:
-127
2
强制转换中有一个容易出错的代码:
float a = 5.6;
5.6默认是 double 类型,因此修改为
float a = (float )5.6;
字符串可通过基本类型对应包装类实现转换成基本类型
String a = “45”;
使用 Integer 的方法将字符串转换成 int 类型
int b = Integer.parseInt(a);
2.3.3表达式类型的自动提升
当一个算术表达式中包含多个基本类型的值时,整个算术表达式的数据类型会发生自动提升。如下是自动提升规则。
- 所有 byte 类型、short 类型和 char 类型会被提升到 int 类型
- 整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型
//典型错误:
short sValue = 5;
//在表达式中sValue 自动提升到 int 类型,则右边表达式类型为 int
//将 int 类型赋给 short 类型变量会发生错误
sValue = sValue -2;
//自动提升的正确代码
byte b = 40;
char c ='a';
int i = 23;
double d = .314;
//右边的表达式最高的操作数是double类型的,所以result也必须是double类型的
//表达式中所有的数据都会上升为double类型
double result = b+c+i*d;
System.out.println(result);
//表达式中包含字符串则又是另一种情况
//输出字符串Hello!a7
System.out.println("Hello!"+'a'+7);
//输出字符串104Hello!
System.out.println('a'+7+"Hello!");
/*对于第一个表达式,先进行"Hello!"+'a',把'a'转换成字符串,再进行"Hello!a"+7
对于第二个表达式,先进性'a'+7加法运算,把'a'提升到int类型,变成a对于的ASCII值再进行104+"Hello!"运算
2.4直接量
直接量指在程序中通过源代码直接给出的值,例int a = 5;为变量a所分配的初始值5就是一个直接量
2.4.1直接量的类型
不是所有的数据类型都可以指定直接量,能指定直接量的通常有三种类型:基本类型、字符串类型、null类型。如下8种类型的直接量。
- int 类型的直接量
- 在程序中直接给出整型数值,可分为二进制(0B或者0b开头)、八进制(0开头)、十进制、十六进制(0x开头或者0X开头)。
- long 类型的直接量
- 在整型数值后添加“l”或者“L”就变成了long类型的直接量,例,30L、0x12L。
- float 类型的直接量
- 在浮点数后添加f或F就变成了了float类型的直接量,这个浮点数可以使标准小数形式也可是科学计数法形式,例5.34F、3.14E5f。
- double 类型的直接量
- 直接给出一个标准小数形式也可是科学计数法形式的浮点数就是 double 类型的直接量,例,5.34、3.14E5
- boolean 类型的直接量
- 这个类型的直接量只有 true 和 false。
- char 类型的直接量
- char 类型的直接量有三种形式,粉表示单引号、转义字符和 Unicode 值表示的字符,例,‘a’、‘\n’、‘\u0061’。
- String 类型的直接量
- 一个用双引号括起来的字符序列就是 String 类型的直接量。
- null 类型的直接量
- 这个类型的直接量只有 null。
注:以上8中类型的直接量中,null类型是一种特殊类型,可以赋给任何引用类型的变量,用以表示这个引用类型的变量中保存的地址为空,即还未指向有效对象。
String 类型的直接量不能赋给其他类型的变量。
boolean 类型的变量只能赋给 boolean 类型的变量。
当程序第一次使用某个字符串直接量时,Java 会使用常量池(constant pool)来缓存该字符串直接量,如果程序后面的部分需要用到该字符串直接量时,Java 会直接使用常量池中的字符串直接量。
2.5运算符
2.5.1算术运算符
用于执行基本的数学运算,下面是7个基本算术运算符:
- +:加法运算符
- +还可以作为字符串的连接运算符
- -:减法运算符
- *:乘法运算符
- /:除法运算符
- 如果除法运算符的两个操作数都是整数类型,则计算结果也是整数,就是将自然除法的结果截断取整,例19/4 结果是 4,而不是 5;如果除法运算符的两个操作数都是整数类型,则除数不能为 0,否则会引发除以零异常。
- 如果除法运算符的两个操作数至少有一个是浮点数,则计算结果也是浮点数,这个结果就是自然除法的结果,此时允许除数为 0,得到结果为正或负无穷大。
- %:求余运算符
- 求余运算的结果不一定总是整数,因为求余运算符允许浮点数间的求余运算;由于求余运算也需要进行除法运算,如果除法运算符的两个操作数都是整数类型,则除数不能为 0,否则会引发除以零异常。
- 如果求余运算符的两个操作数至少有一个是浮点数,则计算结果也是浮点数,这个结果就是自然除法的结果,此时允许除数为 0,只是求余运算的结果是非数。
- ++:自加
- 自加是单目运算符,只能操作一个操作数
- 自加运算符只能操作单个数值型的变量,不能操作常量或表达式
- ++放在操作数左边,则是先操作数加1,再把操作数放入表达式中运算
- ++放在操作数右边,则是操作数放入表达式中运算,再把操作数加1
- –:自减
- 用法与++基本一致,只是将操作数减1
2.5.2赋值运算符
赋值运算符用于为变量指定变量值,Java也使用 = 作为赋值运算符。
2.5.3比较运算符
比较运算符用于判断两个变量或常量的大小,比较运算符的结果是一个 boolean 类型(true 或 false)。
- 大于>
- 大于等于>=
- 小于<
- 小于等于<=
- 等于==
- 如果进行比较的两个操作数都是数值类型,**即使它们的数据类型不同,只要它们的值相等,也都返回 true,**例97==‘a’ , 5.0==5 都返回 true 。
- 如果两个操作数都是引用类型,那么只有当两个引用变量的类型具有父子关系时才可以比较,并且这两个引用必须指向同一个对象才会返回 true 。
- 不等于!=
- 和==的原则几乎一致
2.5.4逻辑运算符
逻辑运算符用于操作两个布尔型的变量或者常量,如下6个
- &&:与,前后两个操作数必须都为 true 才会返回 true ,否则返回 false
- &:不短路与,与&&一样,但不会短路
- ||:或,前后两个操作数有一个为 true 就会返回 true
- |:不短路或,与||一样,但不会短路
- !:非,只需要一个曹组数,如果操作数为 true 则返回 false;如果操作数为 false则返回 true 。
- ^:异或,当两个操作数不同才返回 true ,两个操作数相同返回 false。
2.5.5位运算符
- &:按位与
- 当两位同时为1才返回1
- |:按位或
- 有一位为1即可返回1
- ~:按位非
- 单目运算符,将操作数的每个为(包括符号位)全部取反
- 按位非运算符把操作数在计算机底层的二级制码按位取反。
- ^:按位异或
- 当两位相同时返回 0 ,不同返回1
- 需要将两个操作数转换成二进制进行运算
- <<:左移运算符
- 将操作数的二进制整体左移指定位数,左移后右边空出来的位以0填充
- 右移运算符>>:
- 无符号右移运算符>>>:
2.5.6三目运算符
三目运算符只有一个 : ? :
(expression) ? if-true-statement : if-false-statement
规则:先对逻辑表达式 (expression) 求值,如果逻辑表达式返回 true ,则返回第二个操作数的值,如果逻辑表达式返回 false ,则返回第三个操作数的值
三目运算符基本上都是 if else 的精简写法。
String str = 5 >3 ? "5大于3" : "5不大于3";
System.out.println(str);
/*res: "5大于3"
边空出来的位以0填充
- 右移运算符>>:
- 无符号右移运算符>>>:
2.5.6三目运算符
三目运算符只有一个 : ? :
(expression) ? if-true-statement : if-false-statement
规则:先对逻辑表达式 (expression) 求值,如果逻辑表达式返回 true ,则返回第二个操作数的值,如果逻辑表达式返回 false ,则返回第三个操作数的值
三目运算符基本上都是 if else 的精简写法。
String str = 5 >3 ? "5大于3" : "5不大于3";
System.out.println(str);
/*res: "5大于3"