回顾

  • 基本数据类型

    • 88 个,String 不是哦!
  • 变量名命名规则

    • 只能包含字母、数字、下划线、美元符号,且不能以数字开头。
  • 编译

    • Java 源代码(.java 文件)-> 字节码(.class 文件)。字节码(bytecode)是一种中间代码,与平台(操作系统)无关,能被 Java 虚拟机(JVM)执行。

    • 编译并运行:java Main.java arg0 arg1 arg2 ...,其中 arg0 arg1 arg2 ...main 方法的参数,也就是 public static void main(String[] args) 中的 args 数组。

    • 编译:javac Main.java

    • 运行:java Main arg0 arg1 arg2 ...

  • printf 方法

  • switch-case

    • case 后的值必须是编译期已知的常量,不能使用变量或表达式。

    • 如果省略 break,代码会继续执行下一个 case,称为贯穿(fall through)。而 default 可以没有 break,因为碰到大括号也会退出。

    • default 可以没有——如果没有匹配的 case 且没有 default 分支,则 switch 块会直接结束。

    • switch 表达式的类型有限制。Java 7 以前,仅支持 byte、short、char 和 int;从 Java 7 开始,还支持 String 和 enum。

  • 表达式执行顺序

    • 按照优先级从高到低的顺序进行计算,同优先级从左到右依次运算。
  • 隐式类型转换

    • 跨类型赋值或计算时,小范围类型会自动转换为大范围类型。(从大到小则需要强制类型转换,可能损失精度)

    • boolean 和其他任何类型都不能相互转换。

    • 在方法调用中,实参类型可以自动提升为形参类型。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      public class Main {
      public static void main(String[] args) {
      printNumber(10); // int 自动转换为 double
      }

      static void printNumber(double num) {
      System.out.println("数字: " + num);
      }
      }
  • 多态

    • 分为编译时多态性(Static Polymorphism)和运行时多态性(Dynamic Polymorphism)。

    • 简要地说,能在编译时知道调用哪个方法的,都会在编译时被绑定(bind);反之,编译时看不出来该调用哪个方法的,都会在运行时被绑定。

  • 重载(Overload)与运行时多态性(Dynamic Polymorphism)

    • 名字相同的两个方法,只要参数不完全相同,就可以共存。
  • 重写(Override)与编译时多态性(Static Polymorphism)

    • 不一定要写 @Override

    • 子类重写构造器时,需要在第一句调用父类构造器;如果不写,则自动调用父类的无参构造器。(btw,一个类里面如果什么构造器都没写,会自动有一个空构造器,没有参数、方法体也是空的。但如果写了至少一个构造器,那个空构造器就不存在了)

    • static、final 方法和构造器不能被重写。abstract 方法不能被子类 abstract 方法重写。

    • 对于重写方法,参数列表必须完全一致;返回值类型必须一致,或是原类型的子类;而访问权限(access level)上子类须与父类一致或更宽松,即:

      父类方法访问权限 子类方法允许的访问权限
      public public
      protected protectedpublic
      包访问权限 包访问权限,protectedpublic
      private 无法重写
  • 接口(Interface)

    • 不能(直接)被实例化(instanciate)。
  • static

    • static 方法内不能有 this(本对象),也不能有 super(父对象),只能调用其他 static 变量和方法。

    • static 的所有东西都跟类走,所以都只有唯一的一份。

    • static 方法不能被重写(override)。

  • final

    • final 基本类型变量:值不能变。

      1
      2
      final int MAX_VALUE = 100;
      MAX_VALUE = 200; // 编译错误:final 变量不能重新赋值
    • final 引用类型变量:引用的哪个对象不能变,但该对象的内容可以变。

      1
      2
      3
      final List<String> list = new ArrayList<>();
      list.add("Hello"); // 正确,可以修改引用对象的内容
      list = new ArrayList<>(); // 编译错误:引用的哪个对象不能修改
    • final 方法:在子类中不能被重写(override)。

    • final 类:不能被继承。

  • abstract

    • abstract 方法:没有方法体(以分号结尾),子类必须实现该方法。如果一个类包含抽象方法,该类必须声明为抽象类。

    • abstract 类:不能直接被实例化,只能通过继承来使用。抽象类也可以包含具体方法。如果子类没有实现父类的所有抽象方法,那么该子类也应当是抽象类。

  • 泛型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class Main {
    public static <T extends Number> double sum(T a, T b) {
    return a.doubleValue() + b.doubleValue();
    }

    public static void main(String[] args) {
    System.out.println(sum(10, 20)); // Outputs: 30.0
    System.out.println(sum(5.5, 2.2)); // Outputs: 7.7
    // sum("10", "20"); // Compile-time error: String is not a subtype of Number
    }
    }
    • 尖括号中可以用逗号隔开多个类型参数(type parameter),如 <T1 extends Number, T2, T3>

    • 这里的 extends 关键字限定了类型参数的上界,即该类型必须是 Number 的子类。

  • Comparable 接口与 compareTo 方法

    • 实现了 Comparable 接口的类可以直接与同类对象进行比较。例如 a.compareTo(b),返回一个 int:为负数,则 a<ba < b;为 00,则 a=ba = b;为正数,则 a>ba > b
  • valueOf 方法

    • 包装类的 valueOf:将基本类型或字符串转换为相应的包装类对象。

      1
      2
      3
      4
      Character a = Character.valueOf('A'); // 返回 Character 对象
      String b = String.valueOf(42); // 将基本类型转换为 String 对象 "42"
      Integer c = Integer.valueOf(42); // 将基本类型转换为 Integer 对象
      Integer d = Integer.valueOf("42"); // 将字符串转换为 Integer 对象
    • 枚举类的 valueOf:用于将字符串转换为对应的枚举常量。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      enum Color {
      RED, GREEN, BLUE;
      }

      public class Main {
      public static void main(String[] args) {
      Color color = Color.valueOf("RED"); // 转换为枚举常量 Color.RED
      System.out.println(color); // 输出:RED
      }
      }
    • 可以认为 valueOf 与 toString 互逆。

  • instanceof

    • 基本语法:objectName instanceof ClassName,返回一个布尔值,表示 objectName 是否是 ClassName 类或其子类的对象。这里 ClassName 也可以是接口。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Animal {}
    class Cat extends Animal {}
    class Dog extends Animal {}

    public class Main {
    public static void main(String[] args) {
    Animal animal = new Cat();
    System.out.println(animal instanceof Cat); // true
    System.out.println(animal instanceof Dog); // false
    System.out.println(animal instanceof Animal); // true
    System.out.println(animal instanceof String); // 报错
    }
    }

