1.5.1 描述
java 的继承具有单继承的特点,每个子类只有一个直接父类。通过extends关键字实现。
java 的子类不能获得父类的构造器和初始化块,子类只能从被扩展的父类获得成员变量、方法和内部类(包括内部接口、枚举)。
public class Friut
{
public double weight;
public void info()
{
System.out.println("...");
}
}
public class Apple extends Friut
{
public static void main(String[] args)
{
var a = new Apple();
a.weight = 56;
a.info();
}
}
从子类角度看,子类扩展(extends) 了父类;但从父类的角度来看,父类派生(derive)出了子类。
扩展和派生所描述的是同一个动作,只是观察角度不同而已。
1.5.2 重写父类的方法
子类扩展了父类,子类是一个特殊的父类。子类总是以父类为基础,额外增加新的成员变量和方法。
但有一种情况例外: 子类需要重写父类的方法。
public class Bird
{
public void fly()
{
System.out.println("。。。");
}
}
public class Ostrich extends Bird
{
// 重写Bird类的方法
public void fly()
{
System.out.println("...");
}
public static void main(String[] args)
{
// 创建Ostrich对象
var os = new Ostrich();
os.fly();
}
}
// 子类包含与父类同名方法的现象被称为方法重写(Override)
子类包含与父类同名方法的现象被称为方法重写(Override)
方法的重写要遵循“两同两小一大”规则
- “两同” : 方法名相同、形参列表相同
- “两小”:子类方法返回值类型比父类返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等。
- “一大”: 子类方法的访问权限应比父类方法的访问权限更大或相等。
覆盖方法和被覆盖方法都只能是实例方法,不能一个是类方法,一个是实例方法。
1.5.3 super 限定
如果需要在子类方法中调用父类被覆盖的实例方法,则可以使用super限定来调用父类被覆盖的实例方法。
class Creature
{
public Creature()
{
System.out.println("Creature 无参数的构造器");
}
}
class Animal extends Creature
{
public Animal(String name)
{
System.out.println("Animal 带一个参数的构造器,"+ "该动物的name为" + name);
}
public Animal(String name,int age)
{
// 使用this调用同一个重载的构造器
this(name);
System.out.println("Animal带两个参数的构造器,"+ "其age为" +age);
}
}
public calss Wolf extends Animal
{
public Wolf()
{
// 显示调用父类有两个参数的构造器
super("灰太狼",3);
System.out.println("Wolf 无参数的构造器");
}
public static void main(String[] args)
{
new Wolf();
}
}
1.5.4 多态
Java引用变量有两个类型: 一个是编译时类型 一个是运行时类型
编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定
如果编译时类型和运行时类型不一致,就可能出现所谓的 多态
1.5.5 使用继承的注意点
- 尽量隐藏父类的内部数据。尽量把父类的所有成员变量都设置成private访问类型,不要让子类直接访问父类的成员变量。
- 不要让子类可以随意访问、修改父类的方法。父类中那些仅为辅助其他的工具方法,应该使用private访问控制符修饰,让子类无法访问该方法;如果父类中的方法需要被外部类调用,则必须以public修饰,但又不希望子类重写该方法,可以使用final修饰符来修饰该方法;如果希望父类的某个方法被子类重写,但不希望被其他类自由访问,则可以使用protected来修饰该方法。
- 尽量不要在父类构造器中调用将要被子类重写的方法。