继承
Java使用extends关键字来实现继承
- 子类自动获得了父类的所有属性,严禁定义与父类重名的属性。
- 除
Object
,每个类都会有父类,一个类有且仅有一个父类。 - 子类无法访问父类的
private
字段或者private
方法,但可以继承protected
字段和方法。 - 父类没有默认的构造方法,子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。
public class SuperClass {
protected String name;
protected int age;
public SuperClass(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Child extends SuperClass {
public Child(int age, String name) {
super(name,age);// 调用父类的构造方法
System.out.println("Child");
}
public String hello() {
return "Hello, " + name; // OK!
}
public void updateAge(int age)
{
super.setAge(age);
}
}
继承树:
Child >SuperClass > Object
- super关键字表示父类(超类)
public void updateAge(int age)
{
super.setAge(age);
}
阻止继承
正常情况下,只要某个class
没有final
修饰符,那么任何类都可以从该class
继承。
从Java 15开始,允许使用sealed修饰class
,并通过permits明确写出能够从该class
继承的子类名称。
public sealed class Shape permits Rect, Circle, Triangle {
...
}
上述Shape类就是一个sealed类,它只允许指定的3个类(Rect, Circle, Triangle)继承它。
向上转型
当我们定一个变量指向子类时,我们可以将定义类型指定为父类,这种方式在我们使用设计模式会很常用。
这种把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)。
SuperClass sc = new SuperClass("张三",14);
System.out.println(sc.getName());
Object o1 = sc;
向下转型
和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting)。
向下转型很容易出现ClassCastException
,所以最好使用instanceof
判定下类型
SuperClass c = new Child(14,"张三");
Child c2 = (Child) c;
System.out.println(c2.getName());
SuperClass sc = new SuperClass(14,"李四");
if (sc instanceof Child){
//不包含Child
Child sc2 = (Child) sc;
}
Child sc1 = (Child) sc;//ClassCastException
区分继承和组合
区域继承就是通过属性来进行赋值
class Book {
protected String name;
public String getName() {...}
public void setName(String name) {...}
}
public class Child extends SuperClass {
protected Book book;
}
final
如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override
public final String hello() {
return "Hello, " + name;
}
如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final
final class Person {}
对于一个类的实例字段,同样可以用final修饰。用final修饰的字段在初始化后不能被修改。
class Person {
public final String name = "Unamed";
}
Person p = new Person();
p.name = "New Name"; // compile error!
可以在构造方法中初始化final字段
多态
方法重写
在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为覆写(Override)。
如果方法签名相同,并且返回值也相同,就是Override,如果方法签名不同,就是Overload。
public class Child extends SuperClass {
...
@Override
public String getName() {
return name+"——"+ age;
}
}
多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法
public static void getName(SuperClass c){
System.out.println(c.getName());
}
SuperClass c = new Child(14,"张三");
getName(c);
多态的特性就是,运行期才能动态决定调用的子类方法。对某个类型调用某个方法,执行的实际方法可能是某个子类的覆写方法。
覆写Object方法
因为所有的class最终都继承自Object,而Object定义了几个重要的方法:
-
toString()
:把instance输出为String; -
equals()
:判断两个instance是否逻辑相等; -
hashCode()
:计算一个instance的哈希值。
class SuperClass {
...
// 显示更有意义的字符串:
@Override
public String toString() {
return "SuperClass:name=" + name;
}
// 比较是否相等:
@Override
public boolean equals(Object o) {
// 当且仅当o为SuperClass类型:
if (o instanceof SuperClass) {
SuperClass sc = (SuperClass) o;
// 并且name字段相同时,返回true:
return this.name.equals(sc.name);
}
return false;
}
// 计算hash:
@Override
public int hashCode() {
return this.name.hashCode();
}
}