第3章 操作符
3.1 更简单的打印语句
本节介绍了静态导入,通过封装程序,简化打印语句。
传统打印:
public static void main(String[] args) {
System.out.println("hello java");
}
工具类:
package com.ding.three.util;
public class Print {
public static void outPut(Object o){
System.out.println(o);
}
}
封装后:
package com.ding.three;
import static com.ding.three.util.Print.*;
public class Test {
public static void main(String[] args) {
outPut("hello java");
}
}
3.2 使用Java操作符
操作符: 接收一个或多个参数,并生成一个新值。
副作用: 有些操作符会改变操作数自身的值。
操作符大部分是操作“基本类型”,但是“=” “==” ”!=“ 可以操作对象,String类可以使用”+“和”+=“。
3.3 优先级
当一个表达式中存在多个操作符时,操作符的优先级决定了各部分的计算顺序。
public class Test {
public static void main(String[] args) {
// String后的+跟随非String时,编译器会将非String转换为String
outPut("a = "+ 1);
}
}
3.4 赋值
别名现象
public static void main(String[] args) {
User user1 = new User();
User user2 = new User();
user1.age = 10;
user2.age = 20;
outPut("1: " + user1.age + "-" + user2.age); // 1: 10-20
user1 = user2;
user1.age = 30;
outPut("2: "+user1.age + "-" +user2.age); // 2: 30-30
}
方法调用中的别名
public static void f(User user){
user.age = 1;
}
public static void main(String[] args) {
User user = new User();
user.age = 10;
outPut("1-" + user.age); // 1-10
f(user); // 方法中的参数传递
outPut("2-" + user.age); // 2-1
}
总结: 基本数据类型赋值是赋的本身,对象赋的是内存地址。对其的理解为变量是一块内存空间,右边的内存空间是什么,左边的变量的内存空间就会是什么,因为基本数据类型右边装的就是其本身,所以左边也会是其本身,而变量是内存地址,所以右边也会是内存地址。User user = new User();可以认为是做了两件事,在堆中开辟一块内存空间,创建User的实例,并将该内存空间的地址赋值给user变量。
3.5 算术操作符
public static void main(String[] args) {
// 指定一个种子,产生的数会固定;一般不指定,会以当前时间作为种子,达到伪随机
Random random = new Random(47);
// 获取0-100一个随机整数
int a = random.nextInt(100) + 1; // +1防止出现0
int b = random.nextInt(100) + 1;
outPut(a); // 59
outPut(b); // 56 random获取一个数列,nextInt()不断获取下一个
outPut(a + b); // 115
outPut(a - b); // 3
outPut(a * b); // 3304
outPut(a / b); // 1 去掉小数,不是四舍五入
outPut(a % b); // 3
a %= b;
outPut(a); // 3
outPut(-a); // -3 一元操作符(可以将小类型提升到int)
outPut(+a); // 3 一元加号
}
3.6 自动递增和递减
public static void main(String[] args) {
int i = 1;
outPut(++i); // 2 先执行运算
outPut(i++); // 2 后执行运算
outPut(i); // 3
outPut(--i); // 2
outPut(i--); // 2
outPut(i); // 1
}
3.7 关系操作符
public static void main(String[] args) {
// > < >= <= == !=
Integer n1 = new Integer(10);
Integer n2 = new Integer(10);
// 比较对象的引用
outPut(n1 == n2); // false
// 比较对象的值
outPut(n1.equals(n2)); //true
}
3.8 逻辑操作符
public static boolean test1(int n) {
outPut("test1");
return n == 1;
}
public static boolean test2(int n) {
outPut("test2");
return n == 2;
}
public static void main(String[] args) {
// 短路与&& 短路或|| 非!
outPut(true && true); // true
outPut(true && false); // false
outPut(false && false); // false
outPut(true || true); // true
outPut(true || false); // true
outPut(false || false); // false
outPut(!true); // false
outPut(!false); // true
// 短路现象:当前边的条件可以判断整个逻辑表达式时,后边的就不会执行
boolean b1= test1(2) && test2(2); // test1
boolean b2 = test1(1) || test2(2); // test1
}
3.9 直接常量
public static void main(String[] args) {
int i = 0;
double d = 0;
// float类型
d = 7f;
d = 7F;
// double类型
d = 7l;
d = 7L;
// 八进制
i = 07;
// 十六进制
i = 0x7;
// 转为二进制
outPut(Integer.toBinaryString(i)); // 111
// 幂/返回double类型
outPut(1.24e2); // 124.0
outPut(1.24E-2); // 0.0124
}
3.10 按位操作符
public static void main(String[] args) {
// 按位操作符:按二进制计算
outPut(Integer.toBinaryString(3)); // 11
outPut(Integer.toBinaryString(7)); // 111
// 按位与
outPut(3 & 7); // 3
// 按位或
outPut(3 |7); // 7
// 按位异或
outPut(3 ^7); // 4
outPut(Integer.toBinaryString(5)); // 101
// 按位非
outPut(~5); // -6
// 布尔类型可以执行& | ^ 但不会短路
outPut(true & true); // true
outPut(true & false); // false
}
3.11 移位操作符
原码: 最高位是符号位,非符号位是该数字绝对值的二进制表示。
反码: 正数的反码与原码一致;负数的反码是除最高位外对原码按位取反。
补码: 正数的补码与原码一致;负数的补码是该数的反码加1。
获得负数二进制的两种方法:
- 符号位+数字绝对值->除符号位取反->最后位+1->负数的二进制;
- 对应正整数->取反(所有)->最后位+1->负数的二进制。
计算机数字运算均是基于补码的。
int 数据类型是32位、有符号的以二进制补码表示的整数,最小值是 -2,147,483,648(-2^31);最大值是 2,147,483,647(2^31 - 1)。
public static void main(String[] args) {
// << 左移位:二进制向左移动,末尾补0
outPut(Integer.toBinaryString(2)); // 10
outPut(Integer.toBinaryString(2<<1)); // 100
// >> 右移位:二进制向右移动,从后向前,消去对应的数量
outPut(Integer.toBinaryString(4)); // 100
outPut(Integer.toBinaryString(4>>1)); // 10
// 负数会在开头补1
outPut(Integer.toBinaryString(-4)); // 11111111111111111111111111111100
outPut(Integer.toBinaryString(-4>>2)); // 11111111111111111111111111111111
outPut(Integer.toBinaryString(-4<<2));
// >>> 无符号右移,无论正负,在开头补0
outPut(Integer.toBinaryString(-4>>>2)); // 111111111111111111111111111111
outPut(-4>>>2); // 1073741823
// 应用
outPut(3<<2); // 3*2^2快速计算 12
outPut(20>>2); // 20/2^2快速计算 5
}
3.12 三元操作符
public static void main(String[] args) {
outPut(true ? 1 : 2); // 1
outPut(false ? 1 : 2); // 2
}
3.13 字符串操作符+和+=
public static void main(String[] args) {
String s = "a";
s += "b"; // 字符串+=运用
outPut(s);
outPut("" + 1); // 转为字符串
}
3.15 类型转换
窄化转换:将类型转化 为容纳更少信息的类型。
扩展转换: 将类型转化 为容纳更多信息的类型。
基本数据类型(除布尔外)可以相互转换。
类族之间可以进行相互转换。
public static void main(String[] args) {
// 窄化是截尾操作
outPut((int)0.7); // 0
// 四舍五入使用round()方法
outPut(Math.round(0.7)); // 1
outPut(Math.round(0.4)); // 0
}
char、byte、shot在运算时先转为int再运算,如果想赋值给他们,需要进行类型转换;
运算中最大数据类型决定了结果的数据类型。