进制

世界上有 10 种人,认识和不认识二进制的。

  • 二进制(binary):0,1 ,满2进1。以 0b0B 开头。
  • 十进制(decimal):0-9 ,满10进1。
  • 八进制(octal):0-7 ,满8进1。以 0 开头。
  • 十六进制(hex):0-9 及 A-F(不区分大小写),满16进1。 以 0x0X 开头表示。

直接 print 出来的都是十进制。

int num1 = 0b100;
int num2 = 100;
int num3 = 0100;
int num4 = 0x100;

System.out.println(num1);
System.out.println(num2);
System.out.println(num3);
System.out.println(num4);


运算符

分类:

  • 算术运算符:+ - * / % ++ --
  • 赋值运算符:= += -= *= /= %=
  • 比较运算符(关系运算符):== != < > <= >= instanceof
  • 逻辑运算符:
    &—逻辑与 |—逻辑或 !—逻辑非
    &&—短路与 ||—短路或 ^—逻辑异或
  • 位运算符:<< >> >>> & | ^ ~
  • 三元运算符: (条件表达式) ?表达式1 :表达式2 ;

挑一些要点介绍一下。

取余运算

int m1 = 12;
int n1 = 5;
System.out.println("m1 % n1 = " + m1 % n1);

int m2 = -12;
int n2 = 5;
System.out.println("m2 % n2 = " + m2 % n2);

int m3 = 12;
int n3 = -5;
System.out.println("m3 % n3 = " + m3 % n3);

int m4 = -12;
int n4 = -5;
System.out.println("m4 % n4 = " + m4 % n4);


取余结果的符号与被模数一致。

自增自减

int a1 = 10;
int b1 = ++a1;
System.out.println("a1 = " + a1 + ",b1 = " + b1);

int a2 = 10;
int b2 = a2++;
System.out.println("a2 = " + a2 + ",b2 = " + b2);

自增不会改变数据类型,而 + 1 会。

short a = 1;
short b = a + 1; //×
short b = a++;   //√

赋值

1.
+= 不会改变数据类型。

short a = 1;
a = a + 1; //×
a += 1;    //√
int i = 1;
i *= 0.1;
System.out.println(i);
i++;
System.out.println(i);


2.

int num = 0;
(num++)++;  //×


3.
n *= m++;n = n * m++n = n * m; m++;

逻辑运算符

  • &—逻辑与(单与)
  • &&—短路与(双与)
  • |—逻辑或(单或)
  • ||—短路或(双或)
  • !—逻辑非
  • ^—逻辑异或
boolean b1 = false;
int num1 = 10;
boolean result1 = (b1 & (num1++ > 0));
System.out.println(result1);
System.out.println(num1);

boolean b2 = false;
int num2 = 10;
boolean result2 = (b2 && (num2++ > 0));
System.out.println(result2);
System.out.println(num2);


结论:短路——出结果则停,不继续运算。

位运算符

<< >> >>> ~ & | ^

运算符 含义 细节
<< 左移 3<<2 → 3*2*2 → 12 被移除的高位丢弃,右边补0。
>> 右移 3>>2 → 3\2 → 1 最高位是0(正数),左边补0;
最高位是1(负数),左边补1。
>>> 无符号右移 3>>>2 → 3\2 → 1 无论最高位是0或者是1,左边都补0。
& 按位与 6&3 → 110&011 → 010 → 2
| 按位或 6|3 → 110|011 → 111 → 7
^ 按位异或 6^3 → 110^011 → 101 → 5
~ 取反 ~6 → ~00000110 → 11111001 → -7
~(-6) → ~11111010 → 00000101 → 5
按补码取反
  • 左移是在右补0(正负数都是)。正数左移太多位会出现负数
  • 右移是在左补1(负数)、补0(正数)。
  • 无符号右移,在左补0,

对于 & ^|,判断其是逻辑运算符还是位运算符,取决于其左右两边是布尔型还是整型。

练习:交换两个变量的值

int n1 = 10;
int n2 = 20;

