子类继承父类,子类的构造方法必须调用父类的构造方法。如果子类的构造方法中没有显式调用父类的构造方法,系统默认调用父类的无参构造方法。如果父类没有无参构造方法,且子类没有显式调用父类的其他构造方法,编译时会报错There is no parameterless constructor available in 'xxx'。
final 不能修饰构造方法,因为构造方法不是可以被继承的成员。构造方法本身就只能在创建对象时调用,不能被重写。
⚠️ 注意:不能在实例初始化块中对final 修饰的变量进行赋值。实例初始化块(构造代码块)在每次创建对象时执行,而 final 变量有严格的赋值规则:
final 变量可以在声明处或构造方法中赋值
如果你在实例初始化块中给 final 变量赋值,编译器无法保证构造方法中不会再次赋值
因此,为了保证 final 变量只赋值一次,Java 不允许在初始化块中赋值已经在构造方法中赋值的 final 变量
class MyClass { final int x; // 实例初始化块:尝试给final变量赋值 { x = 10; // 错误:final变量不能在实例初始化块中赋值 } // 合法的构造方法赋值 public MyClass(int value) { x = value; // 合法:在构造方法中赋值 }}
public class Main { public static void main(String[] args) { Person p = new Person("Alice", 20); System.out.println(p); // 输出:Person{name='Alice', age=20} }}class Person { private String name; private int age; Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; }}
equals方法
功能:比较两个对象是否相等。默认实现是比较内存地址(引用)的相等性。
重写建议:如果希望基于对象内容比较相等性,应重写此方法。
public class Main { public static void main(String[] args) { Person p1 = new Person("Alice", 20); Person p2 = new Person("Alice", 20); System.out.println(p1.equals(p2)); // 输出:true }}class Person { private String name; private int age; Person(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Person other = (Person) obj; return age == other.age && name.equals(other.name); }}
hashCode方法
功能:返回对象的哈希码。默认实现通常基于对象的内存地址计算哈希码。
重写建议:如果重写了 equals() 方法,应重写 hashCode(),确保哈希码的一致性。
import java.util.Objects;public class Main { public static void main(String[] args) { Person p1 = new Person("Alice", 20); Person p2 = new Person("Alice", 20); System.out.println(p1.hashCode() == p2.hashCode()); // 输出:true }}class Person { private String name; private int age; Person(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Person other = (Person) obj; return age == other.age && name.equals(other.name); } @Override public int hashCode() { return Objects.hash(name, age); }}
getClass 方法
功能:返回表示当前对象的 Class 类型的对象。可以用它来动态检查对象的类信息。
public class Main { public static void main(String[] args) { Person p = new Person(); Class<?> clazz = p.getClass(); System.out.println(clazz.getName()); // 输出:Person }}class Person {}
public class InstanceofDemo { public static void main(String[] args) { Animal animal = new Dog(); if (animal instanceof Animal) { // true Animal an = (Animal) animal; an.eat(); } if (animal instanceof Dog) { // true Dog dog = (Dog) animal; dog.lookHome(); } if (animal instanceof ShepherdDog) { // false ShepherdDog shepherdDog = (ShepherdDog) animal; shepherdDog.introduction(); } if (animal instanceof Cat) { // false Cat cat = (Cat) animal; cat.catchMouse(); } // boolean flag = animal instanceof String; // 编译失败 }}class Animal { public void eat() { System.out.println("Animal eat ..."); }}class Dog extends Animal { public void lookHome() { System.out.println("Dog look home ..."); }}class ShepherdDog extends Dog { public void introduction() { System.out.println("Shepherd dog introduction ..."); }}class Cat extends Animal { public void catchMouse() { System.out.println("Cat catch mouse ..."); }}
多态中成员变量的特点
无论编译还是运行,访问的都是 等号左边的引用类型所属的类 的变量。
注意:成员变量不会发生多态,始终使用 引用类型的变量。
public class Main { public static void main(String[] args) { Parent p = new Child(); System.out.println(p.name); // 输出: Parent }}class Parent { String name = "Parent";}class Child extends Parent { String name = "Child";}
多态中成员方法的特点
编译阶段:编译器只检查左侧引用类型中是否声明了该方法;如果没有,则编译报错。
运行阶段:实际调用的是右侧对象所属类中重写后的方法(动态绑定 / 动态分派)。
public class Main { public static void main(String[] args) { Parent p = new Child(); p.show(); // 输出: Child show }}class Parent { void show() { System.out.println("Parent show"); }}class Child extends Parent { @Override void show() { System.out.println("Child show"); }}