Think in java 读书笔记
pikzas
2019.03.03
第3章-操作符
知识点
算数运算符
"+" 在处理字符串时候的特殊处理
常规的算数运算符有加减乘除取余赋值等(+-*/%=),这些操作符对于所有的基本数据类型都是可以直接使用的,但是对于对象还能有判定内存地址是否相等,是否不等,赋值(==,!=,=)操作符可以用。对于String这个特殊的引用对象类型,还可以使用拼接符(+),这是Java提供的一个语法糖,反编译字节码后,会发现”+“号会被StringBuffer的append方法代替。
"=" 在对象赋值过程中的特殊处理(别名现象)
发生这种现象是因为Java是值传递的,
对于基本数据类型,一个变量其实是指向堆栈中特定的值,在进行a=b这种赋值操作的时候,实际上是将b的值拷贝给了a变量。
对于引用数据类型,m=n这个操作,是将变量n所指向的对象的地址赋值给了m,这时候如果对m,n所指向的是同一个内存地址的同一个对象,无论是通过m还是n对对象有任何改变,所有指向该对象的引用(即变量)都会将这次的改变体现出来。
class Tank{
int level;
}
public class Demo{
Tank t1 = new Tank();
Tank t2 = new Tank();
t1.level = 12;
t2.level = 34;
print("--1--"+t1.level+"---"+t2.level);
t1 = t2; // t1 变量的指针指向了t2 的所指向的那个对象
t1.level = 56; // 通过t1 对对象作出改变
print("--2--"+t1.level+"---"+t2.level);
}
// 打印结果
// --1--12---34
// --2--56---56
别名现象也会出现在方法调用上
public class Test {
public static void f(int x) {
x = 12;
}
public static void f2(String args) {
args = "1234";
}
public static void f3(Bean bean) {
bean.x = 123;
}
public static void main(String[] args) {
int y = 44;
f(y);
System.out.println(y);
String str = "xxx";
f2(str);
System.out.println(str);
Bean bean = new Bean();
bean.x = 111;
f3(bean);
System.out.println(bean.x);
}
}
class Bean{
public int x;
}
// 输出结果为
44
xxx
123 //为什么这个值发生了变化,而上面两个没有呢
除运算(/)在java中返回的值只有整数部分,不会四舍五入。
自动递增和递减
- 对于前缀递增和递减(++a或--a)会先执行运算,在生成值
- 对于后缀递增和递减(a++或a—-)会先生成值,在执行运算
class Demo{
public static void main(String[] args){
int i = 1;
System.out.println("i: " + i); //1
System.out.println("++i:" + ++i); //2
System.out.println("i++:" + i++); //2
System.out.println("i: " + i); //3
System.out.println("--i:" + --i); //2
System.out.println("i--:" + i--); //1
}
}
关系操作符
关系操作符返回的结果是布尔值 true 或者 false
所有的运算符包含 大于(>)、小于(<)、大于或等于(>=)、小于或等于(<=)、等于(==)、不等于(!=)。以上运算符可以作用在除布尔值以外的所有对象上。
- 布尔值只有true 或者 false 不存在谁比谁大。
- 以上运算符如果作用在引用数据类型的时候,比较的是其地址,如果需要比较对象的"值",则需要对该对象重载equals方法。默认的基础数据类型的包装类,都有做重写equals处理。
public class TestOne{
public static void main(String[] args) {
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println(i1 != i2); //true
System.out.println(i1 == i2); //false
System.out.println(i1 > i2); //false
System.out.println(i1 < i2); //false
System.out.println(i1.equals(i2)); //true
}
}
逻辑运算符
由于java是强类型语言,所以在进行逻辑运算的时候,参与运算的参数必须都是布尔类型,不能像js那样运行(123 && 123) = true。注意逻辑运算过程中的短路,一旦能确定运算结果,表达式就会停止运算再往后的表达式。
直接常量
一般我们在程序里都是用的数字都是十进制的,在指定情况下,也可以用二进制,八进制或者十六进制。
class Demo{
int i = 0x2f; // 0x或者0X 开头表示该数字为十六进制
int j = 0177; // 0 开头表示该数字为八进制
int m = 0b101; // 0b 开头表示该数字为二进制
int n = 100; // 默认情况下表示为十进制
long l = 123123123;
long l1 = 234234234L;
long l2 = 345345345L;
float f = 123.234;
float f1 = 12.333f;
float f2 = 23.555F;
double d1 = 1.234d;
double d2 = 2.345D;
}
16进制在表示一些特殊数字的时候比较方便,如char类型的占有2byte=16bits位,取值范围为 0 - 216-1,2的8次方✖️2的8次方-1=256×256-1=65535-1=0xffff-1
不同进制转换方法,假设数字是mab这样的格式 如果m=0x 代表这是16进制数字 那么将16进制的ab转换为10进制为: a×16(2-1) + b×16(1-1)
位操作符
位操作符号有 与(&)、或(|)、异或(^)、非(~)
先将数字转换为二进制,然后从右向左逐位取一位运算,将1看为true,0看为false。则位运算符与逻辑运算符类似,^可以看成如果两位相同,则取0,否则取1.
class Demo{
public static void main(String[] args){
System.out.println(1&1); // 1
System.out.println(1&0); // 0
System.out.println(0&1); // 0
System.out.println(0&0); // 0
System.out.println(1|1); // 1
System.out.println(1|0); // 1
System.out.println(0|1); // 1
System.out.println(0|0); // 0
System.out.println((0b11)^(0b11)); // 0
System.out.println((0b10)^(0b10)); // 0
System.out.println((0b11)^(0b10)); // 1
System.out.println((0b11)^(0b00)); // 3
// ~按位去反 输入0得1 输入1得0
}
}
位移运算符
有符号的左移、右移(<<,>>)和无符号的右移(>>>)
类型转换
再将变量做类型转换的时候,若从较小的类型转换成较大的类型的时候,可以自动实现。反之则需要显式的申明,表明你已经知道可能存在的信息丢失的风险。
在将double 或者float 数据转换为int的时候,总是取数轴上离零点最近的那个值 (int)(29.5) = 29 、(int)(-29.5) = -29
如果想要实现四舍五入操作,需要使用Math.round(); 总是往大了转。
class Demo{
public static void main(String[] args){
System.out.println(Math.round(-29.3)); //-29
System.out.println(Math.round(-29.5)); //-29
System.out.println(Math.round(-29.7)); //-29
System.out.println(Math.round(29.3)); //29
System.out.println(Math.round(29.5)); //30
System.out.println(Math.round(29.7)); //30
}
}