Java基础原理笔记(二)

数据类型和运算符

本章主要内容

  • 基本类型的转换
  • 直接量
  • 运算符

基本类型的类型转换


Java语言所提供的7中数值类型之间可以相互转换,有两种转换方式: 自动类型转换、强制类型转换

自动类型转换


  当把一个表数范围小的数值或变量直接赋给另一个表数范围大的变量时,西东可以自动类型转换,反之,则需要强制转换。



如:

1
2
3
4
5
6
int a = 6;
float b = a;//此时b的值为6.0
byte c = 7;
//下面代码将出错,byte类型不能自动转换成char类型
char d = b;

  特别地,当任何基本类型的值和字符串值进行连接运算时,基本类型的值会自动转换成字符串类型的值,如:

1
2
3
4
5
String TransToStr = 2.5f + "";
String Str1 = 3 + 4 + "Hello!";//Str1的值为 "7Hello!"
String Str2 = "Hello!" + 3 + 4;//Str2的值为 "Hello34"

强制类型转换


  强制类型转换的格式为(targetType)value,需要注意的是,若转换的值超过了目标类型的表数范围,将会引起溢出,造成数据丢失,如:

1
2
3
4
5
6
7
8
9
10
11
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);

原理:

  32位int类型的233强制转换为8位的byte类型,需要截断前面的24位,截断后最左一位表示符号位,而负数在计算机中以补码形式存在,则11101001转成原码还需减一取反,得到10010111,即为-23。

另外,有一个容易出错的地方,如下:

1
2
3
4
//5.6默认是double型的,直接赋给一个float型的变量会出错
float a = 5.6;
//应为
float a = (float)5.6;

  一般的,字符串不能直接转换为基本类型,但是可以通过基本类型对应的包装类实现字符串转基本类型,如:

1
2
String a = "25";
int iValue = Integer.parseInt(a);

Java中八种基本类型对应的包装类如下:

基本类型 包装类
boolean Boolean
byte Byte
short Short
int Integer
long Long
char charcter
float Float
double Double

8个包装类均提供parseXxx(String str)静态方法用于将字符串转成对应的基本类型。

直接量


能指定直接量的通常只有三种类型: 基本类型、字符类型、null型

  • 基本类型: int、long、float、double、Boolean、char
  • 字符类型: String
  • null类型: 只有一个值,即为 null

需要注意的是:

  • String类型的直接量不能赋给其他类型的变量
  • null类型的直接量可以直接赋给任何引用类型的变量
  • Boolean类型的直接量只能赋给Boolean类型的变量

   关于字符串直接量有一点需要指出,当程序第一次使用某个字符串直接量时,Java会使用常量池来缓存该字符串直接量,若后续要使用该字符串直接量,Java会直接使用常量池中的该直接量。

   常量池指的是在编译期被确定,并被保存在已编译的.class魏建忠的一些数据。它包括关于 类、方法、接口中的常量,也包括 字符串常量

如下所示:

1
2
3
4
5
String s0 = "hello";
String s1 = "hello";
String s2 = "he" + "llo";
System.out.println( s0 == s1);
System.out.println( s0 == s2);

运行结果为:

1
2
true
true

  因为Java会确保每个字符串常量只有一个,不会产生多个副本。例子中的s0和s1中的”hello”都是字符串常量,他们在编译期就被确定了,所以s0==s1返回true;s2同样在编译器就被解析为一个字符串常量,所以s2也是常量池中”hello”的引用。

运算符


Java中的算术运算符可分为如下几种:

  • 算术运算符
  • 赋值运算符
  • 比较运算符
  • 逻辑运算符
  • 位运算符
  • 类型相关运算符

算术运算符


  • +:加法运算符
  • -:减法运算符
  • *:乘法运算符
  • /:除法运算符
  • %:求余运算符
  • ++:自加
  • –:自减

注意:自加和自减只能用于 操作变量,不能用于操作数值直接量、常量或表达式。如:5++、6–都是错误的。

Java没有提供更复杂的运算符,如果要完成乘方、开方等运算,需借助 java.lang.Math类的工具方法完成。

赋值运算符


用于为变量指定变量值,如:

1
2
3
String str = "Java";
String str2 = str;

把变量当成一个盛装数据的容器,赋值运算就相当于“装入”的过程。赋值运算符是 从右向左执行计算的,程序先计算得到 =右边的值,再把该值装入左边的变量中。因此, =左边只能是变量。

位运算符


  • &:按位与。当两位同时为1时才返回1。
  • |:按位或。只要有一位为1即可返回1。
  • ~:按位非。单目运算符,将操作数的每个位(包括符号位)全部取反。
  • ^ :按位异或。当两位相同时返回0,不同时返回1。
  • <<:左移运算符。
  • >>:右移运算符。
  • >>>:无符号右移运算符。

实例代码:

1
2
System.out.println(5 & 9);//输出1
System.out.println(5 | 9);//输出13

原理如下:

按位异或和按位取反:

1
2
System.out.println(~-5);//输出4
System.out.println(5 ^ 9);//输出12

按位取反原理如下:

按位异或原理如下:

左移运算符是将操作数的二进制码整体左移指定位数,左移后右边空出来的用0补充,如下:

1
2
System.out.println(5 << 2);//输出20
System.out.println(-5 << 2);//输出-20

左移原理如下:

  Java的右移运算符有两个 >>、>>>,对于 >>运算符而言,把第一个操作数的二进制码右移指定位数后,左边空出来的为以原来的符号位填充,即如果是一个整数则以0补充,如果第一个操作数是负数则补1。 >>>把第一个操作数右移指定位数后总以0补充。

1
2
System.out.println(5 >> 2);//输出-2
System.out.println(-5 >>> 2);//输出1073741822

-5>>2的运算原理

-5>>>2的运算原理:

注意: 进行移位运算不会改变操作数本身,只是得到一个新的运算结果,原来的操作数本身不会改变

比较运算符


比较运算符用于判断两个变量或常量的大小,其结果是一个布尔值(true或false),如下:

  • >:大于,(只支持数值类型)
  • >=:大于等于,(只支持数值类型)
  • <:小于,(只支持数值类型)
  • <=:小于等于,(只支持数值类型)
  • ==:等于, 如果两边都是数值类型,即使它们数据类型不同,只要值相等也会返回true。如果两边是引用类型, 只有当两个引用变量具有父子关系时才可比较,同时,这两个变量必须指向 同一个对象才会返回true。
  • !=:不等于,(同==)

逻辑运算符


用于操作两个布尔类型的变量或常量,如下:

  • &&:与,两边为true时返回true
  • &: 不短路与,(同&&)但不会短路
  • ||:或,两边有一个为true返回true
  • |: 不短路或
  • !: 非,只有一个操作数,为true返回false
  • ^ :异或,两边结果不同时返回true,相同返回false

三目运算符


三目运算符只有一个:(?:)

格式为:(expression) ? if-true-statement : if-false-statment;

运算符结合性和优先级


单目运算符、赋值运算符、三目运算符从右向左运算的。

下表为运算符优先级表,上一行优先于下一行。