zoukankan      html  css  js  c++  java
  • 面向对象之多态

       多态:可以理解为事物存在的多种体现形态。

       例如:人:男人,女人;

               动物:猫,狗

               猫 x = new 猫();

               动物 x = new 猫();

       从以下几个方面介绍多态:

    1. 多态的体现——父类的引用指向了自己的子类对象。父类的引用也可以接收自己的子类对象
    2. 多态的前提——必须是类与类之间有关系,要么继承,要么实现。通常还有一个前提:存在覆盖
    3. 多态的好处——多态的出现大大的提高了程序的扩展性
    4. 多态的弊端——提高了扩展性,但是只能使用父类的引用访问父类中的成员,不能预先使用子类,因为那时子类还没存在
    5. 多态的应用
    6. 多态的出现在代码中的特点(多态使用的注意事项)

       以动物:猫,狗,猪为例说之

    abstract class Animal {
        public abstract void eat();
    }
    class Cat extends Animal {
        public void eat() {
            System.out.println("吃鱼");
        }
        public void catchMouse() {
            System.out.println("抓老鼠");
        }
    }
    class Dog extends Animal {
        public void eat() {
            System.out.println("吃骨头");
        }
        public void KanJia() {
            System.out.println("看家");
        }
    }
    class Pig extends Animal {
        public void eat() {
            System.out.println("饲料");
        }
        public void gongDi() {
            System.out.println("拱地");
        }
    }
    //-----------------------------------------------------------
    public class PolDemo {
    
        public static void main(String[] args) {
    //        Cat c = new Cat();
    //        c.eat();
    //        
    //        Dog d = new Dog();
    //        d.eat();
    //        Cat c = new Cat();
    //        function(c);
    //        
    //        function(new Dog());
    //        
    //        function(new Pig());
            
    //        Animal c = new Cat();
    //        c.eat();
            
            Animal a = new Cat();//类型提升。向上转型
            a.eat();
            
            //如果想要调用猫的特有方法时,如何操作?
            //强制将父类的引用转成子类类型,向下转型
            Cat c = (Cat)a;
            c.catchMouse();
            
            /*
             * 千万不要出现这样的操作,就是将父类对象转成子类类型
             * 我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换
             * 多态自始至终都是子类对象在做着变化
             * Animal a = new Animal();
             * Cat c = (Cat)a;
             * 
             */
    //        function(new Cat());
    //        function(new Dog());
    //        function(new Pig());
            
        }
        
        public static void function(Animal a) { //Animal a = new Cat();
            a.eat();
    //        a.catchMouse();
            /*if(a instanceof Animal) {
                System.out.println("hello");
            } else*/ if(a instanceof Cat) {
                Cat c = (Cat)a;
                c.catchMouse();
            } else if(a instanceof Dog) {
                Dog d = (Dog)a;
                d.KanJia();
            }
            
        }
        /*
        public static void function(Cat c) { //Cat c = new Cat();
            c.eat();
        }
        
        public static void function(Dog d) {
            d.eat();
        }
        
        public static void function(Pig p) {
            p.eat();
        }
        */
    }

       以下例说明多态的应用:

       基础班学生:学习,睡觉

       高级班学生:学习,睡觉

       可以将这两类事物进行抽取。

       代码如下:

    abstract class Student {
        public abstract void study();
        public void sleep() {
            System.out.println("躺着睡");
        }
    }
    //工具类
    class DoStudent {
        public void doSomething(Student s) {
            s.study();
            s.sleep();
        }
    }
    //--------------------------------------------------------------
    class BaseStudent extends Student {
        public void study() {
            System.out.println("base study");
        }
        public void sleep() {
            System.out.println("坐着睡");
        }
    }
    class AdvStudent extends Student {
        public void study() {
            System.out.println("adv study");
        }
    }
    
    public class DuoTaiDemo {
    
        public static void main(String[] args) {
            DoStudent ds = new DoStudent();
            ds.doSomething(new BaseStudent());
            ds.doSomething(new AdvStudent());
    //        BaseStudent bs = new BaseStudent();
    //        bs.study();
    //        bs.sleep();
    //        AdvStudent as = new AdvStudent();
    //        as.study();
    //        as.sleep();
        }
        
    }

       以下例说明多态的出现在代码中的特点(多态使用的注意事项)

       在多态中成员函数(非静态)的特点

    • 在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败
    • 在运行时期:参阅对象所属的类中是否有调用的方法

       简单总结就是:

    • 成员函数(非静态)在多态调用时,编译看左边,运行看右边。
    • 在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)
    • 在多态中,静态成员函数的特点:无论编译和运行,都参考左边。

       示例代码如下:

    class Fu {
        
        int num = 5;
        
        void method1() {
            System.out.println("fu method_1");
        }
        void method2() {
            System.out.println("fu method_2");
        }
        static void method4() {
            System.out.println("fu method_4");
        }
    }
    class Zi extends Fu {
        
        int num = 8;
        
        void method1() {
            System.out.println("zi method_1");
        }
        void method3() {
            System.out.println("zi method_3");
        }
        static void method4() {
            System.out.println("zi method_4");
        }
        
    }
    public class DuoTaiDemo1 {
    
        public static void main(String[] args) {
    /*
     * 在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属 的类)
     */
    //        Fu f = new Zi();
    //        System.out.println(f.num);
    //        
    //        Zi z = new Zi();
    //        System.out.println(z.num);
            
    /*
     * 在多态中,静态成员函数的特点:无论编译和运行,都参考左边。     
     */
            Fu f = new Zi();
            f.method4();
            Zi z = new Zi();
            z.method4();
            
    /*
     * 在多态中成员函数(非静态)的 特点:在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败
     *                在运行时期:参阅对象所属的类中是否有调用的方法             
     * 简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。     
     */
    //        Fu f = new Zi();
    //        f.method1();
    //        f.method2();
    //        f.method3();
            
        }
    }

       

       多态的应用:

       1、电脑运行示例,电脑运行基于主板

       代码示例如下:

    //接口定义规则
    interface PCI {
        public void open();
        public void close();
    }
    class MainBoard {
        public void run() {
            System.out.println("mainboard run");
        }
        public void usePCI(PCI p) {// PCI p = new NetCard(); 接口型引用指向自己的子类对象
            if(p != null) {
                p.open();
                p.close();
            }
        }
    }
    class NetCard implements PCI {
        public void open() {
            System.out.println("netcard open");
        }
        public void close() {
            System.out.println("netcard close");
        }
    }
    class SoundCard implements PCI {
        public void open() {
            System.out.println("SoundCard open");
        }
        public void close() {
            System.out.println("SoundCard close");
        }
    }
    
    public class DuoTaiDemo2 {
    
        public static void main(String[] args) {
            MainBoard mb = new MainBoard();
            mb.run();
            mb.usePCI(null);
            mb.usePCI(new NetCard());
            mb.usePCI(new SoundCard());
        }
    
    }

       2、数据库的操作。数据是:用户信息。

    1. 连接数据库(JDBC Hibernate)
    2. 操作数据库(CRUD)——C creat R read U update D delete
    3. 关闭数据库连接

       代码示例如下:

    interface UserInfoDao { //dao: d(data) a(access) o(object)——数据访问对象
        public void add(User user);
        public void delete(User user);
    }
    class UserInfoByJDBC implements UserInfoDao {
        public void add(User user) {
            1、JDBC连接数据库
            2、使用sql添加语句添加数据
            3、关闭连接
        }
        public void delete(User user) {
            1、JDBC连接数据库
            2、使用sql删除语句删除数据
            3、关闭连接
        }
    }
    class UserInfoByHibernate implements UserInfoDao {
        public void add(User user) {
            1、Hibernate连接数据库
            2、使用sql添加语句添加数据
            3、关闭连接
        }
        public void delete(User user) {
            1、Hibernate连接数据库
            2、使用sql删除语句删除数据
            3、关闭连接
        }
    }
    public class DBOperate {
    
        public static void main(String[] args) {
    //        UserInfoByJDBC ui = new UserInfoByJDBC();
    //        UserInfoByHibernate ui = new UserInfoByHibernate();
            UserInfoDao ui = new UserInfoByJDBC(); //多态
            ui.add(user);
            ui.delete(user);
        }
    
    }

       Object

       Object:是所有对象的直接或者间接父类,传说中的上帝。该类中定义的肯定是所有对象都具备的功能。

       Object类中已经提供了对对象是否相同的比较方法,如果自定义类中也有比较相同的功能,没有必要重新定义。只要沿袭父类中的功能,建立自己特有比较内容即可,这就是覆盖。

       内部类

       内部类的访问规则:

    • 内部类可以直接访问外部类中的成员,包括私有。之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类中的引用,格式--外部类名.this
    • 外部类要访问内部类,必须建立内部类对象

       访问格式:

       1、当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象。

           格式:外部类名.内部类名   变量名  =  外部类对象.内部类对象

                   Outer.Inner in = new Outer().new Inner();

       2、当内部类在成员位置上,就可以被成员修饰符修饰,比如,private将内部类在外部类中进行封装,static内部类就具备static的特性。当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。

           在外部其他类中,如何直接访问静态内部类非静态成员呢?

           new Outer.Inner().function();

           在外部其他类中,如何直接访问静态内部类静态成员呢?

           Outer.Inner.function();

       注意:当内部类中定义了静态成员,该内部类必须是static的。当外部类中的静态方法访问内部类时,内部类也必须是static的。

       示例代码如下:

    class Outer {
        private static int x = 3;
        
        static class Inner {//内部类可以被私有修饰(静态内部类)
    //        int x = 4;
            static void function() {
    //            int x = 6;
                System.out.println("inner:"+x);
            }
        }
        
        static class Inner2 {
            void show() {
                System.out.println("inner2 show");
            }
        }
        
        public static void method() {
    //        Inner in = new Inner();
    //        in.function();
            
    //        Inner.function();
            new Inner2().show();
        }
    }
    
    public class InnerClassDemo {
    
        public static void main(String[] args) {
            
            Outer.method();
    //        Outer.Inner.function();
    //        Outer out = new Outer();
    //        out.method();
            
            //直接访问内部类中的成员
    //        Outer.Inner in = new Outer().new Inner();
    //        in.function();
        }
    
    }

       内部类什么时候使用呢?

       当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容。以人体和心脏为例进行说明之(示例代码如下)

    //人体(外部类)
    class Body {
         //心脏(内部类)
         private class XinZang { //心脏得封装起来
     
         }
         public void show() {
                new XinZang().tiaoDong();
         }
    }        

       内部类定义在局部时

    1. 不可以被成员修饰符修饰,因为private、static不能修饰局部成员
    2. 可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量,java8好像没这个区别了

       示例代码如下:

    class Outer_P {
        
        int x = 3;
        
        void method(final int a) {
            final int y = 4;
            class Inner { //private、static不能修饰局部成员
                void function() {
    //                System.out.println(Outer_P.this.x);
    //                System.out.println(y);
                    System.out.println(a);
                }
            }
            new Inner().function();
        }
    }
    public class InnerClassDemo1 {
    
        public static void main(String[] args) {
            Outer_P out = new Outer_P();
            out.method(7);
            out.method(8);
        }
    
    }

       匿名内部类

    1. 匿名内部类其实就是内部类的简写格式
    2. 定义匿名内部类的前提:内部类必须是继承一个类或者实现接口
    3. 匿名内部类的格式:new 父类或者接口() {定义子类的内容}
    4. 匿名内部类其实就是一个匿名子类对象,而且这个对象有点胖。可以理解为带内容的对象
    5. 匿名内部类中定义的方法最后不要超过3个。

       示例代码如下:

    abstract class AbsDemo {
        abstract void show();
    }
    class Outer_I {
        int x  =3;
        /*
        class Inner extends AbsDemo {
            int num = 90;
            void show() {
                System.out.println("show:"+num);
            }
            void abc() {
                System.out.println("haha");
            }
        }
        */
        
        public void function() {
    //        new Inner().show();
            
    //        Inner in = new Inner();
    //        in.show();
    //        in.abc();
            
            //AbsDemo a = new Inner();
            //new AbsDemo(){}是一个AbsDemo的匿名子类对象
            AbsDemo d = new AbsDemo() {
                int num = 9;
                void show() {
                    System.out.println("num==="+num);
                }
                //子类特有方法
                void abc() {
                    System.out.println("haha");
                }
            };
            d.show();
    //        d.abc();//编译失败
            new AbsDemo() {
                void show() {
                    System.out.println("x="+x);
                }
                //子类特有方法
                void abc() {
                    System.out.println("haha");
                }
            }.abc();
            
        }
    }
    public class InnerClassDemo2 {
    
        public static void main(String[] args) {
            new Outer_I().function();
        }
    
    }

       练习:补全代码。通过匿名内部类

       示例代码:

    interface Inter {
        void method();
    }
    class Test {
        /*
        static class Inner implements Inter {
            public void method() {
                System.out.println("method run");
            }
        }
        static Inter function() {
            return new Inner();
        }
        */
        //补足代码。通过匿名内部类
        static Inter function() {
            return new Inter() {
                public void method() {
                    System.out.println("haha");
                }
            };
        }
    }
    
    public class InnerClassTest {
    
        public static void main(String[] args) {
            //Test.function():Test类中有一个静态的方法function
            //.method():function这个方法运算后的结果是一个对象,而且是一个Inter类型的对象,因为只有是Inter类型的对象,才可以调用method().
            Test.function().method();
            
    //        Inter in = Test.function();
    //        in.method();
            show(new Inter() {
                public void method() {
                    System.out.println("main run");
                }
            });
        }
        
        public static void show(Inter in) {
            in.method();
        }
    
    }

       面试时可能遇到的一个小问题(有关匿名内部类),如果没有一个类继承或一个抽象类实现,还能使用匿名内部类吗?答案是可以的。示例代码如下:

    class InnerTest {
        
        public static void main(String[] args) {
            new Object() {// new Object() {}是Object类的子类对象
                public void function() {
                    System.out.println("hello");
                }
            }.function();
        }
    }
  • 相关阅读:
    正则表达式学习网站
    Longest Substring Without Repeating Characters
    保留小数点后几位数字
    ReentrantLock和synchronized的区别随笔
    范型 小编
    两个线程交替打印字符串
    Gray Code
    Ajax
    堆排序
    Clone Graph
  • 原文地址:https://www.cnblogs.com/yerenyuan/p/5205131.html
Copyright © 2011-2022 走看看