黑马程序员技术交流社区

标题: 抽象类_多态_接口(细节及其总结) [打印本页]

作者: 曾乐祥    时间: 2016-6-25 22:27
标题: 抽象类_多态_接口(细节及其总结)
【抽象类的特点】
1,抽象类和抽象方法都需要被abstract修饰。
抽象方法一定要定义在抽象类中。
2,抽象类不可以创建实例,原因:调用抽象方法没有意义。
3,只有覆盖了抽象类中所有的抽象方法后,其子类才可以实例化。
否则该子类还是一个抽象类。


之所以继承,更多的是在思想,是面对共性类型操作会更简单。


【细节问题】
1,抽象类一定是个父类?        
        是的,因为不断抽取而来的。

2,抽象类是否有构造函数?
        有,虽然不能给自己的对象初始化,但是可以给自己的子类对象初始化。
        抽象类和一般类的异同点:
        相同:
                1,它们都是用来描述事物的。
                2,它们之中都可以定义属性和行为。

        不同:
                1,一般类可以具体的描述事物。
                        抽象类描述事物的信息不具体
                2,抽象类中可以多定义一个成员:抽象函数。
                3,一般类可以创建对象,而抽象类不能创建对象。

3,抽象类中是否可以不定义抽象方法。
        是可以的,那这个抽象类的存在到底有什么意义呢?仅仅是不让该类创建对象。


4,抽象关键字abstract不可以和哪些关键字共存?        
        1,final:
        2,private:
        3,static:

【final关键字】
是一个修饰符,可以修饰类,方法,变量(成员变量,局部变量,静态变量)。
【特点】
1,final修饰的类是一个最终类,不能在派生子类。
如果类中从出现部分可以重写,部分不可以?怎么办?只要让指定的方法最终化就可以了。
2,final修饰的方法是最终方法,不可以给重写。
3,final修饰的变量是一个常量,只能被赋值一次。
【什么时候会在程序中定义final常量呢?】
当程序中一个数据使用时是固定不变的,这时为了增加阅读性,可以该该数据起个名字。
这就是变量,为了保证这个变量的值不被修改,加上final修饰,这就一个阅读性很强的常量。
书写规范,被final修饰的常量名所有的字母都是大写的。如果由多个单词组成单词间通过 _ 连接。

接口中的成员已经被限定为固定的几种。
【接口的定义格式先介绍两种:】
1,定义变量,但是变量必须有固定的修饰符修饰,public static final 所以接口中的变量也称之为常量。
2,定义方法,方法也有固定的修饰符,public abstract
接口中的成员都是公共的。

【接口的特点】
1,接口不可以创建对象。
2,子类必须覆盖掉接口中所有的抽象方法后,子类才可以实例化。
        否则子类是一个抽象类。
定义子类去覆盖接口中的方法。子类必须和接口产生关系,类与类的关系是继承,类与接口之间的关系是 实现。通过 关键字 implements

【接口最重要的体现】
解决多继承的弊端。将多继承这种机制在java中通过多实现完成了。

【怎么解决多继承的弊端呢?】
弊端:多继承时,当多个父类中有相同功能时,子类调用会产生不确定性。
其实核心原因就是在于多继承父类中功能有主体,而导致调用运行时,不确定运行哪个主体内容。
为什么多实现就解决了呢?
因为接口中的功能都没有方法体,由子类来明确。

【基于接口的扩展。】
子类通过继承父类扩展功能,通过继承扩展的功能都是子类应该具备的基础功能。
如果子类想要继续扩展其他类中的功能呢?这时通过实现接口来完成。

接口的出现避免了单继承的局限性。
父类中定义的事物的基本功能。
接口中定义的事物的扩展功能。

【接口出现后的一些小细节】
1,类与类之间是继承(is a)关系,类与接口之间是实现(like a)关系,
        接口与接口之间是继承关系,而且可以多继承。

多态:
        【体现】
                父类的引用或者接口的引用指向了自己的子类对象。
                Dog d = new Dog();//Dog对象的类型是Dog类型。
                Animal a = new Dog();//Dog对象的类型右边是Dog类型,左边Animal类型。
        【好处】
                提高了程序的扩展性。
        【弊端】
                通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。
        【前提】
                1,必须有关系:继承,实现。
                2,通常都有重写操作。
        【子类的特有方法如何调用呢?】
        Animal a = new Dog();//Animal是父类型,new Dog()是子对象。
        但是父类型引用指向子类对象时,这就是让子类对象进行了类型的提升(向上转型)。
        向上转型好处:提高了扩展性,隐藏了子类型。弊端:不能使用子类型的特有方法。
        如果要想使用子类的特有方法,只有子类型可以用。
        可以向下转型,强制转换。
        Animal a = new Dog();
        a.eat();
        Dog d = (Dog)a;//将a转型为Dog类型。向下转型。
        d.lookHome();
        向下转型什么时候用?当需要使用子类型的特有内容时。
        
        注意:无论向上还是向下转型,最终都是子类对象做着类型的变化。
        
        【向下转型的注意事项】
        Animal a = new Dog();
        //Cat c = (Cat)a;向下转型因为不明确具体子类对象类型,所以容易引发ClassCastException异常。
        所以为了避免这个问题,需要在向下转型前,做类型的判断。
        判断类型用的是关键字 instanceof
        if(a instanceof Cat)//a指向的对象的类型是Cat类型。
        {
                //将a转型Cat类型。
                Cat c = (Cat)a;
                c.catchMouse();
        }
        else if(a instanceof Dog)
        {
                Dog d = (Dog)a;
                d.lookHome();
        }

        【转型总结】
        1,什么时候使用向上转型呢?
                提高程序的扩展性,不关系子类型(子类型被隐藏)。
                需要用子类的特有方法吗?不需要,哦了。向上转型。
        2,什么时候使用向下转型呢?
                需要使用子类型的特有方法时。
                但是一定要使用 instanceof 进行类型的判断。避免发生 ClassCastException
多态中,成员调用的特点。

1,成员变量。
        当子父类中出现同名的成员变量时。
                多态调用该变量时:
                        编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
                        运行时期:也是调用引用型变量所属的类中的成员变量。
                简单记:编译和运行都参考等号的左边。
                                编译运行看左边。

2,成员函数。
        编译,参考左边,如果没有,编译失败。
        运行,参考右边的对象所属的类。
                编译看左边,运行看右边。
        
        对于成员函数是动态绑定到对象上。

3,静态函数。
        编译和运行都参考左边。

        静态函数是静态的绑定到类上。


【结论】
对于成员变量和静态函数,编译和运行都看左边。
对于成员函数,编译看左边,运行看右边。





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2