继承和多态

一.继承

1.概念

继承机制:是面向对象程序设计使代码可复用的最重要的手段,它允许程序员在保持原有类的特性的基础上进行扩展,增加新的功能,这样产生的类成为派生类。继承呈现了面型对象程序设计的层次结构,体现了由简单到复杂的过程。

继承主要解决的问题:抽取共性,实现代码复用

2.语法

修饰符 class 子类 extends 父类{
    ......
}


//举例
class Animal{
    String name;
    int age;
}
class Dog extends Animal{
    String color;
    public void bark(){
        System.out.println(name+"汪汪叫");
    }
}

3.父类成员访问

(1)子类访问父类成员的成员变量

1.子类和父类不存在同名变量

2.子类和父类成员变量同名

(2)子类访问父类的成员方法

1.子类和父类不存在同名变量

2.子类和父类成员变量同名

(3)总结

方法不同时,在子类方法中或通过子类对象访问方法时,优先访问子类自己的,自己没有时再到父类中去找,如果父类也没有就报错

4.关键字super

1.主要作用:在子类方法中访问父类

2.注意:(1)只能在非静态方法中访问;

(2)在子类方法中,访问父类成员的成员变量和方法;

5.子类构造方法

1.子类对象构造时,要先调用基类构造方法,然后执行子类的构造方法

2.子类构造方法中,没有写任何关于基类构造方法的代码,但在构造子类对象时,先执行基类构造方法,然后再执行子类构造方法

(原因)子类对象中,成员由两部分组成:基类继承下来的部分,子类新增的部分。在构造子类对象时先要调用基类的方法,将从基类继承下来的构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整。

3.注意:(1)若父类显式定义无参或默认无参的构造方法,在子类构造方法第一行默认有隐含的super()调用即调用基类构造方法;

(2)若父类构造方法带参数,则此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败;

(3)在子类构造方法中,super()调用父类构造时,必须是子类构造函数中的第一条语句;

(4)super()只能在子类构造方法中出现一次,且不能和this同时出现;

6.super和this的异同

1.都是java中的关键字1.this是当前对象的调用,即调用实例方法的对象;super相当于是子类对象中从父类继承下来的部分的成员的引用
2.都只能在类的非静态访问中使用,用来访问非静态成员方法和字段2.在非静态成员方法中:this用来访问本类的方法和属性;super用来访问父类继承下来的方法和属性
3.在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在3.在构造方法中:this()用于调用本类的构造方法;super用于调用父类构造方法。两种调用不能同时在构造方法中出现
4.构造方法中一定会有super()的调用,用户没有写编译器也会增加;但this()用户不写则没有

7.再谈初始化

执行顺序:

父类和子类的静态先执行(只执行一次)     

父类的实例,父类的构造方法                       

子类的实例,子类的构造方法                 

//静态代码块先执行,且值执行一次,在类加载阶段执行;

//当有对象创建时,才会执行实例化代码块,实例化代码块完成后最后构造方法执行      

8.protected关键字

注意:父类中private成员变量虽然在子类中不能直接访问,但也继承到子类中了

9.继承方式

1.单继承:class B---->class A

public class A{
    //......
}
public class B extends A{
    //......
}

2.多层继承:class C---->class B---->class A

public class A{
    //......
}
public class B extends A{
    //......
}
public class C extends B{
    //......
}

3.不同类继承同一个类:class B---->class A<----class C

public class A{
    //......
}
public class B extends A{
    //......
}
public class C extends A{
    //......
}

//java不支持多继承

//如果需要控制继承,此时这个类可以被final修饰,意味着当前类不可以继承,这个类是密封类。

10.final关键字

1.final修饰变量/字段:表示变量不可被修改

2.final修饰类:表示次类不能被继承

3.final修饰方法:表示该方法不能被重写

11.继承与组合

1.组合是一种表达类之间的关系的方式,能够达到代码重用的效果;

组合并没有涉及到特殊用法,仅仅是将一个类的实例作为另一个类的字段;

2.组合表示对象之间的关系是has--a(比如:汽车由引擎,底盘等组成)

