面向对象基础9(继承)
封装、继承、多态是面向对象的三大特征
继承的理解
苹果(类)继承了水果(类)
老虎(类)继承了动物(类)
- Java的继承是类与类之间的关系
- 是一种由一般到特殊的关系(与现实中的辈分没有关系,所以子类和父类名字并不准确)
——小类(子类)是一种特殊的父类(大类)
子类的实例完全可当做父类的实例来使用
别称
父类(超类、基类、大类);子类(派生类、小类)
继承的语法
修饰符 class 类名 extends 父类
{代码块}
说明:
Java是单继承的,所以,一个子类只能继承一个父类
若不显示继承父类,Java会默认继承Object
类
——一切皆Object!
举例:
public class A {
}
class B extends A{
}
class C extends B{
}
//C的直接父类是B;Object、A是C的间接父类(我附庸的附庸不是我的附庸...)
//A的直接子类是B,间接子类是C
继承的作用:
子类继承父类,就可以直接使用父类的方法和成员变量
举例1:
public class Bird {
public void fly(){
System.out.println("Birds Flying");
}
}
class Sparrow extends Bird{
}
//此处Sparrow类继承Bird类,Sparrow类并没有写任何方法但继承了Bird类的方法
public class SparrowTest {
public static void main(String[] args) {
Sparrow sp=new Sparrow();
sp.fly();
}
}
/*
Birds Flying
*/
继承的优点是可以实现代码的复用
方法重写
存在意义
当子类发现父类的方法不适合自己的时候,就需要重写方法
规则
两同两小一大:
两同:方法名相同、形参列表相同;
两小:返回值类型相同或者更小,声明抛出的异常相同或者更小;
一大:访问权限相同或者更大
举例2:
public class Ostrich extends Bird{
//重写fly方法
@Override
public void fly(){
System.out.println("can not fly");
}
}
public class OstrichTest {
public static void main(String[] args) {
Ostrich A=new Ostrich();
A.fly();
}
}
/*
can not fly
*/
此时原有的fly
方法被重写
注解@Override
——用于报错,要求被修饰的方法必须重写父类方法,否则就报错(方法拼写错误);
Super关键字
与this
引用很相像,super
可以用于限定访问父类的实例变量和实例方法。
super.父类的实例变量
super.父类的实例方法(参数)
例3:
class Base {
int age=2;
}
class Sub extends Base{
int age =20;
public void test(){
int age=200;
System.out.println(age);
System.out.println(this.age);//调用该类中的成员变量
System.out.println(super.age);//调用父类中的成员变量
public void names(String name)
{
System.out.println("执行父类"+name);
}
}
}
public class SubTest {
public static void main(String[] args) {
Sub A=new Sub();
A.test();
}
}
/*
200
20
2
*/
例3改:
class Base {
int age=2;
}
class Sub extends Base{
public void test(){
System.out.println(age);
System.out.println(this.age);
System.out.println(super.age);
}//此处删除了原有的局部变量与子类中的成员变量
}
public class SubTest {
public static void main(String[] args) {
Sub A=new Sub();
A.test();
}
}
/*
2
2
2
*/
从上面两个例子可以看出:
变量的调用遵循就近原则,输出的age
变量优先调用所属方法的局部变量,若局部变量不存在,其次考虑所属类的实例变量(此处是子类),最后考虑其父类的实例变量。
而this
和super
关键字再次就是为了打破就近原则,调用所需要的变量。
class Base {
public void names(String name)
{
System.out.println("执行父类"+name);
}
}
class Sub extends Base{
public void names(String name)
{
System.out.println("执行子类"+name);
}
public void test(){
names("Java");
/*
此处等同于this.names("Java");
等同于Base.names("Java");
类方法需要类来调用,默认添加类名
*/
super.names("Java");
}
}
public class SubTest {
public static void main(String[] args) {
Sub A=new Sub();
A.test();
}
}
/*
执行子类Java
执行父类Java
*/
此时带有super
关键子的names
方法会打破就近原则,执行父类的原有方法。
子类调用父类的构造器
子类的构造器一定要调用父类的构造器一次(有且仅有一次)
- 如果子类构造器没有显示调用父类构造器,系统会在子类构造器的第一行自动调用父类无参数的构造器;
- 子类构造器的第一行显示使用
super
调用父类构造器:super()
super和this关键字不顾能出现在同一语句
例5:
package Super关键字;
class Fruit{
private double weight;
public Fruit(double weight)
{
this.weight=weight;
}
}
public class Apple extends Fruit {
public Apple() {
super(2.2);//常识调用父类Fruit的double构造器
}
}
备注:如果父类没有无参构造器——则子类构造器必须显示调用(super
调用,如上例)父类的构造器