[2017.10.21-22]多态&抽象类&接口

来源:互联网 发布:mac终端重设密码 编辑:程序博客网 时间:2024/06/05 14:31

多态

1.多态:一个事物在不同时刻体现出来的不同状态.

2.对于多态的三个前提条件(缺一不可) :
1)必须有继承关系(如果没有继承关系,谈不上多态!)
2)必须有方法重写
3)有父类引用指向子类对象:向上转型

3.多态的成员访问特点:
1)成员变量:
编译看左边,运行看左边
2)成员方法(非静态的成员方法):
编译看左,运行看右;由于存在方法重写,所以就运行最终的就是子类的成员方法
3)静态成员方法:(静态方法算不上方法重写,静态直接跟类有关系!)
编译看左,运行看左
4)构造方法:还是对象进行初始化,由于是一种继承关系,还是分层初始化

4.演示:

//父类class Fu{    public int num = 10 ;    //父类的成员方法    public void show(){        System.out.println("show Fu...");    }    //静态方法    public static void function(){        System.out.println("function Fu....");    }}//子类class Zi extends Fu{    int num = 20 ;    public void show(){        System.out.println("show Zi...");    }    public static void function(){        System.out.println("function Zi....");    }}//测试类public class DuoTaiDemo {    public static void main(String[] args) {        //创建父类的对象:多态的形式//      有父类引用指向子类对象:向上转型        Fu f = new Zi() ;        //访问成变量        System.out.println(f.num);        //调用成员方法:show()        f.show() ;        //静态方法        f.function() ;    }}

5.多态的好处(特点):
1)提高代码的维护性(由继承保证)
2)提高代码的扩展性(由多态保证)
(java的开发原则:低耦合,高内聚)

6.演示:

//父类class Animal{    public void eat(){        System.out.println("eat");    }    public void sleep(){        System.out.println("sleep...");    }}//猫类class Cat extends Animal{    public void eat(){        System.out.println("猫吃鱼...");    }    public void sleep(){        System.out.println("猫趴着睡...");    }}//狗类class Dog extends Animal{    public void eat(){        System.out.println("狗吃骨头...");    }    public void sleep(){        System.out.println("狗躺着睡....");    }}//猪类class Pig extends Animal{    public void eat(){        System.out.println("猪吃白菜...");    }    public void sleep(){        System.out.println("猪卧着睡....");    }}//写一个动物的工具类class AnimalTool{    //将类中无参构造私有化:目的是为了不让外界创建对象!    /*private AnimalTool(){    }*/    //形式参数是一个父类    public void useAnimal(Animal a){        a.eat() ;        a.sleep() ;    }}//测试类public class DuoTaiDemo2 {    public static void main(String[] args) {        //我喜欢猫,养一只猫        Cat c1 = new Cat() ;        c1.eat() ;        //还喜欢猫,又养了一只        Cat c2 = new Cat() ;        c2.eat() ;        //...        Cat c3 = new Cat() ;        c3.eat() ;        System.out.println("---------------------");        //优化改进:将猫的吃和睡的方法封装成独立的功能        /*useCat(c1) ;        useCat(c2) ;        useCat(c3) ;*/        Dog d1 =  new Dog() ;        Dog d2 =  new Dog() ;        Dog d3 =  new Dog() ;        //调用狗的功能        /*useDog(d1) ;        useDog(d2) ;        useDog(d3) ;*/        Pig p1 = new Pig() ;        Pig p2 = new Pig() ;        Pig p3 = new Pig() ;        System.out.println("------------------------");        //最终版代码        //先创建AnimalTool对象        AnimalTool at = new AnimalTool() ;        at.useAnimal(c1) ;//形式参数:Animal a = new Cat();        at.useAnimal(c2) ;        at.useAnimal(c3) ;        System.out.println("-------------------------");        at.useAnimal(d1) ;        at.useAnimal(d2) ;        at.useAnimal(d3) ;        System.out.println("-------------------------");        at.useAnimal(p1) ;        at.useAnimal(p2) ;        at.useAnimal(p3) ;    }    //写一个功能    /*public static void useCat(Cat c){        c.eat() ;        c.sleep() ;    }    public static void useDog(Dog d){        d.eat() ;        d.sleep() ;    }*/}

