面向对象(多态)

面向对象(多态)

一、方法覆盖

方法重载:同一个类,两个或者两个以上,方法名称一致,参数列表不一致,跟其他无关(static,void,public)

方法覆盖(重写):子类继承并且改变了方法体,其他不能改变(访问修饰符,异常)

  • static方法不能覆盖和重写,因为静态的方法是跟类绑定,子类写了和父类一样的静态方法,并不是覆盖

static是模板,只能继承,不能覆盖

package com.szwollf.Day08.DemoOverride;
​
public class Person {
    private String name;
    private String sex;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public String getSex() {
        return sex;
    }
​
    public void setSex(String sex) {
        this.sex = sex;
    }
    //说话
    public void speak(){
        System.out.println("人说人话!");
    }
​
    //静态方法
    public static void fun(){
        System.out.println("我是父类的静态方法!!!!");
    }
​
}
 

package com.szwollf.Day08.DemoOverride;
​
public class AmericaPerson extends Person{
//    @Override//可以不标明覆盖 但是最好标明
    public void speak(){
        System.out.println("Hello! nice to meet you!");
    }
}
 

package com.szwollf.Day08.DemoOverride;
​
public class ChinesePerson extends Person{
    //说话-- 中国人
//    public void speak(){//这里不写则不覆盖 直接使用父类的方法
//        System.out.println("华为牛逼");
//    }
//静态方法
    public static void fun(){
        System.out.println("我是子类的静态方法!!!!");
    }
}
 

package com.szwollf.Day08.DemoOverride;
​
public class Test {
    public static void main(String[] args) {
        ChinesePerson cp=new ChinesePerson();
        cp.speak();
        AmericaPerson ap=new AmericaPerson();
        ap.speak();
    }
}

二、多态

三大特征:封装 继承 多态

同一个动作,在不同地方,表现的形态是不同的(龙生九子,各有不同)

多态的前提条件:

  • 继承(每个子都从龙父那里继承了一些变量和方法)

  • 重写覆盖(同时由产生变异,每个实例由改写了方法体)

  • 子类类型向上转型(可以向上和向下转换,变量不能向上转型所以不能多态)

多态能调用的方法,都是父子共有的方法,执行的是子类的方法

package com.szwollf.Day08.DemoPolymorphic;
​
public class Animal {
    private String name;
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    //方法 movie() 动
    public void movie(){
        System.out.println("动物动");
    }
}
 

package com.szwollf.Day08.DemoPolymorphic;
​
public class Cat extends Animal{
    @Override
    public void movie() {
        System.out.println("猫爬");
    }
    public void catchMouse(){
        System.out.println("只有猫会捉老鼠!");
    }
}
 

package com.szwollf.Day08.DemoPolymorphic;
​
public class Dog extends Animal{
    @Override
    public void movie() {
        System.out.println("狗跑");
    }
}
 

package com.szwollf.Day08.DemoPolymorphic;
​
public class Test {
    public static void main(String[] args) {
        Cat c1 = new Cat();
        c1.setName("狸猫-小黑");
        System.out.println(c1.getName());
        c1.movie();
        c1.catchMouse();//猫类独有的必须是向下转型的才能使用
​
        Dog d1 = new Dog();
        d1.setName("旺财");
        System.out.println(d1.getName());
        d1.movie();
        //Animal 是 父类   Cat是子类---向上转型
        Animal c2=new Cat();
        c2.setName("小黑");
        System.out.println(c2.getName());
        c2.movie();
        //c2.catchMouse();//不能调用
​
        Animal d2=new Dog();//向上转型
        d2.setName("旺财");
        System.out.println(d2.getName());
        d2.movie();
    }
}

因为多态能调用的方法是父子共有的,子类独有的方法多态是不能调用的,怎么办呢?使用向下转型

向下转型引发的问题:

java.lang.ClassCastException 类型转换异常

  Animal cat=new Cat();
  Dog cat1 = (Dog) cat;//向上才可以强转

new 的是谁,转换成谁,不要犯错

转换为了防止出现转换异常,用 instanceof 关键字来进行判断

变量 instanceof 类型 ----运算符

判断 前边变量 属于不属于 后面的类型? 结果是boolean类型

cat instanceof Cat 判断变量 cat 属于Cat类型吗?

if(cat instanceof  Dog){//前面的是否属于后面的具象化
    Dog cat1 = (Dog) cat;
}else {
    System.out.println("cat不属于Dog类型,不能转换!");
}

以后再进行引用数据类型的转换都要先判断是不是要转换的类型,养成习惯!

 

 

  • 子类独有的方法,为什么不直接new子类呢?而非要用多态,再向下转型呢?

后期,拿到对象是别人给的,别人给的形态就是父类类型,具体的代码通过使用多态的向下转型而来,即给出框架,我们用多态围绕框架编程

为什么别人不直接给我子类类型呢?而是给我一个父类类型?

多态的优点:耦合度降低,参数作为抽象的类,面向抽象编程

手机耦合度太高了----------内存不够用-------换手机

电脑-------------------4g不够-----8g---16g----------------耦合度低

代码的方向:高内聚,低耦合

讲课 ,一个老师一个阶段,耦合度不高

 

三、super关键字

super关键字指当前对象的父类对象的特征

this指当前对象

