参考资料:
- 面向对象基础 - 廖雪峰的官方网站 (liaoxuefeng.com)
方法
Java 的方法允许定义可变参数:
class Group {private String[] names;public void setNames(String... names) {this.names = names;}
}
用可变参数代替数组类型的好处有:
-
可变参数的传参形式更简单:
Group g = new Group(); g.setNames("Xiao Ming", "Xiao Hong", "Xiao jun"); // 可变参数 g.setNames(new String[] {"Xiao Ming", "Xiao Hong", "Xiao jun"}); // 数组参数
-
可变参数可以避免传入
null
基本类型值传递,引用类型引用传递。
构造方法
class Person {private String name = "Unamed";private int age = 10;public Person(String name, int age) {this.name = name;this.age = age;}
}
在Java中,创建对象实例的时候,先初始化字段,例如,int age = 10;
表示字段初始化为 10
,然后执行构造方法的代码进行初始化。
方法重载
和 C++ 类似
继承
使用 extends
关键字实现继承:
class Person {private String name;private int age;public String getName() {...}public void setName(String name) {...}public int getAge() {...}public void setAge(int age) {...}
}class Student extends Person {// 不要重复name和age字段/方法,// 只需要定义新增score字段/方法:private int score;public int getScore() { … }public void setScore(int score) { … }
}
在Java中,没有明确写 extends
的类,编译器会自动加上 extends Object
,所以除了 object
类,任何类都会继承自某个类。
Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。
super
super
关键字表示父类:
class Person {protected String name;protected int age;public Person(String name, int age) {this.name = name;this.age = age;}
}class Student extends Person {protected int score;public Student(String name, int age, int score) {this.score = score;}
}
上述代码会编译报错,这是因为在 Java 中,任何 class
的构造方法,第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句 super();
由于 Person
类没有无参的构造方法,所以编译失败。
我们可以使用 super
显示调用父类的构造方法:
class Student extends Person {protected int score;public Student(String name, int age, int score) {super(name, age); // 调用父类的构造方法Person(String, int)this.score = score;}
}
阻止继承
使用 final
关键字修饰不能被继承的类。
从 Java 15 开始,可以使用 sealed
和 permits
来明确指定能够继承该 class
的类:
public sealed class Shape permits Rect, Circle, Triangle {...
}
向上转型
可以让父类型的引用变量指向子类型的实例。
向下转型
Person p1 = new Student(); // upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; // ok
Student s2 = (Student) p2; // runtime error! ClassCastException!
向下转型能否成功由变量实际所指的类型决定,可以使用 instanceof
加以判断:
Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // falseStudent s = new Student();
System.out.println(s instanceof Person); // true
System.out.println(s instanceof Student); // trueStudent n = null;
System.out.println(n instanceof Student); // false
instanceof
实际上判断一个变量所指向的实例是否是指定类型,或者这个类型的子类。如果一个引用变量为 null
,那么对任何 instanceof
的判断都为 false
。
从 Java 14 开始,判断 instanceof
后可以直接转型为指定变量:
Object obj = "hello";
if (obj instanceof String) {String s = (String) obj;System.out.println(s.toUpperCase());
}// 可以简写为Object obj = "hello";
if (obj instanceof String s) {System.out.println(s.toUpperCase());
}
区分继承和组合
继承是 is 关系,组合是 has 关系。
多态
可以使用 @Override
让编译器帮助检查是否进行了正确的覆写:
class Person {public void run() {}
}public class Student extends Person {@Override // Compile error!public void run(String s) {}
}
实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。
覆写Object
方法
Object
定义了几个重要的方法:
toString()
:把 instance 输出为String
;equals()
:判断两个 instance 是否逻辑相等;hashCode()
:计算一个 instance 的哈希值。
final
如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为 final
。