点击进入我的博客
3.1更简单的打印语句
System.out.println("imbug");
通过编写一个小类库,并通过import static
该方法来实现简化打印(基本没啥用)。
public class Print {
public static void println(String str) {
System.out.println(str);
}
}
import static s1.Print.println;
public class Test {
public static void main(String[] args) {
println("imbug");
}
}
3.2 使用Java操作符
- 操作符接受一个或多个参数,并生成一个新值
- 有些操作符可能会改变操作数本身的值
- 几乎所有的操作符都只能操作基本类型;
=
、==
、!=
能操作所有的对象;String
类支持+
、+=
操作符
3.3 优先级
运算符优先级表.png- 操作符是有优先级的。
- 个人认为:死记硬背操作符的优先级除了应付大学考试和智障笔试题之外,并无卵用~只要理解了运算符的原理再来看优先级有易如反掌了~
- 如果有人写这样的代码请打死他:
System.out.println(a<<=b+=c>>=5);
-
System.out.println()
中的+
运算符可能会表示字符串拼接,还有可能进行字符串转换。
3.4 赋值
赋值=
的意思是取右边的值把它复制给左边。
左边的值必须是明确的、已命名的变量。
右值可以是任何常熟、变量或者表达式(只要它能生成一个值)。
基本类型传递的是值,对象类型传递的是引用。
3.5 算术操作符
+
、-
、*
、/
、%
/
:整数的除法会直接干掉小数位而不是四舍五入
+
、-
:还可以用作正负号
3.6 自动递增和递减
++
、--
前缀式:++a
先执行运算再生成值,即++a == a is true
后缀式:a++
先生成值再执行运算,即a == a++ is true
3.7 关系运算符
>
、<
、>=
、<=
、!=
、==
- 关系操作符生成的是一个
boolean
的结果。 -
大于、小于、大于等于、小于等于不适用于
boolean
类型 - 等于和不等于适应于全部基本数据类型及对象类型
- 等于和不等于作用于对象类型时比较的是引用(我更倾向于用C++中的地址来理解这个概念)
- 对基本数据类型的包装类、
String
、BigInteger
、BigDecimal
的equals
方法比较的是值 - 如果你自己的
class
没有重写equals
方法,那么equals
方法使用的是Object
的equals
方法,即比较引用。
数值的包装类
Integer x1 = new Integer(10);
Integer x2 = new Integer(10);
System.out.println("x1 == x2: " + (x1 == x2));
System.out.println("x1.equals(x2): " + x1.equals(x2));
// x1 == x2: false
// x1.equals(x2): true
Integer y1 = 10;
Integer y2 = 10;
System.out.println("y1 == y2: " + (y1 == y2));
System.out.println("y1.equals(y2): " + y1.equals(y2));
// y1 == y2: true
// y1.equals(y2): true
Integer z1 = 1000;
Integer z2 = 1000;
System.out.println("z1 == z2: " + (z1 == z2));
System.out.println("z1.equals(z2): " + z1.equals(z2));
//z1 == z2: false
//z1.equals(z2): true
上述代码的.class文件反编译后的代码
Integer x1 = new Integer(10);
Integer x2 = new Integer(10);
System.out.println((new StringBuilder()).append("x1 == x2: ").append(x1 == x2).toString());
System.out.println((new StringBuilder()).append("x1.equals(x2): ").append(x1.equals(x2)).toString());
Integer y1 = Integer.valueOf(10);
Integer y2 = Integer.valueOf(10);
System.out.println((new StringBuilder()).append("y1 == y2: ").append(y1 == y2).toString());
System.out.println((new StringBuilder()).append("y1.equals(y2): ").append(y1.equals(y2)).toString());
Integer z1 = Integer.valueOf(1000);
Integer z2 = Integer.valueOf(1000);
System.out.println((new StringBuilder()).append("z1 == z2: ").append(z1 == z2).toString());
System.out.println((new StringBuilder()).append("z1.equals(z2): ").append(z1.equals(z2)).toString());
通过new Integer新建对象
-
new Integer
每次都会新建对象,所以==
的结果为false
自动装箱与拆箱
- 自动装箱:用赋值运算符
=
把一个数值或基本类型变量赋值给一个包装类变量(Integer y1 = 10
)。装箱调用的是Integer.valueOf(10)
方法。 - 自动拆箱:用赋值运算符
=
把一个包装类赋值给一个基本类型变量(int y3 = y1
),或者是在包装类进行数值运算时。拆箱调用的是Integer#intValue()
方法。 -
装箱方法的坑(笔面试题):下面是
Integer.valueOf(int i)
的源代码。可以看出当装箱的数值在-128到127之间是,返回的对象是IntegerCache
中提前new
出来的对象,所以y1 == y2
的结果是true
;当装箱的数值超出该范围,则返回的是new
出来的对象,所以z1 == z2
的结果为false
。 - 其他的装箱方法:
Byte
、Short
、Integer
、Long
的范围都是[-128,127];Character
的范围是[0,127];Float
、Double
全部是new
出来的新对象;Boolean
都是预定义好的true
和false
。有趣的是,这些代码作者是一样的,但写法各不相同。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
备注内容:可以从https://varaneckas.com/jad/下载Java反编译工具JAD;或者可用从http://jd.benow.ca/下载反编译工具JD-GUI
3.8 逻辑操作符
&&
、||
、!
- 逻辑运算符只能根据两个布尔值参数的逻辑关系,生成一个布尔值。
布尔值短路
- 即一旦能够明确无误地确定整个表达式的值,就不再计算表达式剩余的部分了
-
&&
:遇到第一个false
则不执行后边的代码 -
||
:遇到第一个true
则不执行后边的代码
public static boolean func1() {
System.out.println("func1");
return true;
}
public static boolean func2() {
System.out.println("func2");
return false;
}
public static boolean func3() {
System.out.println("func3");
return true;
}
if(func1() && func2() && func3()); // 不执行func3中的内容
if(func1() || func2() || func3()); // 不执行func2和fanc3中的内容
- 面试题:如何不使用条件语句控制流程。
// 不使用if来控制该流程
if(func1()) {
func2();
}
// 方法
boolean var = func1() && func2();
3.9 直接常量
- 前缀
0x
、0X
:表示16进制数字 - 前缀
0
:表示8进制数字 - 后缀
l
、L
:表示long
类型。在写代码的时候,由于小写的l
容易和数字1
混淆,所以各种规范中都不建议(禁止)使用小写的l
表示长整数。最简单就全部用大写就好了! - 后缀
f
、F
:表示float
类型。 - 后缀
d
、D
:表示double
类型。 -
e
、E
:指数计数,表示10的幂
3.10 按位操作符
&
、|
、^
、~
&=
、|=
、^=
-
boolean
:可以把boolean
值看成单比特值对待,&
、|
、^
的操作相同,但是~
不能用于布尔值。
3.11 移位操作符
<<
:高位(包括符号位)舍弃,低位补零。
>>
:有符号右移运算,若高位是1,则高位补1;若高位是0,则高位补0。
>>>
:无符号右移,最高位补0。
- 移位操作符只能用来处理整数类型。
-
char
、byte
、short
进行移位操作时,会先被转成int
类型,并且结果也是int
类型 -
long
类型移位还是long
<<=
、>>=
、>>>=
- 注意:在对
byte
、short
进行>>>=
无符号右移等于运算时,整个流程是先向上转化成int
——进行移位运算——向下转化(强制截取)成byte
或short
,所以会导致移位后对结果不正确。
short s = -1;
System.out.println(Integer.toBinaryString(s));
// 11111111111111111111111111111111
System.out.println(Integer.toBinaryString(s >>> 10));
// 1111111111111111111111
s >>>= 10;
System.out.println(Integer.toBinaryString(s));
// 11111111111111111111111111111111
3.12 三目运算符
boolean-exp ? val1 : val2
3.13 字符串运算符
+
、+=
3.14 操作符常犯错误
- Java中
if
、while
语句必须使用boolean
值,所以不会出现==
被写成=
的问题;除非是两个boolean
值 - Java编译器也能够防止逻辑与或(
&&
、||
)和按位与或(&
、|
)的问题,除非是两个boolean
值
3.15 类型转换操作符
- 既可以对数值进行转换,也可以对数值变量进行转化
- 向下转化必须要强制转化,否则编译失败(移位等于、算数等于时不会)
- 向上转化不必显示进行转化
- 除布尔值之外,其他类型都可以互相转化
- 浮点数转成整数值的时候直接截尾,不会进行四舍五入
- 表达式的最大数据类型决定了表达式的数据类型
3.16 没有sizeof
Java所有基本数据类型的size是确定的,所以不需要sizeof
3.17 操作符小结
-
char
、byte
、short
在使用算术操作符和移位操作符的时候都会被转成int
,必须显示类型转换回原来的类型。以下注释掉的都是编译错误的。
short s1 = 10;
short s2 = 10;
// short s3 = s1 + s2;
// short s4 = s1 >> 1;
-
char
、byte
、short
在进行复合赋值运算(移位等于、算数等于)时不需要强制转化。 -
int
类型要小心结果溢出 - 除
boolean
外,任何基本类型都可以通过类型转换变成其他基本类型 - 必须留意向下转化的的结果,因为可能存在丢失信息的可能性
网友评论