package com.szpowernode.day08.superdemo;
//父类
public class Person {
    String name;


}
package com.szpowernode.day08.superdemo;
//子类
public class Student extends Person {

    public void fun(){
        System.out.println(this);//s1
        System.out.println(this.name);//
       // System.out.println(super);
        //super不是一个对象,使用上跟this基本一样
        System.out.println("super:"+super.name);
    }
}
package com.szpowernode.day08.superdemo;

public class TestStudent {
    public static void main(String[] args) {
        Student s1=new Student();
        s1.name="张三";
        System.out.println("s1:"+s1.name);
        s1.fun();

    }
}

 

super 不是对象,因为不能直接输出,如果是对象就可以输出

  • super应用

this在构造函数使用 this(【参数列表】) 第一行

super([参数列表])第一行

package com.homework.Day07.Demo01;

public class Monkey {
    private String name;
    private char gender;
    public void speak(String sentence){
        System.out.println(sentence);
    }
    public Monkey() {}
    public Monkey(String name,char gender) {
        this.name = name;
        this.gender = gender;
    }
    public void setName(String name) {
        this.name = name;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public char getGender() {
        return gender;
    }
}
package com.homework.Day07.Demo01;

public class Person extends Monkey{
    public Person() {}
    public Person(String name,char gender) {
        super(name,gender);就是把子类构造函数的参数传给父类
    }//子类构造函数调用前会先调用父类无参
}

package com.szpowernode.day08.thisandsuper;

public class TestZi {
    public static void main(String[] args) {
        Zi zi=new Zi("刘备","男","女");
        System.out.println(zi.name);
        System.out.println(zi.sex);
        System.out.println(zi.hobby);
    }
}
package com.homework.Day07.Demo01;

public class Test {
    public static void main(String[] args) {
        Person p=new Person();
        p.speak("我是珍妮");
        p.setGender('男');
        p.setName("飞科");
        System.out.println(p.getGender());
        System.out.println(p.getName());
        Person p2=new Person("哈哈",'女');
        System.out.println(p2.getGender());
        System.out.println(p2.getName());
    }
}

 

super()调用父类对象的构造函数 必须在第一行

  • super调用父类方法以及变量多态

package com.szwollf.Day08.DemoDragon;

public class Dragon {
    String name="蛟龙";
    public void Fire(){
        System.out.println("喷火");
    }
}
package com.szwollf.Day08.DemoDragon;

public class TaoTie extends Dragon{
    String name="饕餮";
    @Override
    public void Fire(){
        System.out.println("喷水");
        super.Fire();
    }
}
package com.szwollf.Day08.DemoDragon;

public class Test {
    public static void main(String[] args) {
        TaoTie tt=new TaoTie();
        tt.Fire();
        Dragon tt2=new TaoTie();
        tt2.Fire();//赋值给父类 变量名.成员方法  用的还是子类重写的方法
        System.out.println();
        Dragon dg=new TaoTie();
        System.out.println(dg.name);//向上转型时 变量名.成员变量 用的是父类的成员变量 并没有覆盖
        //        dg.name="饕餮";
        ((TaoTie)dg).name="饕餮";//把父类强转子类然后改值,父类没变
        System.out.println(dg.name);//依旧是父类的蛟龙
        System.out.println(((TaoTie)dg).name);//改的是这个 不是父类的name

    }
}

多态

父类 变量 = new 子类();

变量.成员变量还是父类的

变量.成员方法是子类

 

总结:

子类继承并改写父类方法的方法体可以覆盖,而子类重写成员变量却不能覆盖

即new的子类对象方法赋值给父类类型的变量时,把父类本身的方法给重写了,即子类的方法有两种类型,一种子类类型,一种父类类型,这就是多态,所以多态的条件为继承(覆盖的前提),覆盖(如果不能覆盖那就是子类和父类是分开的并不是子类的多种形态),向上转型(即子类的方法可以是父类类型)

多态:子类的方法向上转为父类类型

变量那个并不是跨类覆盖,而是子类父类各写各的,你子类赋值给子类,子类把子类覆盖,那当然是子类的变量,你子类赋值给父类,还是父类,覆盖失败,父类强转子类在赋值变量,父类依旧没被覆盖。

对于成员变量来说不能多态,所以变量是什么类型就是什么类型

对于成员方法来说能多态,所以方法用哪个类型看new的是哪个,new父类用父类,new子类,子类覆盖父类。用子类方法。

 

java语言设计者,只是设计了方法的覆盖重写,没有设计成员变量的覆盖和重写

四、递归(Day04)

package com.szwollf.Day08;

public class Recursion {
    public static void main(String[] args) {
        System.out.println(calc(10));
    }
    public static int calc(int n){
        n = n/2;
        System.out.println(n);//5 2 1 0压栈
        if (n > 0) {
            calc(n);//调用自己
        }
        return n;//0 1 2 5出栈
    }
}

如上图所示,函数在每进入下一层的时候,当前层的函数并未结束,它必须等它调用的下一层函数执行结束返回后才能继续往下走。 所以最下面的那句print(n)会等最里层的函数执行时才会执行,然后不断往外退层,所以会出现0、1、2、5的效果

递归特性:

  1. 必须有一个明确的结束条件

  2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

  3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

递归通常用于多级菜单

 

 

 

posted @ 2019-10-02 13:57  Wollf  阅读(198)  评论(0)    收藏  举报