博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java多态
阅读量:6942 次
发布时间:2019-06-27

本文共 16281 字,大约阅读时间需要 54 分钟。

一.多态概念 

  注: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      * 使用instanceof22      */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     @Override10     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     @Override12     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     @Override12     public void connection() {13         System.out.println("我自己的collection方法 ");14     }15     @Override16     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文件命名:外部类$内部类.class20      */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 stub24         /*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             @Override41             public void read() {42                 // TODO Auto-generated method stub43                 System.out.println("我是匿名内部类");44                 45             }46         });47         48 49     }50 51 }
View Code

 

 

    

 

转载于:https://www.cnblogs.com/lyq-biu/p/10696800.html

你可能感兴趣的文章
使用智能DNS与多线路由解决教育网服务器费用难题
查看>>
SQL Server 2012 AlwaysOn高可用配置之五:配置仲裁
查看>>
Powershell管理系列(三十九)PowerShell查询和解锁AD账号
查看>>
【实战虚拟化】安全设计之一基本架构
查看>>
LINUX下查看CPU负载的vmstat命令
查看>>
linux里shell中的test代表的意义
查看>>
【VMCloud云平台】SCOM配置(六)-应用深度监控
查看>>
解析linux下磁盘乱序的问题
查看>>
Excel图表之道一突破常规
查看>>
是什么浪费了我工作的时间
查看>>
四大超能力加持,京东家电双11效率致胜
查看>>
关于Golang语言的web编程的实例及常见问题
查看>>
JDK5.0新特性(2)-注解(Annotation)
查看>>
C# 中的委托和事件
查看>>
代替Runas,自动输入密码
查看>>
老师的斐波那契数列算法
查看>>
AutoLISP图像控件Image应用示例
查看>>
MVVM中的命令绑定及命令参数
查看>>
动态加载JS脚本【转】
查看>>
单元测试
查看>>