7.多态的弊端:
不能访问子类的特有功能

8.演示:

class Animal2{    public void show(){        System.out.println("show Animal2...");    }}//子类class Cat2 extends Animal2{    public void show(){        System.out.println("show Cat2....");    }    //特有功能    public void playGame(){        System.out.println("猫玩毛线...");    }}//测试类public class DuoTaiDemo3 {    public static void main(String[] args) {        //多态的形式:父类引用指向子类对象        Animal2 a = new Cat2() ;        a.show() ;//      a.playGame() ;    }}

9.多态的弊端:
不能访问子类的特有功能.
解决方案:
1)创建子类的具体对象,来访问自己的特有功能;虽然可以解决多态的弊端,但是从内存角度考虑,需要创建子类对象,那么必须在堆内存开辟空间, 耗费内存,浪费空间!
2)既然多态的第三个前提条件:父类引用指向子类对象,那么可以向下转型:将父类的引用强制转换为子类的引用(前提必须有父类的引用存在)
3)向下转型必须依赖于向上转型!

10.演示:

class Animal3{    public void show(){        System.out.println("show Animal2...");    }}//子类class Cat3 extends Animal3{    public void show(){        System.out.println("show Cat2....");    }    //特有功能    public void playGame(){        System.out.println("猫玩毛线...");    }}public class DuoTaiDemo4 {    public static void main(String[] args) {        //父类引用指向子类对象        Animal3 a = new Cat3() ; //向上转型        a.show() ;        //不能访问子类特有功能//      a.playGame();        //创建子类具体对象    /*  Cat3 c = new Cat3() ;        c.playGame() ;*/        //父类的引用强制转换为子类的引用:向下转型        Cat3 c = (Cat3) a ;        c.playGame() ;    }}

11.一般情况下,向下转型使用不当会造成异常.

12.演示:

class Animal4{    public void eat(){}}class Cat4 extends Animal4{    public void eat(){}    public void playGame(){}}class Dog4 extends Animal4{    public void eat(){}    public void lookDoor(){}}//测试类:public class DuoTaiDemo5 {    public static void main(String[] args) {        //内存是狗        Animal4 a = new Dog4() ;        //向下转型:还原成狗        Dog4 d = (Dog4)a ;        //内存是猫        a = new Cat4() ;        //还原成猫        Cat4 c = (Cat4) a ;        //编译通过了        Dog4 dd = (Dog4)a ; //不能将内存猫转换为狗    }}

多态的向下转型内存变化图解

13.有继承关系 分层初始化:
父类先初始化,然后子类初始化

14.多态的访问特点:
成员方法(非静态的):
编译看左,运行看右(方法重写)

15.练习:

