JavaSE----面向对象(多态、抽象类、接口)

来源:互联网 发布:购买域名后如何解析 编辑:程序博客网 时间:2024/05/04 14:24

3.7 多态

3.7.1、理解多态

     多态可以理解为事物存在的多种体现形态。例如下面的代码:

Cat c = new Cat();Animal a = new Cat();

    建立一个猫的对象,可以用猫这个类引用,也可以用动物这个类引用。

3.7.2、多态的前提

    1、类与类之间必须有关系,要么继承,要么实现。

    2、存在覆盖。父类中有方法被子类重写(其实没有也是可以的,但是如果没有这个就没有意义)。

3.7.3、多态中成员的特点

    1、多态中非静态成员变量的特点

    在编译时,参阅引用型变量所属的类中是否有调用的成员变量。如果有,编译通过,如果没有,编译失败。在运行时,调用的成员变量也是引用型变量所属的类中的成员变量。

    简单来说:编译看左边,运行看左边。

class Fu{public int num = 100;}class Zi extends Fu{public int num = 200;}class DuoTaiDemo{public static void main(String[] args){Fu f = new Zi();System.out.println(f.num);}}
    运行结果:


    面试题:下面代码的输出结果是:

public class Child extends Person {public String grade;public static void main(String[] args) {Person p = new Child();System.out.println(p.name);}}class Person {private String name = "Person";int age = 0;}

