面向对象之多态

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

   例如:人:男人,女人;

           动物:猫,狗

           猫 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();
    }
}

 

posted @ 2016-02-21 16:20  叶十一少  阅读(322)  评论(0编辑  收藏  举报