class A {    public void show() {        show2();    }    public void show2() {        System.out.println("我");    }}class B extends A {    /**     * public void show(){     *  show2() ;     * }     * */    public void show2() {        System.out.println("爱");//爱    }}class C extends B {    public void show() {        super.show();    }    public void show2() {        System.out.println("你");//你    }}public class DuoTaiTest {    public static void main(String[] args) {        A a = new B();        a.show();        B b = new C();        b.show();        //  2)爱你     }}

//猫狗案例练习多态版/** * 猫 *      eat() *      sleep() * 狗 *      eat() *      sleep() *  * 动物类:Animal *  * */class Animal5{    public void eat(){        System.out.println("动物饿了就需要吃饭...");    }    public void sleep(){        System.out.println("动物困了,需要休息...");    }}//子类class Cat5 extends Animal5{    @Override    public void eat(){        System.out.println("猫吃鱼...");    }    public void sleep(){        System.out.println("猫趴着睡觉...");    }}class Dog5 extends Animal5{    @Override    public void eat(){        System.out.println("狗吃骨头...");    }    public void sleep(){        System.out.println("狗躺着睡觉...");    }}//测试类public class DuoTaiTest2 {    public static void main(String[] args) {        //创建对象        //多态版(实际开发中:多态使用最广泛:接口多态是经常使用的!)        Animal5 a = new Cat5() ;        a.eat() ;        a.sleep()  ;        a = new Dog5() ;        a.eat() ;        a.sleep();    }}

//不同地方饮食文化不同的案例class Person{    public void eat(){        System.out.println("eat");    }}//南方人class SourthPerson extends Person{    public void eat(){        System.out.println("南方人喜欢吃米饭...");    }    //特有功能    public void business(){        System.out.println("南方人爱经商....");    }}//北方人class NorthPerson extends Person{    public void eat(){        System.out.println("北方人爱吃馒头...");    }    //特有功能    public void yanJiu(){        System.out.println("北方人爱研究....");    }}//测试类public class DuoTaiTest3 {    public static void main(String[] args) {        //多态版测试        Person p = new SourthPerson() ;        p.eat() ;//      p.business() ;        SourthPerson sp =  (SourthPerson) p ;        sp.eat() ;        sp.business() ;        System.out.println("------------------");        //测试北方人        Person p2 = new NorthPerson() ;        p2.eat() ;        NorthPerson np = (NorthPerson) p2 ;        np.yanJiu() ;    }}

抽象类

1.抽象类的概念:
每一个动物的吃和睡的功能不一样,不应该把动物类定义为一个具体类,而是给出一个声明(abstract).
当一个类中如果有抽象功能(抽象方法)的时候,那么这个类一定要定义为抽象类!

2.一个抽象类中可以有非抽象方法吗?
一个抽象类中可以抽象,也可以有非抽象的

3.抽象类不能实例化:抽象类不能创建对象
如何进行实例化:
通过抽象类多态形式.父类的引用指向子类对象,通过子类进行初始化

4.抽象类的子类的特点:
1)抽象类的子类是抽象类,那么没有意义!
(最终使用的就是通过子类进行对象初始化的,如果子类都被抽象修饰了,那么也不能创建对象,所以没意义)

5.抽象类多态:
强制子类必须重写当前抽象的父类中所有的抽象方法
还可以提高代码的维护性

6.演示:

abstract class Animal{    //抽象方法:没有方法体的一个方法    public abstract void eat() ;    public abstract void sleep() ;    //具体方法    /*public void eat(){        System.out.println("eat");    }*/    public void show(){        System.out.println("show Animal....");    }}//抽象的子类//abstract class Cat extends Animal{//  //}//子类是具体类class Cat extends Animal{    @Override    public void eat() {        System.out.println("猫吃鱼");    }    @Override    public void sleep() {        System.out.println("猫趴着睡觉..");    }}//测试类public class AbstractDemo {    public static void main(String[] args) {        //当前Animal已经被abstract修饰了//      Animal a = new Animal();//Cannot instantiate the type Animal:抽象类不能实例化:instaceof        //多态:父类引用指向子类对象        Animal a = new Cat() ; //Animal是抽象类,---->抽象类多态形式        a.eat() ;        a.sleep() ;    }}

7.抽象类的成员特点
1)成员变量:
可以是变量也可以是自定义常量
2)构造方法:
抽象类可以有构造方法:包括有参构造和无参构造
作用:通过抽象类多态的形式:让子类进行数据的初始化
3)成员方法:
可以有抽象方法,也可以有非抽象方法
抽象类的成员方法特性:
a.抽象方法:强制子类必须要做到一件事情:方法重写(覆盖)
b.非抽象方法:由继承保证可以去提高代码的复用性

8.演示