编译会出错,因为Person类中的name成员变量只有在本类中才能访问,在其Child子类无法访问,所以编译会出错,

    2、多态中非静态成员方法的特点

    在编译时,参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有,编译失败。在运行时,调用的方法是对象所属类中的该方法。

    简单来说:编译看左边,运行看右边。

 class Fu{public int num = 100;public void show_1(){System.out.println("show Fu_1");}public void show_2(){System.out.println("show Fu_2");}}class Zi extends Fu{public int num = 200;public void show_1(){System.out.println("show Zi_1");}}class DuoTaiDemo{public static void main(String[] args){Fu f = new Zi();//System.out.println(f.num);f.show_1();f.show_2();}}
    运行结果:


    在调用show_1()方法时,调用的是子类中的该方法,在调用show_2()方法时,子类中没有,所以调用的是父类中的该方法。

    3、多态中静态成员方法的特点

    在编译时,参阅引用型变量所属的类中是否有调用的成员方法。如果有,编译通过,如果没有,编译失败。在运行时,调用的成员方法也是引用型变量所属的类中的成员方法。

    简单来说:编译看左边,运行看左边。

class Fu{public int num = 100;public void show_1(){System.out.println("show Fu_1");}public void show_2(){System.out.println("show Fu_2");}public static void function(){System.out.println("function Fu");}}class Zi extends Fu{public int num = 200;public void show_1(){System.out.println("show Zi_1");}public static void function(){System.out.println("function Zi");}}class DuoTaiDemo{public static void main(String[] args){Fu f = new Zi();//System.out.println(f.num);//f.show_1();//f.show_2();f.function();}}

    运行结果:



3.7.4、多态的利弊

    好处:提高了代码的扩展性

    坏处:只能使用父类的引用访问父类中的成员。想要调用子类中特有的方法时,需要将父类的引用经过向下转型为子类成员。

class Animal{public void eat(){System.out.println("吃东西");}}class Cat extends Animal{public void eat(){System.out.println("吃鱼");}public void catchMouse(){System.out.println("捉老鼠");}}class Dog extends Animal{public void eat(){System.out.println("吃骨头");}public void lookDoor(){System.out.println("看门");}}class DuoTaiDemo2{     public static void main(String[] args){          //自动类型提升,猫对象提升到了动物类型。但是特有功能无法访问,作用就是限制对特有功能的访问。          //专业讲:向上转型,将子类型隐藏。就不能使用子类的特有方法了。          Animal a = new Cat();          a.eat();          //a.catchMouse();//报错          //如果还想用具体动物猫的特有功能。          //你可以将该对象进行向下转型。          Cat c = (Cat)a; //向下转型的目的是为了能够使用子类中的特有方法。          c.eat();          c.catchMouse();          //注意:对于转型,自始至终都是子类对象在做类型的变化。          //Animal a = new Dog();          //Cat c = (Cat)a;//但是类型不能随意转换,否则可能会报出ClassCastException的异常     }     public static void method(Animal a){//接收时用Animal类的对象接收          a.eat();     }}
    运行结果:



    多态练习:

    1、猫狗案例多态版

/*多态练习:猫狗案例*/class Animal{public void eat(){System.out.println("吃饭");}}class Dog extends Animal{public void eat(){System.out.println("狗吃肉");}public void lookDoor(){System.out.println("狗看门");}}class Cat extends Animal{public void eat(){System.out.println("猫吃鱼");}public void playGame(){System.out.println("猫玩游戏");}}class DuoTaiTest{public static void main(String[] args){//定义为狗Animal a = new Dog();a.eat();System.out.println("------------");//还原成狗Dog d = (Dog)a;d.eat();d.lookDoor();System.out.println("------------");//变成猫a = new Cat();a.eat();System.out.println("------------");//还原成猫Cat c = (Cat)a;c.eat();c.playGame();//Dog dd = (Dog)a; 运行时出错,ClassCastException//Dog dd = new Animal(); 编译时出错,不兼容类型//Dog dd = new Cat(); 编译时出错,不兼容类型}}

    运行结果:



3.8 抽象类

3.8.1 抽象类的概述

    Java中定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。

    抽象方法是怎么来的呢?

    多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。

3.8.2 抽象类的特点

    1、抽象类和抽象方法必须用abstract关键字修饰。

    2、抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类。

    3、抽象类不可以用new建立对象,但是有构造方法, 构造方法的作用是用于子类访问父类数据的初始化。

    4、抽象类中的抽象方法要想被使用,必须由子类复写所有抽象方法后,然后建立子类对象调用。如果子类只复写了部分抽象方法,那么该子类还是一个抽象类。

abstract class Animal{//抽象方法public abstract void eat();//public abstract void eat(){}//这个是空方法体,不是没有方法体,所以会报错//抽象类有构造方法public Animal(){}}//子类是抽象类abstract class Dog extends Animal {}//子类是具体类,重写所有抽象方法class Cat extends Animal {public void eat() {System.out.println("猫吃鱼");}}class AbstractDemo {public static void main(String[] args) {//创建对象//Animal是抽象的; 无法实例化//Animal a = new Animal();//通过多态的方式Animal a = new Cat();a.eat();}}
    运行结果:


3.8.3 抽象类的成员特点

    代码:

/*抽象类的成员特点:    成员变量:可以使变量,也可以是常量。构造方法:有,用于子类访问父类数据的初始化。成员方法:既可以是抽象的,也可以是非抽象的。*/abstract class Animal{//成员变量public int num = 10;public final int num2 = 20;//构造方法public Animal(){}//成员方法public abstract void show();public void method(){System.out.println("method run");}}class Dog extends Animal{public void show(){System.out.println("Dog show");}}class AbstractDemo2{public static void main(String[] args){//采用多态Animal a = new Dog();a.num = 100;System.out.println(a.num);//a.num2 = 200;System.out.println(a.num2);System.out.println("-----------------");a.show();a.method();}}

    运行结果:


    结论:

    抽象类的成员变量可以使变量,也可以是常量;构造方法也有,作用是用于子类访问父类数据的初始化;成员方法既可以是抽象的,也可以是非抽象的。

3.8.4 练习题

    需求:我们在开发一个系统时需要对员工类进行设计,员工包含3个属性:姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

    分析:

    普通员工类(以程序员为例):

    成员变量:姓名、工号、工资
    构造方法:
    成员方法:工作


    经理类:

    成员变量:姓名、工号、工资、奖金

    构造方法:

    成员方法:工作

//定义员工类abstract class Employee{private String name;private String id;private int salary;public Employee(){}public Employee(String name,String id,int salary){this.name = name;this.id = id;this.salary = salary;}public String getName(){return name;}public void setName(String name){this.name = name;}public String getId(){return id;}public void setId(String id){this.id = id;}public int getSalary(){return salary;}public void setSalary(int salary){this.salary = salary;}public abstract void work();}class Programmer extends Employee{public Programmer(){}public Programmer(String name,String id,int salary){super(name,id,salary);}public void work(){System.out.println("写代码");}}class Manager extends Employee{//奖金private int bonus;public Manager(){}public Manager(String name,String id,int salary){super(name,id,salary);}public Manager(String name,String id,int salary,int bonus){super(name,id,salary);this.bonus = bonus;}public void work(){System.out.println("跟客户谈需求");}public int getBonus(){return bonus;}public void setBonus(int bonus){this.bonus = bonus;}}class AbstractTest4{public static void main(String[] args){//测试普通员工类Employee e = new Programmer();e.setName("小明");e.setId("czbk001");e.setSalary(10000);System.out.println(e.getName()+"---"+e.getId()+"---"+e.getSalary());e.work();System.out.println("---------------------");e = new Programmer("小明","czbk001",10000);System.out.println(e.getName()+"---"+e.getId()+"---"+e.getSalary());e.work();System.out.println("---------------------");/*e = new Manager();e.setName("小刚");e.setId("czbk010");e.setSalary(8K);e.setBonus(2K);*///由于子类有特有的内容,所以我们用子类来测试Manager m = new Manager();m.setName("小刚");m.setId("czbk010");m.setSalary(8000);m.setBonus(2000);System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getBonus());m.work();System.out.println("---------------------");m = new Manager("小刚","czbk010",8000,2000);System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getBonus());m.work();}}

    运行结果:


    面试题:

1、一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?

    可以,目的就是为了不让创建对象。

2、abstract不能和哪些关键字共存?

    private、final、static

3.9 接口

3.9.1 理解接口

    抽象类中的方法可以没有一个抽象方法,也可以抽象方法和一般方法各占一些,还可以全都是抽象方法。当抽象类中的方法全都是抽象方法时,这个类可以通过接口的形式来实现。接口使用interface来定义,格式为:interface 接口名 { }。子类中用implements来实现,格式为:子类名 implements 接口名 { }。

3.9.2 接口的成员特点

    成员变量:只能是常量,并且是静态的。默认修饰符:public static final

    构造方法:接口类没有构造方法。

    成员方法:只能是抽象方法。默认修饰符:public abstract

3.9.3 类与类、类与接口、接口和接口的关系

    类与类:继承关系,只能单继承,可以多层继承

    类与接口:实现关系,可以单实现,也可多实现,并且还可以在继承一个类的同时实现多接口。

    接口与接口:继承关系,可以单继承,也可以多继承

3.9.4 抽象类和接口的区别

1、成员区别

    成员变量:在抽象类中可以是变量,也可以是常量;在接口中只能是常量。

    构造方法:抽象类有构造方法;接口没有构造方法。

    成员方法:在抽象类中可以是抽象的,也可以是非抽象的;在接口中必须是抽象的。

2、设计理念区别

    抽象类:被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能。    

    接口:被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能。

3.9.5 接口练习

猫狗案例,加入跳高的额外功能

/*猫狗案例,加入跳高的额外功能分析:从具体到抽象猫:姓名,年龄吃饭,睡觉狗:姓名,年龄吃饭,睡觉由于有共性功能,所以我们抽取了一个父类:动物:姓名,年龄吃饭();睡觉(){}猫 继承动物狗 继承动物跳高的额外功能是一个新扩张功能,所以我们要定义一个接口接口:跳高部分猫 实现跳高接口部分狗 实现跳高接口*/interface Jumpping{//跳高功能public abstract void jump();}abstract class Animal{private String name;private int age;public Animal(){}public Animal(String name,int age){this.name = name;this.age = age;}public String getName(){return name;}public void setName(String name){this.name = name;}public int getAge(){return age;}public void setAge(int age){this.age = age;}//吃饭是抽象的public abstract void eat();//睡觉是具体的public void sleep(){System.out.println("睡觉");}}//具体猫类class Cat extends Animal{public Cat(){}public Cat(String name,int age){super(name,age);}public void eat(){System.out.println("猫吃鱼");}}//具体狗类class Dog extends Animal{public Dog(){}public Dog(String name,int age){super(name,age);}public void eat(){System.out.println("狗吃肉");}}//有跳高功能的猫class JumpCat extends Cat implements Jumpping{public JumpCat(){}public JumpCat(String name,int age){super(name,age);}public void jump(){System.out.println("跳高猫");}}//有跳高功能的狗class JumpDog extends Dog implements Jumpping{public JumpDog(){}public JumpDog(String name,int age){super(name,age);}public void jump(){System.out.println("跳高狗");}}class InterfaceTest{public static void main(String[] args){JumpCat jc = new JumpCat();jc.setName("多啦A梦");jc.setAge(3);System.out.println(jc.getName()+"---"+jc.getAge());jc.eat();jc.sleep();jc.jump();System.out.println("--------------------");jc = new JumpCat("加菲猫",2);System.out.println(jc.getName()+"---"+jc.getAge());jc.eat();jc.sleep();jc.jump();}}

    运行结果:



0 0
原创粉丝点击