class Tire{}
class Engine{}
class Car{
    private Tire tire;
    private Engine engine;
}

继承别是对象之间的关系是is---a(比如:狗是一种动物)

3.组合和继承都能实现代码复用,一般建议能用组合尽量用组合


二.多态

1.概念

不同的对象完成同一行为时会产生不同的结果

2.多态实现条件

1.必须在继承体系下;

2.子类必须要对父类中方法进行重写;

3.通过父类的引用调用重写的方法;

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法

3.重写

1定义:override,也称覆盖,是子类对父类非静态,非private修饰,非final修饰,非构造方法等的实现过程进行重新编写;返回值、形参(参数个数,参数类型)不能改变

2.好处:可以根据自己需要,定义特定于自己的行为,即子类能根据需要实现父类的方法

3.规则:(1)子类在重写父类的方法时,一般必须与父类方法原型一致:返回值类型,方法名,参数列表(参数类型,参数个数);

(2)被重写的方法返回值类型可以不同,但必须具有父子关系;

(3)访问权限不能比父类中被重写的方法访问权限更低;

(4)父类被private、static修饰的方法,构造方法都不能被重写;

(5)重写的方法可以使用@Override注解来显式指定,能帮助进行一些合法性校验;

(6)被final修饰的方法(密封方法)不能被重写;

4.设计原则:对于已经投入使用的类,最好重新定义一个新的类,来重复利用其中共性的内容或改动新的内容

5.重写和重载的区别

名称重写重载
参数列表一定不能修改可以修改
返回类型一定不能修改(除非可构成父子关系)可修改
访问限定符一定不能做更严格的限制(可降低限制)

可修改

即:方法重写是子类与父类的一种多态性表现,方法重载是一个类的多态。

6.动态绑定:(前期/早绑定):在编译时根据用户传递的实参类型就确定了具体调用哪个方法(典型:函数重载)

7.静态绑定:(后期/晚绑定):在编译时不能确定方法的行为,需要等到程序运行时才能确定具体调用哪个类的方法

4.向上转型和向下转型

1.向上转型:

(1)创建一个子类对象,将其当做父类对象来使用

(2)语法格式:父类类型 对象名=new 子类类型();

Animal animal=new cat ("kitty",2);
//animal是父类类型,但是可以引用一个子类对象,因为是从小范围到大范围的转换

(3)应用场景:

方法传参

public animal void func(Animal animal){}

直接赋值

public static void main(String[] args){
    Animal animal=new Dog("小白",3);
    func(new Dog("小白",3));
}

返回值

public static Animal func(){
    return new Dog("小白",3);
}

(4)优点:代码实现更灵活

(5)缺陷:不能调用子类特有的方法

2.向下转型:

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时可能需要调用子类特有的方法,此时将父类引用再还原为子类对象即可,即向下转换

5.使用多态的优劣

(1)好处

1.降低代码的“圈复杂度”,避免使用大量if-else

2.可扩展能力更强

(2)缺陷

1.实行没有多态性:当父类或子类都有同名属性时,通过父类引用,只能引用父类自己的成员属性

2.构造方法没有多态性

6.避免在构造方法中调用要重写的方法

class B{
    public B{
        func();
    }
    public void func(){
        System.out.println("B.func()");
    }
}
class D extends B{
    private int num=1;
    @Override
    public{
        System.out.println("D.func()"+num);
    }
}
public class Test{
    public static void main(String[] args) {
        D d=new D();
    }
}

//打印结果:D.func()0

1.构造对象的同时会调用B的构造方法;

2.B的构造方法中调用了func方法,此时会触发动态绑定,会调用到D中的func;

3.此时D对象自身还没有构造,此时num处在未初始化的状态,值为0;

4.故在构造函数内,尽量避免使用实例方法,除了final和private方法

结论:用尽量简单的方法时对象进入可工作区域,尽量不要在构造器中调用方法(如果次方法还没被重写,就会触发动态绑定,但此时子类对象还没构造完),可能会出现一些隐藏但极难发现的问题。

  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值