学习笔记 java编程思想 第3章 操作符"/>
java学习笔记 java编程思想 第3章 操作符
目录
- 3.1 更简单的打印语句
- 练习1
- 3.2 使用Java操作符
- 3.3 优先级
- 3.4 赋值
- 练习2
- 3.4.1 方法调用中的别名问题
- 练习3
- 3.5 算术操作符
- 练习4
- 3.6 自动递增和递减
- 3.7 关系操作符
- 3.7.1 测试对象的等价性
- 练习5
- 练习6
- 3.8 逻辑运算符
- 练习7
- 3.8.1 短路
- 3.9 直接常量
- 练习8
- 3.9.1 指数记数法
- 练习 9
- 3.10 按位操作符
- 练习10
- 3.11 移位操作符
- 练习 11
- 练习 12
- 练习13
- 3.12 三元操作符 if-else
- 3.13 字符串操作符 +和 +=
- 3.14 使用操作符时常犯的错误
- 3.15 类型转换操作符
- 3.15.1 截尾和舍入
- 3.15.2 提升
- 3.16 Java没有sizeof()
- 3.17 操作符小姐
- 练习14
在最底层,Java中的数据是通过使用操作符来操作的。
3.1 更简单的打印语句
import java.util.Date;
// javase5新增加的概念 静态导入(static import)
import static net.mindview.util.Print.*;public class Test01 {}class HelloDate {public static void main(String[] args) {print("Hello, it's: ");print(new Date());}
}
// 运行结果
Hello, it's:
Sat Mar 27 20:19:13 CST 2021
练习1
import static net.mindview.util.Print.*;public class Exec01 {public static void main(String[] args) {System.out.println("Hello");print("Hello");}
}
// 运行结果
Hello
Hello
3.2 使用Java操作符
大股份操作符都操作基本数据类型,而“=”、“==”、“!=”还可以操作对象。此外,String
类支持“+”和“+=”。
3.3 优先级
在字符串中,“+”的意思是“字符串连接”。
public class Test02 {public static void main(String[] args) {int x = 1, y = 2, z = 3;int a = x + y - 2/2 + z; // 5int b = x + (y - 2) / (2 + z); // 1System.out.println("a=" + a + ", b=" + b);}
}
// 运型结果
a=5, b=1
3.4 赋值
赋值使用操作符“=”。意思是:取右边的值(即右值),把它估值给左边(即左值)。
- 右值:可以是任何常数、变量、表达式(只要能生成一个值就能当作右值)。
- 左值:必须是一个明确的、已命名的变量。常数不能作为左值。也就是说,必须有一个物理空间可以存储等号右边的值。
a = 4;
对基本数据类型的赋值,使用a=b,修改a的内容,b的内容不会受到这中修改的影响。
但是在为对象赋值时,就发生了变化。对一个对象进行操作时,其实真正操作的是对象的引用。
代码实例
import static net.mindview.util.Print.*;public class Test03 {public static void main(String[] args) {Tank t1 = new Tank();Tank t2 = new Tank();t1.level = 9;t2.level = 10;print("1: t1:level=" + t1.level + ", t2:level=" + t2.level);// t1也指向了t2指向的那个level=10的对象,// 之前t1指向的那个level=9的对象没有任何引用指向它,会被垃圾回收器自动清理。t1 = t2;print("1: t1:level=" + t1.level + ", t2:level=" + t2.level);t1.level = 2222;print("1: t1:level=" + t1.level + ", t2:level=" + t2.level);}
}class Tank {int level;
}
// 运行结果
1: t1:level=9, t2:level=10
2: t1:level=10, t2:level=10
3: t1:level=2222, t2:level=2222
这中现象称为“别名现象”,它是java操作对象的一种的方式。
// 避免别名问题的办法就是不进行引用赋值,而是将对象里面的基本类型进行赋值。
t1.level = t2.level;
这样做可以保持连个对象彼此相互对立。但是直接操作对象内的域容易导致混乱,违背了面向对象程序设计的原则。这可不是小问题,所有从现在开始就应该注意,为对象赋值可能会产生意想不到的结果。
练习2
public class Exec02 {public static void main(String[] args) {Student stu1 = new Student();Student stu2 = new Student();stu1.score = 99;stu2.score = 80;System.out.println("1: stu1: score=" + stu1.score + ", stu2: score=" + stu2.score);stu1 = stu2;System.out.println("2: stu1: score=" + stu1.score + ", stu2: score=" + stu2.score);stu2.score = 89.0f;System.out.println("3: stu1: score=" + stu1.score + ", stu2: score=" + stu2.score);}
}class Student {int sno;float score;
}// 运行结果
1: stu1: score=99.0, stu2: score=80.0
2: stu1: score=80.0, stu2: score=80.0
3: stu1: score=89.0, stu2: score=89.0
3.4.1 方法调用中的别名问题
将一个对象传递给方法时,也会出现别名问题。
代码示例
import static net.mindview.util.Print.print;public class PassObject {public static void f(Letter y) {y.c = 'z';}public static void main(String[] args) {Letter l = new Letter();l.c = 'a';print("1: c=" + l.c);// 传递引用,f(Letter y)会将传入的引用l复制一份,赋值给局部变量y// 实际改变的是f()之外的对象f(l);print("2: c=" + l.c);}
}
class Letter {char c;
}
// 运行结果
1: c=a
2: c=z
练习3
import static net.mindview.util.Print.print;public class Exec03 {float score;public static void main(String[] args) {Exec03 e = new Exec03();e.score = 10.0f;print("1: score=" + e.score);e.method1(e);print("2: score=" + e.score);}public void method1(Exec03 obj) {obj.score = 20.0f;}
}
// 运行结果
1: score=10.0
2: score=20.0
3.5 算术操作符
+, -, *, /, %
+=, -=. *=, /=, %=
练习4
import static net.mindview.util.Print.print;public class Exec04 {public static void main(String[] args) {Vehicle vehicle1 = new Vehicle();vehicle1.distance = 50;vehicle1.time = 0.5;// 车辆行驶的平均速度 单位:km/hdouble velocity = vehicle1puteVelocityByDistanceAndTime(vehicle1.distance, vehicle1.time);print("d=" + vehicle1.distance + "km, t=" + vehicle1.time + "h, v=" + velocity + "km/h");}}
class Vehicle {double distance; // 车辆行驶路程 单位:kmdouble time; // 车辆行驶时间 单位:hourpublic double computeVelocityByDistanceAndTime(double d, double t) {return d / t;}
}
// 运行结果
d=50.0km, t=0.5h, v=100.0km/h
3.6 自动递增和递减
代码
import static net.mindview.util.Print.print;public class Test05 {public static void main(String[] args) {int i = 1;print("i : " + i); // 1print("++i : " + ++i); // 2print("i++ : " + i++); // 2print("i : " + i); // 3print("--i : " + --i); // 2print("i-- : " + i--); // 2print("i : " + i); // 1}
}
// 运行结果
i : 1
++i : 2
i++ : 2
i : 3
--i : 2
i-- : 2
i : 1
3.7 关系操作符
3.7.1 测试对象的等价性
class EquivalenceInteger {public static void main(String[] args) {// 因为不通过new创建对象,直接使用字面值赋值,s1和s2都指向同一个地址,即整数常量池中的10的地址Integer n1 = 10;Integer n2 = 10;System.out.println(n1 == n2); // trueSystem.out.println(n1 != n2); // false// 通过new创建了两个对象,s1和s2分别指向了两个对象。// ==和!=都比较的是堆中对象的的地址值。Integer n3 = new Integer(10);Integer n4 = new Integer(10);System.out.println(n3 == n4); // falseSystem.out.println(n3 != n4); // true}
}
// 运行结果
true
false
false
trueclass EqualMethod {public static void main(String[] args) {Integer n1 = new Integer(10);Integer n2 = new Integer(10);System.out.println(n1.equals(n2)); // true}
}
// 运行结果
trueclass Value {int i;
}class EqualMethod2 {public static void main(String[] args) {Value v1 = new Value();Value v2 = new Value();// 因为equals()方法默认是比较引用的,两个引用不一样所以说false。System.out.println(v1.equals(v2)); // false}
}
// 运行结果
false
练习5
public class Exec05 {public static void main(String[] args) {Dog d1 = new Dog();d1.name = "spot";d1.says = "Ruff!";Dog d2 = new Dog();d2.name = "scruffy";d2.says = "Wurf!";System.out.println(d1.name + ", " + d1.says);System.out.println(d2.name + ", " + d2.says);}
}class Dog {String name;String says;
}
// 运行结果
spot, Ruff!
scruffy, Wurf!
练习6
public class Exec06 {public static void main(String[] args) {Cat c1 = new Cat();c1.name = "spot";c1.says = "Ruff!";Cat c2 = new Cat();c2.name = "scruffy";c2.says = "Wurf!";Cat c = c1;System.out.println(c == c1); // trueSystem.out.println(c.equals(c1)); // true}
}class Cat {String name;String says;
}
// 运行结果
true
true
3.8 逻辑运算符
&&, ||, !
逻辑运算符只能用在布尔值上,这与C/C++不一样。
整数类型不能转换为布尔类型,其他类型都可以转换。
练习7
import java.util.Random;public class Exec07 {public static void main(String[] args) {Coin coin = new Coin();Exec07 t = new Exec07();int count = 0;System.out.println("=========开始扔硬币============");while ( count++ < 10) {System.out.print("第" + count +"次: ");t.throwCoin(coin);coin.show();}}public void throwCoin(Coin coin) {Random random = new Random();int n = random.nextInt(1000);coin.isPositive = n % 2 == 0;}
}class Coin {boolean isPositive;public void show() {if (isPositive) System.out.println("正面");else System.out.println("反面");}
}
// 运行结果
=========开始扔硬币============
第1次: 反面
第2次: 反面
第3次: 反面
第4次: 正面
第5次: 反面
第6次: 正面
第7次: 反面
第8次: 正面
第9次: 反面
第10次: 反面
3.8.1 短路
import static net.mindview.util.Print.*;public class Test07 {public static void main(String[] args) {Test07 t = new Test07();// test3(1)没有执行boolean ret = t.test1(0) && t.test2(4) && t.test3(1);System.out.println(ret);}public boolean test1(int val) {print("test(" + val + ")");print("result: " + (val < 1));return val < 1;}public boolean test2(int val) {print("test(" + val + ")");print("result: " + (val < 2));return val < 2;}public boolean test3(int val) {print("test(" + val + ")");print("result: " + (val < 2));return val < 3;}
}
// 运行结果
test(0)
result: true
test(4)
result: false
false
3.9 直接常量
直接常量的后缀字符表示类型,
类型 | 后缀字符 | 前缀字符 |
---|---|---|
long | L或者l | - |
float | F或者f | - |
double | D或者d | - |
十六进制数 | - | 0x或者0X |
八进制数 | - | 0 |
C/C++和java中没有二进制数的直接常量表示法。其他进制数可以通过Integer
和Long
的toBinaryString()
方法,自动转化为int
,显示二进制数。
练习8
public class Exec08 {public static void main(String[] args) {long x = 0x1L;long y = 0xAL;long w = 01L;long v = 010L;System.out.println("x = " + Long.toBinaryString(x));System.out.println("y = " + Long.toBinaryString(y));System.out.println("x + y = " + Long.toBinaryString(x + y));System.out.println("w = " + Long.toBinaryString(w));System.out.println("v = " + Long.toBinaryString(v));System.out.println("w + v = " + Long.toBinaryString(w + v));}
}
// 运行结果
x = 1
y = 1010
x + y = 1011
w = 1
v = 1000
w + v = 1001
3.9.1 指数记数法
练习 9
public class Exec09 {public static void main(String[] args) {float minFloat = 1.4E-45f;float maxFloat = 3.4028235E38f;System.out.println("float min=" + minFloat + ", max=" + maxFloat);double minDouble = 4.9E-324d;double maxDouble = 1.7976931348623157E308d;System.out.println("double min=" + minDouble + ", max=" + maxDouble);}
}
// 运行结果
float min=1.4E-45, max=3.4028235E38
double min=4.9E-324, max=1.7976931348623157E308
3.10 按位操作符
&, |, ~, ^
&=, |=, ^=
按位操作符,不会“短路”。在移位表达式中,不能使用别运算,原因将在后面解释。
练习10
public class Exec10 {public static void main(String[] args) {int x = 0x55;int y = 0xAA;System.out.printf("%8s\n", Integer.toBinaryString(x));System.out.printf("%8s\n", Integer.toBinaryString(y));}
}
// 运行结果1010101
10101010
3.11 移位操作符
<<, >>, <<<, >>>
<<=, >>=, <<<=, >>>=
为了防止移位超出最大位数:对char
、byte
、short
进行移位,进行移位之前,先会转换为int
类型,计算结果也是int
值,只有数值低5位有用(因为2的5次方是32,int
类型数值只有32位)。long
类型的值,结果long
,只有低6位有用。
如果对byte
和short
进行无符号左移和无符号右移位运算时,可能会出现结果会不正确。因为在移位之前,会转换为int
类型,再右移,然后将结果截断,赋值给原来的类型,这个过程可能会出现结果是-1的情况。
import static net.mindview.util.Print.*;public class Test08 {public static void main(String[] args) {int x = -1;// 负数使用的是补码// -1的原码是10000000 00000000 00000000 00000001// -1的反码是11111111 11111111 11111111 11111110// -1的补码是11111111 11111111 11111111 11111111print(Integer.toBinaryString(x)); // 11111111 11111111 11111111 11111111// x无符号右移10位,位x >>>= 10;// 将x的补码无符号右移10位的00000000 11111111 11111111 11111111print(Integer.toBinaryString(x)); // 11111111 11111111 11111111long y = -1;// -1 的原码是 10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001// -1 的反码是 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111110// -1 的补码是 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111print(Long.toBinaryString(y)); // 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111y >>>= 10;print(Long.toBinaryString(y)); // 00000000 00111111 11111111 11111111 11111111 11111111 11111111 11111111short s = -1;// -1 的原码是 10000000 00000001// 先将short类型,转换为int类型 10000000 00000000 00000000 00000001// 然后后面的计算和int一样了print(Integer.toBinaryString(s));s >>>= 10;// 11111111 11111111 11111111 11111111// 右移10位是 00111111 11111111 11111111// 然后截取 11111111 11111111print(Integer.toBinaryString(s));byte b = -1;print(Integer.toBinaryString(b));// 这个移位运算的结果,没有赋值给b,而是直接打印出来的int类型,没有截断,所以结果数正确的。print(Integer.toBinaryString(b>>>10));}
}
练习 11
public class Exec11 {public static void main(String[] args) {int x = 0x80000000;for (int i = 0; i < 32; i++) {x >>>= 1;System.out.println(Integer.toBinaryString(x));}}
}
// 运行结果
1000000000000000000000000000000
100000000000000000000000000000
......
100
10
1
0
练习 12
public class Exec12 {public static void main(String[] args) {int x = 0xffffffff;x <<= 5;System.out.println(Integer.toBinaryString(x));for (int i = 0; i < 32; i++) {x >>>= 1;System.out.println(Integer.toBinaryString(x));}}
}
// 运行结果
11111111111111111111111111100000
1111111111111111111111111110000
111111111111111111111111111000
11111111111111111111111111100
1111111111111111111111111110
111111111111111111111111111
.......
11
1
0
练习13
public class Exec13 {public static void main(String[] args) {char ch = '~';// 126=0111 1110show(ch);}public static void show(char ch) {System.out.println(Integer.toBinaryString(ch));}
}
// 运行结果
1111110
3.12 三元操作符 if-else
boolean-exp ? value0 : value1
如果boolean-exp(布尔表达式)为true,就计算value0,value0就是最终整个三元操作符的值。如果boolean-exp(布尔表达式)为false,就计算value1。value1就是最终整个三元操作符的值。
3.13 字符串操作符 +和 +=
在字符串中的用途:连接不同的字符串、
这是是一种操作符重载(operator overloading)。
public class Test09 {public static void main(String[] args) {int x = 0, y = 1, z = 2;String s = "x, y, z";print(s + x + y + z); // x, y, z012print(x + " " + s); // 0 x, y, zs += "(summed) =";print(s + (x + y + z)); // x, y, z(summed) =3// 基本类型转换为字符串常用的方法print("" + x); // 0}
}
// 运行结果
x, y, z012
0 x, y, z
x, y, z(summed) =3
0
3.14 使用操作符时常犯的错误
while(x = y) {// ...
}
在java中,x = y
不会像C/C++那样,会将int
类型转换为boolean
类型,导致死循环。
但是,在java中,有和C/C++一样的问题,就是使用按位与(&
)、按位或(|
)代替逻辑与(&&
)、逻辑或(||
),但是操作数必须是boolean
类型。
&
:不是短路运算。当操作数全部是整型数值或者可与转换为整型数值时,是位运算符,进行位运算。当操作数全部为布尔类型时,是逻辑运算符。
3.15 类型转换操作符
java中有两种类型转换:
-
隐式类型转换:将一种数据类型自动转换为另一种类型,不需要显示的声明。如:
10 / 3.0
的结果是3.3333333333333335public class A {public static void main(String[] args) {int a = 10;System.out.println(a / 3); // 3System.out.println(a / 3.0); // 3.3333333333333335} }
-
显示类型转换:将想要转换的数据类型放到圆括号里面,可以显式的进行数据类型的转换,或者在不能自动进行准换的时候强制进行类型转换。
public class A {public static void msin(String[] args) {int i = 100;// 对变量进行类型转换long a = (long) i;// 对数值进行类型转换long b = (long) 200.1;String s = "10";// int b = (int) s; // 编译时的错误: 不兼容的类型: String无法转换为int} }
从信息是否丢失的角度,分为:
- 窄化转换(narrowing conversion):将能容纳信息多的类型转换为容纳信息少的数据类型,这可能会造成信息地丢失。编译器会提示需要显示转换。
- 扩展转换(widening conversion):不会造成信息丢失,编译器不会提示需要显示转换。
java允许把任何基本数据类型转换为别的基本类数据型,但布尔类型除外。“类”数据类型不允许随意进行类型转换,必须在其所属类型的类族之间进行类型转换。
3.15.1 截尾和舍入
在进行narrowing conversion时,必须注意截尾和舍入问题。不管是float
还是是double
类型,转换为int
时,总是将数字截尾,不是四舍五入。
public class A {public static void main(String[] args) {float fa = 21.7f;float fb = 21.4f;double da = 21.7;double db = 21.4;System.out.println("(int)fa : " + (int)fa); // 21System.out.println("(int)fb : " + (int)fb); // 21System.out.println("(int)da : " + (int)da); // 21System.out.println("(int)db : " + (int)db); // 21}
}
如果想四舍五入,需要使用java.lang.Math
类中的round()
方法。
public class A {public static void main(String[] args) {float fa = 21.7f;float fb = 21.4f;double da = 21.7;double db = 21.4;System.out.println("Math.round(fa) : " + Math.round(fa)); // 22System.out.println("Math.round(fb) : " + Math.round(fb)); // 21System.out.println("Math.round(da) : " + Math.round(da)); // 22System.out.println("Math.round(db) : " + Math.round(db)); // 21}
}
3.15.2 提升
除布尔类型的其他基本数据类型,执行算术运算或按位运算,会将类型小的,自动转换为类型大的。比如:
- byte类型进行位运算:会先自动转换为int类型,然后再进行位运算,最后的结果是int类型的数值。
- int类型和double类型相加:会先将int类型转换为double类型,然后再在相加,最后的结果是double类型的数值。
3.16 Java没有sizeof()
C/C++中,sizeof()可以得到系统为某个数据分配的字节数。这最大的原因是为了“移植”。在不同机器上,数据类型的字节数可能不同。
java不需要sizeof()操作符,因为所有数据类型在所有的机器上大小都是相同的。
3.17 操作符小姐
必须注意narrowing conversion的结果,否则会造成信息地丢失。
布尔类型没有运算,智能赋值为true或false,测试它是否为true或false。布尔值不能相加相减。
chart、byte和short在运算过程中,会自动进行数据类型提升为int类型,得到的结果是int值,必须显式类型转换为指定的类型。
对两个较大的int类型值座乘法运算,有很大可能会溢出,但是编译器部署提示任何警告或异常。
// 因为int的最大值是2147483647,100000 * 100000的结果为10000000000大于2147483647,产生溢出。
public class A {public static void main(String[] args) {int a = 100000;int b = 100000;System.out.println( a * b); // 1410065408}
}
练习14
public class Exec14 {public static void main(String[] args) {compareTwoStr("asdf", "asdf");compareTwoStr("asd", "asdf");}public static void compareTwoStr(String s1, String s2) {System.out.println("" + s1 + " == " + s2 + ": " + (s1 == s2));System.out.println("" + s1 + " != " + s2 + ": " + (s1 != s2));System.out.println("" + s1 + ".equals(" + s2 + "): " + (s1.equals(s2)));}
}
// 运行结果
asdf == asdf: true
asdf != asdf: false
asdf.equals(asdf): true
asd == asdf: false
asd != asdf: true
asd.equals(asdf): false
更多推荐
java学习笔记 java编程思想 第3章 操作符
发布评论