zoukankan      html  css  js  c++  java
  • Java多态

    一.多态概念 

      注:Python支持多态(同样还有鸭子类型【可以不必继承重写方法,只要方法名相同,动态语言的特性】)

      意味着允许不同类的对象对同一信息做出不同的反应。

      分类:

          编译时多态:设计时多态,方法重载

          运行时多态:程序运行时动态决定调用哪个方法

      Java多态必要条件:

          满足继承关系;

          父类引用指向子类对象

    二.向上转型和向下转型

      1.向上转型(隐式转型/自动转型):

        父类引用指向子类实例,可以调用子类重写父类的方法以及父类派生的方法,无法调用子类独有的方法【小类转型为大类】

        注意:父类中的静态方法无法被子类重写,所以向上转型之后,只有调用父类原有的静态方法(如果想调用子类的静态方法就得向下转型)

       2.向下转型(强制类型转换):

         子类引用指向父类对象,此处必须进行强转,可以调用子类特有的方法【 必须满足转换条件才能进行强制转换】

     1 package com.swpu.test;
     2 
     3 import com.swpu.plo.Animal;
     4 import com.swpu.plo.Cat;
     5 import com.swpu.plo.Dog;
     6 
     7 public class Test {
     8 
     9     public static void main(String[] args) {
    10         /**
    11          * 向上转型,隐式转型,自动转型
    12          * 父类引用指向子类实例,可以调用子类重写父类的方法以及父类派生的方法,无法调用子类独有的方法
    13          * 【小类转型为大类】
    14          */
    15         Animal one =new Animal();
    16         Animal two=new Cat();
    17         Animal three=new Dog();
    18         one.eat();
    19         //无法调用Cat和Dog独有的方法
    20         two.eat();
    21         three.eat();
    22         /**
    23          * 输出:
    24          * 所有的动物都要吃东西
    25                小猫吃东西!!!
    26                狗吃东西!!!
    27 
    28          */
    29         System.out.println("**************");
    30         
    31         /**
    32          * 向下转型,强制类型转换
    33          * 子类引用指向父类对象,此处必须进行强转,可以调用子类特有的方法
    34          * 必须满足转换条件才能进行强制转换
    35          */
    36         Cat tmp=(Cat)two;
    37         tmp.eat();
    38         tmp.run();
    39         //会报错,Cat和Dog没有关系,能转换为Cat是因为two原来指向的就是Cat空间【相当于还原】
    40 //        Cat tmp2 =(Dog)two;
    41         
    42         
    43 
    44     }
    45 
    46 }
    View Code

       3.instanceof:判断对象是否是某个类的实例

        注:相当于Python中的isinstance方法(会检查继承链,肯定是所实例类的对象实例,也是其所继承类的实例),而Python中type只判断是否指向同一个对象(不会检查继承链)

        

        

     1     if(two instanceof Cat){
     2             Cat tmp=(Cat)two;
     3             tmp.eat();
     4             tmp.run();
     5             System.out.println("我是猫对象");
     6         }
     7         
     8         if (two instanceof Dog){
     9             Dog tmp=(Dog)two;
    10             tmp.eat();
    11             tmp.sleep();
    12             System.out.println("我是狗对象");
    13         }
    14         if (two instanceof Animal){
    15             System.out.println("我是Animal对象");
    16 
    17             
    18         }
    19         if (two instanceof Object){
    20             System.out.println("我是Object对象");
    21 
    22         }
    23         /*输出:
    24          *  小猫吃东西!!!
    25             小猫跑步~~~
    26             我是猫对象
    27             我是Animal对象
    28             我是Object对象
    29 
    30          */
    31                 
    32         
    View Code

       4.类型转换总结:

       

        注意:父类的静态方法不能在子类中被重写,可以同名(但是不构成重写,是子类特有的静态方法)

      5.instanceof使用例子:

     1 package com.swpu.plo;
     2 
     3 public class Master {
     4     /**
     5      * 猫:吃完东西就跑
     6      * 狗:吃完东西就睡觉
     7      * 如果有很多动物,则需要一直重载方法
     8      */
     9     //方案一:编写方法,传入不同类型得动物,调用各自的方法
    10 //    public void feed(Cat cat){
    11 //        
    12 //        cat.eat();
    13 //        cat.run();
    14 //    }
    15 //    public void feed(Dog dog){
    16 //            
    17 //        dog.eat();
    18 //        dog.sleep();
    19 //        }
    20     /**
    21      * 使用instanceof
    22      */
    23     //方案二:编写方法传入动物的父类,方法中通过类型的转换,调用指定子类的方法
    24     //视情况用不同的方案
    25     public void feed(Animal obj){
    26         obj.eat();
    27         if(obj instanceof Cat){
    28             Cat tmp=(Cat)obj;
    29             //tmp.eat();
    30             tmp.run();
    31         }
    32         else if(obj instanceof Dog){
    33             Dog tmp=(Dog)obj;
    34             //tmp.eat();
    35             tmp.sleep();
    36         }
    37     }
    38     
    39     /**
    40      * 饲养何种动物
    41      * 时间多:养狗
    42      * 时间少:养猫
    43      */
    44     //方案一
    45     public Dog hasManytime(){
    46         System.out.println("时间多,养狗");
    47         return new Dog();
    48     }
    49     public Cat hasLittletime(){
    50         System.out.println("时间少,养猫");
    51         return new Cat();
    52     }
    53     //方案二
    54     public Animal raise(boolean haManyTime){
    55         if(haManyTime){
    56             System.out.println("时间多,养狗");
    57             return new Dog();
    58         }
    59         else{
    60             System.out.println("时间少,养猫");
    61             return new Cat();
    62         }
    63     }
    64 }
    View Code
     1 package com.swpu.test;
     2 
     3 import com.swpu.plo.Animal;
     4 import com.swpu.plo.Cat;
     5 import com.swpu.plo.Dog;
     6 import com.swpu.plo.Master;
     7 
     8 public class MasterTest {
     9 
    10     public static void main(String[] args) {
    11         Cat cat=new Cat();
    12         Dog dog=new Dog();
    13         Master master=new Master();
    14         master.feed(cat);
    15         master.feed(dog);
    16         System.out.println("**************");
    17         boolean hasManyTime=true;
    18 //        if(hasManyTime){
    19 //            master.hasManytime();
    20 //        }
    21 //        else{
    22 //            master.hasLittletime();
    23 //        }
    24         Animal tmp=master.raise(hasManyTime);
    25         
    26         
    27 
    28     }
    29 
    30 }
    View Code

     三.抽象类和抽象方法

      1.抽象类:加关键字abstract

        不允许实例化,可以通过向上转型指向子类实例。

        注:Python中使用abc模块实现抽象基类和抽象方法,但是抽象基类仍然可以是实例化,但抽象方法必须被重写。

        

     无法调用抽象类Animal(如果要用,可以向上转型,Animal one=new Cat();)

      2.抽象方法: 

        不允许包含方法体且抽象方法需要在抽象类中,子类当中需要重写父类的方法,否则子类也是抽象类。 

      3.总结:

        abstract定义抽象类;

        抽象类不能直接实例化,只能被继承,可以通过向上转型完成对象实例;

        abstract定义抽象方法,不需要具体实现;

        包含抽象方法的类是抽象类;

        抽象类中可以没有抽象方法;

        static(不允许子类重写),final(最终得,不能改变),private(私有的,只能当前类使用)不能和abstract并存。

     四.接口

      如电脑,手机,只能表都有照相的功能,如果分别写,则需要给每个类定义照相的方法。

      1.定义接口并测试:

        建立关系,把接口引用指向实现类的方式,从而完成不同的功能

        1.1接口定义:

    1 package com.swpu.photos;
    2 //定义接口
    3 public interface Iphoto {
    4     //具有照相功能
    5     public void photo();
    6 
    7 }
    View Code

        1.2重写接口方法:

     1 package com.swpu.photos;
     2 
     3 public class Computer implements Iphoto {
     4     public void game() {
     5         System.out.println("电脑可以玩游戏");
     6 
     7     }
     8 
     9     @Override
    10     public void photo() {
    11         System.out.println("电脑也可以照相");
    12 
    13     }
    14 }
    View Code
     1 package com.swpu.photos;
     2 
     3 public class Phone implements Iphoto{
     4     public void phone(){
     5         System.out.println("手机可以打电话");
     6     }
     7     @Override
     8     public void photo() {
     9         System.out.println("手机可以照相");
    10         
    11     }
    12 }
    View Code
     1 package com.swpu.photos;
     2 
     3 public class Watch implements Iphoto{
     4     public void times() {
     5         System.out.println("智能手表可以看时间");
     6         
     7     }
     8     @Override
     9     public void photo() {
    10         System.out.println("智能手表也可以照相");
    11         
    12     }
    13 
    14 }
    View Code

        1.3测试:

    package com.swpu.test;
    
    import com.swpu.photos.Computer;
    import com.swpu.photos.Iphoto;
    import com.swpu.photos.Phone;
    import com.swpu.photos.Watch;
    
    public class Test1 {
        public static void main(String[] args){
            Iphoto ip=new Phone();
            ip.photo();
            ip =new Computer();
            ip.photo();
            ip=new Watch();
            ip.photo();
        }
        
    
    }
    /**
     * 输出:
     *  手机可以照相
        电脑也可以照相
        智能手表也可以照相
    **/
    View Code

      2.接口成员:

        2.1接口规则:

          接口定义了某一批类所需要遵守的规范;

          接口不关心这些类的内部数据,也不关心这些类里的方法的实现细节,它只规定这些类里必须提供什么方法。 

          注:

            接口最好以I开头【规范】,接口访问修饰符只能是public或者是默认的;

            接口当中抽象方法可以不写abstract关键字,修饰符可以不写public【默认也会使用public】;

            当类实现接口时,需要去实现接口中的所有抽象方法,否则可以将类定义为抽象类不重写,继续延续下去;

            接口中可以定义常量 ,默认public static final,可以用接口名(引用)加常量直接访问(INet.TMP);

            如果实现类和接口中的有同名的常量,如果是接口引用指向实现类,调用的是接口的常量,如果是实现类引用指向实现类实例,则是实现类中的常量   

     1 package com.swpu.photos;
     2 
     3 //接口最好以I开头【规范】,接口访问修饰符只能是public或者是默认的
     4 public interface INet {
     5     // 接口当中抽象方法可以不写abstract关键字,修饰符可以不写public【默认也会使用public】
     6     // 当类实现接口时,需要去实现接口中的所有抽象方法,否则可以将类定义为抽象类不重写,继续延续下去
     7     public void net();
     8     public void connection();
     9 
    10     // 接口中可以定义常量 ,默认public static final,可以用接口名(引用)加常量直接访问(INet.TMP)
    11     // 如果实现类和接口中的有同名的常量,如果是接口引用指向实现类,调用的是接口的常量,如果是实现类引用指向实现类实例,则是实现类中的常量
    12     int TMP = 20;
    13 }
    View Code

       3.默认方法和静态方法:

        3.1默认方法:  

          default:默认方法 可以带方法体 JDK1.8后新增;
          可以在实现类中重写,并可以通过接口的引用调用。

        3.2静态方法:    

          static:静态方法 可以带方法体 JDK1.8后新增;
          不可以在实现类中重写,可以使用接口名调用。

        3.3例:  

     1 package com.swpu.photos;
     2 
     3 //接口最好以I开头【规范】,接口访问修饰符只能是public或者是默认的
     4 public interface INet {
     5     // 接口当中抽象方法可以不写abstract关键字,修饰符可以不写public【默认也会使用public】
     6     // 当类实现接口时,需要去实现接口中的所有抽象方法,否则可以将类定义为抽象类不重写,继续延续下去
     7     public void net();
     8 
     9     // 接口中可以定义常量 ,默认public static final,可以用接口名(引用)加常量直接访问(INet.TMP)
    10     // 如果实现类和接口中的有同名的常量,如果是接口引用指向实现类,调用的是接口的常量,如果是实现类引用指向实现类实例,则是实现类中的常量
    11     int TMP = 20;
    12     //default:默认方法  可以带方法体 JDK1.8后新增
    13     //可以在实现类中重写,并可以通过接口的引用调用
    14     default void connection(){
    15         System.out.println("我是接口中的默认方法");
    16     }
    17     //static:静态方法 可以带方法体  JDK1.8后新增
    18     //不可以在实现类中重写,可以使用接口名调用
    19     static void stop(){
    20         System.out.println("我是接口中的静态方法");
    21     }
    22 }
    View Code
     1 package com.swpu.photos;
     2 
     3 public class Phone implements INet{
     4     public void phone(){
     5         System.out.println("手机可以打电话");
     6     }
     7     @Override
     8     public void net() {
     9         System.out.println("手机能上网");
    10     }
    11     @Override
    12     public void connection() {
    13         INet.super.connection();//调用接口中默认方法
    14     }
    15     
    16     
    17 }
    View Code

         3.4处理多接口同名的默认方法:

          需要在子类中重写同名方法。

     1 package com.swpu.photos;
     2 
     3 //接口最好以I开头【规范】,接口访问修饰符只能是public或者是默认的
     4 public interface INet {
     5     // 接口当中抽象方法可以不写abstract关键字,修饰符可以不写public【默认也会使用public】
     6     // 当类实现接口时,需要去实现接口中的所有抽象方法,否则可以将类定义为抽象类不重写,继续延续下去
     7     public void net();
     8 
     9     // 接口中可以定义常量 ,默认public static final,可以用接口名(引用)加常量直接访问(INet.TMP)
    10     // 如果实现类和接口中的有同名的常量,如果是接口引用指向实现类,调用的是接口的常量,如果是实现类引用指向实现类实例,则是实现类中的常量
    11     int TMP = 20;
    12     //default:默认方法  可以带方法体 JDK1.8后新增
    13     //可以在实现类中重写,并可以通过接口的引用调用
    14     default void connection(){
    15         System.out.println("我是INet接口中的默认方法");
    16     }
    17     //static:静态方法 可以带方法体  JDK1.8后新增
    18     //不可以在实现类中重写,可以使用接口名调用
    19     static void stop(){
    20         System.out.println("我是接口中的静态方法");
    21     }
    22 }
    View Code
     1 package com.swpu.photos;
     2 //定义接口
     3 public interface Iphoto {
     4     //具有照相功能
     5     public void photo();
     6     default void connection(){
     7         System.out.println("我是Iphoto接口中的默认方法");
     8     }
     9 
    10 
    11 }
    View Code
     1 package com.swpu.photos;
     2 
     3 public class Phone implements INet,Iphoto{
     4     public void phone(){
     5         System.out.println("手机可以打电话");
     6     }
     7     @Override
     8     public void net() {
     9         System.out.println("我是INet接口中的方法,手机能上网");
    10     }
    11     @Override
    12     public void connection() {
    13         System.out.println("我自己的collection方法 ");
    14     }
    15     @Override
    16     public void photo() {
    17         System.out.println("我是Iphoto接口中的方法,我可以照相");
    18         
    19     }
    20     
    21     
    22 }
    View Code

        3.5注:

          可以继承加实现接口(注继承要在实现类前,如public class Phone extends Tel implements IPhoto,INet(){},只能继承一个类,当可以实现多个接口)

          如果继承的类里面和实现的接口里面有同名的方法,默认指向父类当中的方法。

        3.6处理多接口同名的常量:

          需要明确表明是哪个接口中的常量。

     1 package com.swpu.test;
     2 interface one{
     3     static int x=10;
     4 }
     5 interface two{
     6     static int x=20;
     7 }
     8 
     9 public class Test2 implements one,two{
    10     public void test(){
    11         System.out.println(one.x);
    12         System.out.println(two.x);
    13     }
    14     public static void main(String[] args){
    15         new Test2().test();
    16     }
    17 
    18 }
    View Code

           如果继承的类里面和实现的接口有同名的常量:无法像同名方法那样默认为父类,需要自己在实现类中从新定义常量才不会报错。

      4.接口的继承:

         接口的继承可以继承多个接口,如果有重名的默认方法,需要在子接口中自定义。 

    1 package com.swpu.photos;
    2 
    3 public interface ISon extends IFather1,IFather2{
    4     void fly();
    5     void run();
    6 }
    View Code

     五.内部类

      1.含义:

        在Java中,可以将一个类定义在另一个类里面或者方法里面,这样的类被称为内部类。与之对应,包含内部类的类被称为外部类。

      2.作用:

        内部类隐藏在外部类之内,更好的实现消息隐藏。

      3.内部类分类:

        成员内部类;静态内部类;方法内部类;匿名内部类

        3.1成员内部类:

          内部类中最常见的,也成为普通内部类。

     1 package com.swpu.people;
     2 //外部类
     3 public class Person {
     4     int age;
     5     public Heart getheart(){
     6 
     7         return new Heart();
     8     }
     9     public void eat(){
    10         System.out.println("吃东西");
    11     }
    12     //成员内部类
    13     /*
    14      * 1.内部类在外部使用时,无法直接实例化,需要借由外部信息才能完成实例化;
    15      * 2.内部类的访问修饰符可以任意。但是访问范围会受到影响;
    16      * 3.内部类可以直接访问外部类的成员;如果出现同名的属性,优先访问内部类定义的;
    17      * 4.可以通过外部类.this.成员的方式,访问外部类中同名的信息;
    18      * 5.外部类访问内部类信息,需要通过内部类实例,无法直接访问;
    19      * 6.内部类编译后.class文件命名:外部类$内部类.class
    20      */
    21     class Heart{
    22         public void eat(){
    23             System.out.println("我是内部类里的吃东西");
    24         }
    25         public String beat(){
    26             //调用外部类的eat方法
    27             Person.this.eat();
    28             return age+"heart is running";
    29         }
    30     }
    31 
    32 }
    View Code
     1 package com.swpu.people;
     2 
     3 public class PeopleTest {
     4 
     5     public static void main(String[] args){
     6         Person p1=new Person();
     7         p1.age=15;
     8         /**
     9          * 获取内部类对象实例:
    10          *     方式一:new 外部类.new 内部类
    11          * 
    12          */
    13         Person.Heart heart=new Person().new Heart();
    14         System.out.println(heart.beat());
    15         //方式二:外部类对象.new 内部类
    16         heart =p1.new Heart(); 
    17         System.out.println(heart.beat());
    18         //方式三:外部类对象.获取方法
    19         heart =p1.getheart();
    20         System.out.println(heart.beat());
    21 
    22     }
    23 }
    View Code

        3.2静态内部类:

          静态内部类对象可以不依赖于外部类对象直接创建。

     1 package com.swpu.people;
     2 //外部类
     3 public class Person {
     4     int age;
     5     public Heart getheart(){
     6 
     7         return new Heart();
     8     }
     9     public void eat(){
    10         System.out.println("吃东西");
    11     }
    12     /*
    13      * 静态内部类:
    14      *     1.静态内部类中,只能直接访问外部类的静态方法,如果需要调用非静态方法可以通过对象实例调用
    15      */
    16     static class Heart{
    17         static void say(){
    18             System.out.println("Hello");
    19         }
    20         public String beat(){
    21             //调用外部类的eat方法
    22             new Person().eat();
    23             return new Person().age+"heart is running";
    24         }
    25     }
    26 
    27 }
    View Code
    package com.swpu.people;
    
    public class PeopleTest {
    
        public static void main(String[] args){
            Person p1=new Person();
            p1.age=15;
            /*
             * 获取静态内部类实例的方法:
             *     1.静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例;
             *  2.静态内部类对象实例时,可以不依赖于外部类对象;
             *  3.可以通过外部类.内部类.静态成员的方式,访问内部类的静态成员;
             *  4.当内部类属性与外部类属性同名时,默认直接调用内部类中的成员;
             *      如果需要访问外部类中的静态属性,则可以通过   外部类.属性   的方式
             *      如果需要访问外部类中的非静态属性,则可以通过   new 外部类().属性   的方式
             * 
             */
            Person.Heart heart=new Person.Heart();
            System.out.println(heart.beat());
            Person.Heart.say();
        }
    }
    View Code

        3.3方法内部类:

          定义在外部类方法中的内部类,也称局部内部类。

     1 package com.swpu.people;
     2 //外部类
     3 public class Person {
     4     int age;
     5     public void eat(){
     6         System.out.println("吃东西");
     7     }
     8     
     9     public Object getheart(){
    10         /*
    11          * 方法内部类:
    12          *     1.定义在方法内部,作用范围也在方法内;
    13          *     2.和方法内部成员使用规则一样,class前面不能加public,private,protected,static;
    14          *     3.类中不能包含静态成员’
    15          *     4.类中可以包含final,abstract修饰的成员(不推荐)
    16          * 
    17          */
    18        class Heart{
    19             public void say(){
    20                 System.out.println("Hello");
    21             }
    22             public String beat(){
    23                 //调用外部类的eat方法
    24                 new Person().eat();
    25                 return new Person().age+"heart is running";
    26             }
    27     }
    28     return new Heart().beat();
    29  
    30     }
    31 
    32 }
    View Code
     1 package com.swpu.people;
     2 
     3 public class PeopleTest {
     4 
     5     public static void main(String[] args){
     6         Person p1=new Person();
     7         p1.age=15;
     8         /*
     9          * 获取方法内部类
    10          */
    11         System.out.println(p1.getheart());
    12     }
    13 }
    View Code

        3.4匿名内部类:

          没有名字,将类的定义和创建一起完成(如果只用一次可以这样,对系统内存消耗相对较小)

     1 package com.swpu.test;
     2 
     3 import com.swpu.people.Man;
     4 import com.swpu.people.Person;
     5 import com.swpu.people.Woman;
     6 
     7 public class PersonTest {
     8     //方案一
     9     /*
    10     public void getRead(Man man){
    11         man.read();
    12     }
    13     public void getRead(Woman woman){
    14         woman.read();
    15     }
    16     */
    17     //方案二
    18     public void getRead(Person p){
    19         p.read();
    20     }
    21     public static void main(String[] args) {
    22         PersonTest p1=new PersonTest();
    23         // TODO Auto-generated method stub
    24         /*
    25         Man man=new Man();
    26         Woman woman =new Woman();
    27         p1.getRead(man);
    28         p1.getRead(woman);
    29         */
    30         //匿名内部类
    31         /*
    32          * 1.匿名内部类没有类型名称,实例对象名称;
    33          * 2.编译后的文件命名:外部类$数字.class;
    34          * 3.无法使用private/public/protected/adstract/static等;
    35          * 4.无法在匿名内部类编写构造方法,可以添加构造代码块;
    36          * 5.不能出现静态成员
    37          * 6.匿名内部类可以继承父类,也可以实现接口(但是不能同时实现)
    38          */
    39         p1.getRead(new Person(){
    40             @Override
    41             public void read() {
    42                 // TODO Auto-generated method stub
    43                 System.out.println("我是匿名内部类");
    44                 
    45             }
    46         });
    47         
    48 
    49     }
    50 
    51 }
    View Code

        

  • 相关阅读:
    jQuery Deferred和Promise的使用介绍:
    asp.net客户端IP跟踪
    jquery常用的一些方法
    前端音频流播放
    c# Http请求下载二进制流文件
    iView表格行验证问题
    【已解决】Https请求—未能创建 SSL/TLS 安全通道
    安全开发规范
    数据库设计规范
    高性能开发规范
  • 原文地址:https://www.cnblogs.com/lyq-biu/p/10696800.html
Copyright © 2011-2022 走看看