思考

  1. 一般使用哪两个关键字来一同修饰编译期常量?

  2. 一个方法或类,可以同时被 abstract 和 final 修饰吗?

  3. 预测输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Animal {
    public void speak() {
    System.out.println("This is an animal!");
    }
    }

    class Dog extends Animal {
    @Override
    public void speak() {
    System.out.println("This is a dog!");
    }
    }

    public class Main {
    public static void main(String[] args) {
    Animal myAnimal = new Dog();
    myAnimal.speak();
    }
    }
  4. 预测输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Animal {
    public static void speak() {
    System.out.println("This is an animal!");
    }
    }
    class Dog extends Animal {}

    public class Main {
    public static void main(String[] args) {
    Dog.speak();
    }
    }
  5. 预测输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class Animal {
    public static void speak() {
    System.out.println("This is an animal!");
    }
    }

    class Dog extends Animal {
    public static void speak() {
    System.out.println("This is a dog!");
    }
    }

    public class Main {
    public static void main(String[] args) {
    Animal.speak();
    Dog.speak();

    Animal myAnimal = new Dog();
    myAnimal.speak();
    ((Dog) myAnimal).speak();
    }
    }
  6. 预测输出:

    1
    2
    3
    4
    5
    6
    7
    8
    public class Main {
    public static void main(String[] args) {
    String a = new String("Hello");
    String b = new String("Hello");
    System.out.println(a == b);
    System.out.println(a.equals(b));
    }
    }
  7. 预测输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Main {
    public static void main(String[] args) {
    String a = new String("Hello");
    String b = a;
    a += " World";
    System.out.println(a == b);
    System.out.println(a.equals(b));
    }
    }
  8. 预测输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Dog extends Animal {
    public Dog(int age) {
    System.out.println("This is a dog!");
    }

    public static void main(String[] args) {
    Animal myAnimal = new Dog(10);
    }
    }

    class Animal {
    protected int age;

    public Animal(int age) {
    this.age = age;
    System.out.println("This is an animal!");
    }
    }

答案

  1. static 和 final。static 使该变量会在编译期就被确定,final 使该变量不能被修改。

  2. 不可以。abstract 表示子类必须实现,final 表示子类不能重写(override),二者相矛盾。

  3. 答案:

    1
    This is a dog!
  4. 答案:

    1
    This is an animal!

    如果子类中找不到某 static 方法,会在其父类中寻找。

  5. 答案:

    1
    2
    3
    4
    This is an animal!
    This is a dog!
    This is an animal!
    This is a dog!

    使用 objectName.methodName 来调用静态方法,取决于 objectName 被声明为哪个类,与它实际是谁的对象无关。

  6. 答案:

    1
    2
    false
    true

    对于引用类型,== 只判断二者是否指向同一个地址;String 类型使用 equals 方法实现真正的判等。

  7. 答案:

    1
    2
    false
    false

    a 被修改过后是 Hello World,这是一个新的对象;而 b 仍然是 Hello。所以二者无论如何都不相等。

  8. 答案:

    1
    Complication Error

    子类构造器第一行没有调用父类构造器,且父类也没有无参构造器。