/*

法1
弊端:
1)n1 + n2 可能会超出 int 范围   
2)只能交换数值   

*/
n1 = n1 + n2;
n2 = n1 - n2;
n1 = n1 - n2;

/*

法2
弊端:难理解
不过也不怎么用,不用在意

*/
num1 = num1 ^ num2;
num2 = num1 ^ num2;
num1 = num1 ^ num2;

真实开发的时候,除非操作数非常非常非常大,否则用正常的临时变量交换法就行。

三元运算符

String str = (m > n)? "m大" : ((m == n)? "m和n相等" : "n大");
int max = ((n1 > n2)? n1 : n2) > n3)? ((n1 > n2)? n1 : n2) : n3;

看上去很 NB,但是可读性很差,效率上也没提升,所以没卵用。

另外三元运算可以转换成 if else ,但 if else 未必能转换成三元运算。

运算符优先级

没必要记,有优先级需求用括号。


程序流程控制

  • 顺序结构
  • 分支结构
  • 循环结构

顺序结构没什么说的。

分支结构

if-else

if(条件表达式1){
  执行代码块1;
}else if (条件表达式2){
  执行代码块2;
}
...
else{
  执行代码块n;
}
  • 当多个条件是“互斥”关系时,条件判断语句及执行语句间顺序无所谓。
  • 当多个条件是有交集的关系,需要根据实际情况考虑。
  • 当多个条件是“包含”关系时,条件范围小的在上,范围大的在下,否则范围小的就没机会执行了。

switch

switch(表达式){
  case 常量1:
    语句1;
    break;

  case 常量2:
    语句2;
    break; 

  ...

  case 常量N:
    语句N;
    break;

  default:
    语句;
    break;
}
  • default 语句是可选的,位置也是灵活的。
  • switch( ) 中的表达式,只能是 byteshortcharint、枚举、String 之一

例题:输入 yearmonthday,输出这一天是今年的第几天 sum

switch(month){
case 12:
  sum += 30;
case 11:
  sum += 31;
//...
case 2:
  if((year%4 == 0 && year%100 != 0) || year%400 == 0){
    sum += 29;
  }else{
    sum += 28;
  }
case 1:
  sum += day;
}

凡是可以使用 switch-case 结构的,都可以转换为 if-else 。反之不成立。
条件不多时,优先使用 if-else。

循环结构

  • for
    for(int i = 0; i < n; i++){
      ...
    }
    int n = 1;
    for(System.out.print('a'); n <= 3; System.out.print('c'), n++){
      System.out.print('b');
    }
    结果:abcbcbc
  • while
  • do-while

for 和 while 对比

for(int i = 0; i < n; i++){
  ...
}

相当于

int i = 0;
while(i < n){
  ...
  i++;
}
  • for 定义的 i 是局部的,while 定义的 i 是全局的(当然 for 也可以定义全局的 i)
  • 已知循环次数用 for,不确定循环次数用 while
  • return 的作用是结束方法,不是结束循环。之所以结束循环是因为方法结束。

带标签的break和continue

label:for(int i = 1; i < 999; i++){
  for(int j = 1; j < 10; j++){
    if(j % 4 == 0){
      break label;
    }
    System.out.print(j);
  }
}


Scanner

步骤:

  1. 导入包
    import java.util.Scanner;
  2. Scanner 的实例化
    Scanner scan = new Scanner(System.in);
  3. 调用 Scanner 类的相关方法,获取指定类型的变量
    System.out.println("请输入姓名:");
    String name = scan.next();
    
    System.out.println("请输入年龄:");
    int age = scan.nextInt();
    
    System.out.println("请输入体重:");
    double weight = scan.nextDouble();
    
    System.out.println("请输入性别(true男false女):");
    boolean gender = scan.nextBoolean();
    
    System.out.println("您好," + name + "。您今年" + age + "岁。体重为" + weight + "kg。性别" + gender + "。");

    Scanner 没有提供获取 char 型的获取。所以非要获取 char 的话,只能这么做:
    String srt = scan.next();
    char c = str.charAt(0); //获取索引为 0 的字符