重新开始学习javase_多态(动态绑定、推迟绑定或者运行期绑定)

一,谈向上转换,或者上溯造型

  1. 什么是向上转换(上溯造型),一句话就是父类的引用指向子类的对象。或者把子类的对象当作父类来用
  2. 为什么要进行向上转换?我们先看一个例子吧!
    @Test
        public void test08() {
            Demo1_7_1 d=new Demo1_7_1();
            testDemo1_7_1(d);
        }
        public void testDemo1_7_1(Demo1_7_1 d){
            d.test1();
        }
    
    
    class Demo1_7{
        public void test1() {
            System.out.println("Demo1_7");
        }
    }
    class Demo1_7_1 extends Demo1_7{
        public void test1(){
            System.out.println("Demo1_7_1");
        }
    }
    testDemo1_7_1方法是入参为Demo1_7_1的,这个时候我需求发生变更,Demo1_7再加一个子类Demo1_7_2,那我是不是还需要弄一个testDemo1_7_2的方法呢?

    @Test
        public void test08() {
            Demo1_7_1 d=new Demo1_7_1();
            testDemo1_7_1(d);
            
            Demo1_7_2 d2=new Demo1_7_2();
            testDemo1_7_2(d2);
        }
        public void testDemo1_7_1(Demo1_7_1 d){
            d.test1();
        }
        public void testDemo1_7_2(Demo1_7_2 d){
            d.test1();
        }
    
    
    class Demo1_7{
        public void test1() {
            System.out.println("Demo1_7");
        }
    }
    class Demo1_7_1 extends Demo1_7{
        public void test1(){
            System.out.println("Demo1_7_1");
        }
    }
    class Demo1_7_2 extends Demo1_7{
        public void test1(){
            System.out.println("Demo1_7_1");
        }
    }
    View Code
     如果还有各多的子类呢?所以这个时候向上转型就很重要了,我们只需要这样做:把testDemo1_7_1中的入参类型向上转型成Demo1_7就行了
    @Test
        public void test08() {
            Demo1_7_1 d=new Demo1_7_1();
            testDemo1_7_1(d);
            
            Demo1_7_2 d2=new Demo1_7_2();
            testDemo1_7_1(d2);
        }
        public void testDemo1_7_1(Demo1_7 d){
            d.test1();
        }
        
    
    }
    class Demo1_7{
        public void test1() {
            System.out.println("Demo1_7");
        }
    }
    class Demo1_7_1 extends Demo1_7{
        public void test1(){
            System.out.println("Demo1_7_1");
        }
    }
    class Demo1_7_2 extends Demo1_7{
        public void test1(){
            System.out.println("Demo1_7_1");
        }
    }
    如果是这样的话,不管你有多少子类,我一个方法就是通用的。

二、再谈向上转型

  1. 怎么确定父类的句柄指向的哪个子类
    public void testDemo1_7_1(Demo1_7 d){
            d.test1();
        }

    解决的方法就是“后期绑定”,它意味着绑定在运行期间进行,以对象的类型为基础。后期绑定也叫作“动态绑定”或“运行期绑定”。若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。也就是说,编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。不同的语言对后期绑定的实现方法是有所区别的。但我们至少可以这样认为:
    它们都要在对象中安插某些特殊类型的信息。Java 中绑定的所有方法都采用后期绑定技术,除非一个方法已被声明成final。这意味着我们通常不必决定是否应进行后期绑定——它是自动发生的。
    为什么要把一个方法声明成final 呢?正如上一章指出的那样,它能防止其他人覆盖那个方法。但也许更重要的一点是,它可有效地“关闭”动态绑定,或者告诉编译器不需要进行动态绑定。这样一来,编译器就可为final 方法调用生成效率更高的代码

三,方法的重写:就是把父类中的方法重新定义一次以满足自己的业务需求,下面Demo1_7_1,Demo1_7_2中就是对Demo1_7方法的重写。