abstract class Fu{    private String name ;    private int age ;    //成员变量    public int num = 100 ;    public final int num2 = 200 ; //被final修饰:自定义常量    //无参构造    public Fu(){    }    //有参构造    public Fu(String name,int age){        this.name = name ;        this.age = age ;    }    //抽象方法    public abstract void show();    //非抽象方法    public void function(){        System.out.println("function Fu...");    }}//子类class Zi extends Fu{    @Override    public void show(){        System.out.println("show Zi....");    }}//测试类public class AbstractDemo2 {    public static void main(String[] args) {        //抽象类多态:        //抽象类的类名 对象名= new 子类名() ;        Fu f = new Zi() ;        f.show() ;        f.function() ;    }}

9.一个类中如果没有抽象方法,那么这个类可以定义为一个抽象类

10.abstract不能和哪些关键字共同使用?
private 和abstract\final和abstract\static和abstract不能共同使用

实际开发中:public 公共访问权限

10.演示:

abstract class Fu2{    //无参构造//  private Fu2(){//      //  }//  抽象方法    public abstract void show() ;    //非法修饰//  private abstract void function() ;    //非法修饰:编译不通过//  public final abstract void function() ;    //非法修饰//  public static abstract void function() ;}class Zi2 extends Fu2{    public void show(){        System.out.println("show Zi2....");    }}//测试类public class AbstractDemo3 {        public static void main(String[] args) {            //抽象类多态...创建对象        }}

接口

1.接口的概念:
接口体现的是一种扩展功能
比如:猫可以跳高(并不是所有的猫都具有跳高功能)

2.如何表示接口:
interface:接口 interface 接口名{
}

3.接口里面的方法只能是抽象方法
接口中不能有构造方法

4.接口的特点:
不能实例化(不能直接创建对象)

5.接口实例化:
通过子实现类对数据进行初始化
接口的子实现类:
1)接口的子实现类是抽象类,没有意义,子类都不能创建对象了;实际开发中用的就是子类的对象进行初始化!
2)接口的子实现类是非抽象类

6.接口的子实现类和接口的关系:implements

7.格式:
class 子实现类名 implments(实现) 接口名{

8.演示:

//定义跳高的接口interface Jump{    //非抽象方法:抽象类中不能有抽象方法//  public void jump(){//      System.out.println("猫可以跳高了...");//  }    public abstract  void  jump() ;    //构造方法:不能有//  public Jump(){//      //  }}//子实现类是抽象类类//abstract class Cat implements Jump{//子实现类是非抽象类class Cat implements Jump{    @Override    public void jump() {        System.out.println("猫可以跳高了...");    }}//测试类public class InterfaceDemo {    public static void main(String[] args) {        //创建接口对象//      Jump j = new Jump() ;//接口不能实例化        //接口多态:接口的引用指向子实现类对象        Jump j = new Cat() ;        j.jump();    }}

9.接口成员的特点:
1)成员变量:
只能是常量:存下默认修饰符:public static final (永远建议自己给出默认修饰符)
2)构造方法:
接口是没有构造方法的
3)成员方法:
接口中的成员方法默认修饰符:public abstract(永远建议自己给出默认修饰符)

10.演示

//定义一个接口interface Inter{    public static final int num = 100 ;    public static final  int num2 = 200 ;    //抽象方法//  public void show();//  void show() ;    //全部给出默认修饰符    public abstract void show() ;    //接口没有构造方法//  public Inter(){//      //  }    public abstract void function() ;}//定义接口的子实现类:见名知意:接口名+implclass InterImpl implements Inter{    @Override    public void show() {        System.out.println(num);        System.out.println(num2);    }    @Override    public void function() {        System.out.println("function InterImpl...");    }}//测试类public class InterfaceDemo2 {    public static void main(String[] args) {        //创建接口对象:接口多态的形式        Inter i = new InterImpl() ;//      i.num = 20 ;//当前num变量:被final修饰        System.out.println(Inter.num);//接口名.成员变量(当前变量被static修饰)        System.out.println(Inter.num2);        System.out.println("-------------");        i.show() ;        i.function() ;    }}

11.类与类的关系:
继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承!

12.类与接口的关系
实现关系:implements,并且,一个类在继承另一个类的同时,可以实现多个接口
(class 子实现类名 enxtends Object implements 接口名1,接口名2…)