class Demo1_7{
    public void test1() {
        System.out.println("Demo1_7");
    }
}
class Demo1_7_1 extends Demo1_7{
    public void test1(){
        System.out.println("Demo1_7_1");
    }
}
class Demo1_7_2 extends Demo1_7{
    public void test1(){
        System.out.println("Demo1_7_1");
    }
}

下面是重写与重载的区别:

四,抽象类和方法

  1. 什么是抽象方法什么是抽象类?
    抽象方法即没有方法主体且用abstract关键字修辞的方法:public abstract void test();
  2. 什么是抽象类:含有抽象方法的类一定的抽象类:abstract class A{};被abstract修辞的类为抽象类
  3. 注意:抽象类不一定有抽象方法,有抽象方法的类一定的抽象类
  4. 当继承一个抽象类的时候必须实现抽象类中所有的抽象方法,或者将该类同样调用抽象类
    abstract class Demo2_7{
        public abstract void test1();
        public abstract void test2();
    }
    class Demo3_7 extends Demo2_7{
    
        @Override
        public void test1() {
            // TODO Auto-generated method stub        
        }
    
        @Override
        public void test2() {
            // TODO Auto-generated method stub        
        }
        
    }

     或者:

    abstract class Demo2_7{
        public abstract void test1();
        public abstract void test2();
    }
    abstract class Demo3_7 extends Demo2_7{
    
        @Override
        public void test1() {
            // TODO Auto-generated method stub        
        }
    
    }
  5. 抽象类有什么作用:
    当一个类只是来规定所有继承他的类的模板形式,且自己的实例化对象没有任何意义的时候,可以把这个类设为抽象类,就是它能为不同的子类型作出不同的表示。它为我们建立了一种基本形式,使我们能定义在所有衍生类里“通用”的一些东西。

五,接口(纯的抽象类)

“interface”(接口)关键字使抽象的概念更深入了一层。我们可将其想象为一个“纯”抽象类。它允许创建者规定一个类的基本形式:方法名、自变量列表以及返回类型,但不规定方法主体。接口也包含了基本数据类型的数据成员,但它们都默认为static 和final。接口只提供一种形式,并不提供实施的细节。接口这样描述自己:“对于实现我的所有类,看起来都应该象我现在这个样子”。因此,采用了一个特定接口的所有代码都知道对于那个接口可能会调用什么方法。这便是接口的全部含义。所以我们常把接口用于建立类和类之间的一个“协议”。有些面向对象的程序设计语言采用了一个名为“protocol”(协议)的关键字,它做的便是与接口相同的事情。为创建一个接口,请使用interface 关键字,而不要用 class。与类相似,我们可在 interface关键字的前
面增加一个 public关键字(但只有接口定义于同名的一个文件内);或者将其省略,营造一种“友好的”状态。

为了生成与一个特定的接口(或一组接口)相符的类,要使用 implements(实现)关键字。我们要表达的意思是“接口看起来就象那个样子,这儿是它具体的工作细节”。除这些之外,我们其他的工作都与继承极为相似。

六,抽象类和接口的区别(转:http://www.cnblogs.com/dolphin0520/p/3811437.html)

1.语法层面上的区别

  1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;

  2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;

  3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;

  4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

2.设计层面上的区别

  1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。

  2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

  下面看一个网上流传最广泛的例子:门和警报的例子:门都有open( )和close( )两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:

abstract class Door {
    public abstract void open();
    public abstract void close();
}

和:

interface Door {
    public abstract void open();
    public abstract void close();
}

但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:

  1)将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;

  2)将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。

  从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。

interface Alram {
    void alarm();
}
 
abstract class Door {
    void open();
    void close();
}
 
class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}

七,接口(interface的拓展)----通过接口之间的继承

interface Demo4_7{
    void method1();
}

interface Demo5_7 extends Demo4_7{
    void method2();
}

class Demo6_7 implements Demo5_7{
    @Override
    public void method1() {
        // TODO Auto-generated method stub        
    }

    @Override
    public void method2() {
        // TODO Auto-generated method stub        
    }
}

 

原文地址:https://www.cnblogs.com/wangyang108/p/5794919.html