13.接口与接口的关系
继承关系:extends,可以支持单继承,也可以多继承!

14.演示:

interface Inter2{}interface Inter3{}//接口与接口的关系:extendsinterface Zi extends Inter2{}interface Son extends Inter2,Inter3{}//子实现类class InterImpl2  extends Object implements Inter2,Inter3{}public class InterfaceDemo3 {}

15.面试题:接口和抽象类的区别?
1)成员的区别:
①成员变量:
抽象类:成员变量可以是常量,也可以是变量
接口:成员变量只能是一常量:存在默认修饰符:public static final
②构造方法:
抽象类:可以有无参构造,有参构造方法
作用:通过子类进行数据初始化(通过子类创建对象)
接口:没有构造方法的
③成员方法:
抽象类:可以有抽象方法,也可以有非抽象方法
接口:只能是抽象方法:存在默认修饰符:public abstract

2)关系的区别:
①类与类的关系:
继承关系:extends,java中只支持单继承,不支持多继承,但是可以多层继承!
②类与接口的关系:
实现关系:implements,并且,一个类在继承另一个类的同时,可以实现多个接口
(class 子实现类名 enxtends Object implements 接口名1,接口名2…)
③接口与接口的关系
继承关系:extends,可以支持单继承,也可以多继承!

3)设计理念的区别:
抽象类:
体现的是一种”is a”的关系,存在继承关系!(抽象类多态)
接口:
体现的是一种”like a”的关系,由于接口的一种扩展功能.

16.练习:

 /** * 猫狗案例,加入跳高的额外功能 *  分析:具体到抽象 *      猫: *          成员变量:姓名,年龄 *          构造方法:有参/无参 *          成员方法:setXXX()/getXXX() *              eat(),sleep() *          playGame() *      狗: *  *          成员变量:姓名,年龄 *          构造方法:有参/无参 *          成员方法:setXXX()/getXXX() *              eat(),sleep() *          lookDoor() *  * 抽取一个独立的类:动物类:Animal类:抽象类  eat();抽象功能 *  *      猫继承自Animal *      狗继承自Animal *  *      部分猫和狗具有跳高功能: *      接口: Jump *          跳高的抽象功能 *  * 实现:抽象-->具体 *  *   *           *       * */public class InterfaceTest {    public static void main(String[] args) {        //实现接口的类是最具体的类,里面的功能最多:创建该类对象        //测试类跳高猫        JumpingCat jc = new JumpingCat() ;        jc.setName("Tom") ;        jc.setAge(5) ;        String name = jc.getName() ;        System.out.println(name);//      System.out.println(jc.getName()+"---"+jc.getAge());        jc.eat() ;        jc.sleep() ;        jc.playGame() ;        jc.jump() ;        System.out.println("--------------------");        //通过有参构造进行数据初始化        jc = new JumpingCat("加菲猫", 5) ;        System.out.println(jc.getName()+"---"+jc.getAge());        jc.eat() ;        jc.sleep() ;        jc.playGame() ;        jc.jump() ;    }}
//动物的抽象类public abstract class Animal {    //成员变量    private String name ;    private int age ;    public Animal() {        super();    }    public Animal(String name, int age) {        super();        this.name = name;        this.age = age;    }    //setXXX/getXXX()    public String getName() {        return this.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("困了就需要休息...");    }}
public class Cat2 extends Animal {    public Cat2() {        super();    }    public Cat2(String name, int age) {        super(name, age);    }    @Override    public void eat() {        System.out.println("猫吃鱼...");    }    public void playGame(){        System.out.println("猫玩游戏....");    }}
//跳高接口public interface Jumping {    //抽象功能    public abstract void jump();}
//部分跳高猫首先应该是猫的一种,然后会跳高所以需要实现接口,重写里面的jump()方法public class JumpingCat extends Cat2 implements Jumping {    public JumpingCat() {        super();    }    public JumpingCat(String name, int age) {        super(name, age);    }    @Override    public void jump() {        System.out.println("猫可以跳高了...");    }}
原创粉丝点击