Day09 --面向对象

来源:互联网 发布:多少岁淘宝能贷款 编辑:程序博客网 时间:2024/04/28 03:03
 a.
    多态
        概述
            多态就是事物存在的多种形态。即:这只猫挺可爱的,也可以说成这只动物挺可爱的,描述的都是同一种事物。
                * 由于参数列表不同,而导致的执行效果不同,这种情况叫做多态。
        前提
            * 要存在继承关系
            * 要有方法的重写,即重写父类中的方法。
            * 要有父类引用指向子类对象。
                    * 也就是说:父类 f = new 子类(); f就是父类引用指向子类对象。因为存在继承关系和方法的重写,所以这种情况可行。
                                     f.eat(); //结果:猫吃鱼,因为子类将父类的方法进行了重写,所以f.eat()调用的是子类中的方法,如果子类中没有这个方法,就调用的是父类中的方法。        
    
        特点
            多态不仅解决了方法同名的问题,而且还将程序变的更加灵活,从而提高了代码的扩展性和维护性。


例子中的部分关键代码                
        //Cat c = new Cat(); //new普通的对象  (猫是一只猫)
        //c.eat();
    
        Animal a = new Cat(); //父类引用指向子类对象。 (猫是一只动物)
        a.eat(); //结果:结果:猫吃鱼,因为子类将父类的方法进行了重写,所以f.eat()调用的是子类中的方法,如果子类中没有这个方法,就调用的是父类中的方法。        


例子:
G:\CSDN_Android_\Code\day09 面向对象\01_多态\Demo1_多态的概述.java


b.
    多态访问成员的特点 [左边:父类,右边:子类]
        多态访问成员的特点 [左边:父类,右边:子类]
        1) 成员变量,编译看左,运行也看左。
            * 父类中有,就用父类的,即使父类中的成员变量没有被赋值,也调用父类的;
            * 因为是父类的引用,所以指向的肯定是父类的成员。当父类中没有该成员时,但子类有,结果报错,因为多态的 "成员变量" 跟子类没关系。 
        
        2) 成员方法属于动态绑定! 所以编译看左,运行看右。
    
        3) 静态成员方法属于静态绑定! 所以编译看左,运行也看左。(跟成员变量一样)
                * 静态只和类有关,因为静态是随着类的加载而加载的,所以他算不上是重写,所以访问结果还是看左边。
                * 只有非静态的方法,编译看左,运行看右。
            不满足多态的特征,因为父类中没有该方法,所不能重写父类中的方法,只有重写父类中的方法了,才算编译看左,运行看右。    


例子中的部分关键代码    
        //测试多态中的成员变量 编译看左,运行也看左。
            Father f = new Son();
            System.out.println(f.name); //结果:哈哈,说明多态中的成员变量是:编译看左,运行也看左。
            //System.out.println(f.age);    //因为是父类的引用f,所以指向的肯定是父类的成员。当父类中没有该成员时,但子类有,结果报错,因为多态的成员变量跟子类没关系。


        //测试多态中的成员方法 编译看左,运行看右。
            Father f2 = new Son();
            f2.eat(); //结果:子类 嘻嘻 说明多态中的成员方法,编译看左,运行看右。
                     //因为在编译的时候看左边是否有这个方法,保证左边有的前提下,去看右边子类中是否有,如果子类有,就将子类的方法放入栈内,打印的子类结果。
                     //如果父类中没有该方法,就运行错误。
                     //但子类没有重写父类中的方法,结果还是父类的。


        //测试多态中的静态成员方法 编译看左,运行也看左。
            Father f3 = new Son();
            f3.method(); //结果:父类method hehe  静态方法不属于重写,所以就算不上多态情况的一种,但最终还是编译看左,运行也看左。
            //相当于是Father.method();
        
        class F{
            String name ="哈哈";    
    
            public void eat(){        
                sop("父类 哈哈");
            }
    
            public static void method(){  
                sop("父类method hehe");
            }
        }
        
        class S extends F{
            String name ="嘻嘻";    
            int age =9; 
        
            public void eat(){        
                sop("子类 嘻嘻");
            }
        
            public static void method(){    
                sop("子类method xixi");
    }
        }

例子:
G:\CSDN_Android_\Code\day09 面向对象\01_多态\Demo2_多态中的成员访问特点之成员变量_成员方法_静态成员方法.java



c.
    多态的向上转型和向下转型
            PersonSon p = new SuperMan();  向上转型 --父类引用指向子类对象
            SuperMan s = (SuperMan)p;    向下转型 --将父类变成子类,才能使用子类特有的属性和行为。
            
            StudentFun sf = new StudentFun();
            Student s = (Student)sf;    //这样的过程就是向下转型。        
            

        * 参考以前:
                基本数据类型提升 和 强制类型转换
                    * 基本数据类型
                            int a=10;
                            byte b=20;
                            a = b;    //小的可以直接放大里放, 这种情况叫:基本数据类型的自动类型提升。
                            b = a;  //大的给小的,会损失进度,必须强转,即 b=(byte)(a);
                    * 引用数据类型
                        * Person父类   SuperMan子类。
                            1)Person p = new SuperMan(); 这种父类引用指向子类对象叫“向上转型” 即 superMan提升为了Person类型。                            
                            2)SuperMan s = (SuperMan)p; 将父类对象强转化为子类对象 这种情况叫:向下转型。


        由上可知:
            父类引用指向子类对象 叫 向上转型。
            将父类对象的强转为子类对象 叫 向下转型。
        记住:
            必须先有 "向上转型",才能有 "向下转型"。

例子参考:
    G:\CSDN_Android_\Code\day09 面向对象\Demo3_使用超人来讲解多态的向上转型和向下转型.java



d.
        多态好处和弊端
            好处:
                * 提高了代码的维护性(继承保证)
                * 提高了代码的扩展性(多态保证)[可以将父类当做形式参数,来接收(强转为)任意的子类对象。] public static void method(Aniaml[其实该父类是一个抽象类,后面具体讲] a){}
                      
            弊端:
                不能直接访问子类特有的属性和行为,必须要靠 “向下转型” 来完成对子类特有属性和行为的访问。


例子代码中的部分关键点:
        //Animal2 a = new Cat2() 开发中很少使用父类引用指向子类对象,而是直接使用子类引用去创建子类对象,因为这样可以访问到子类中所有的成员。
        //那么什么时候使用多态呢?
        //当多态当做为形式参数的时候用最好,因为这种扩展性强,如下。
        /**
            public static void method(Animal2 a){ //多态提高了代码的扩展性
                //a.eat();
                //如果将狗强转为猫,就会出现类型转换异常:ClassCastException, 所以做判断来完成具体的子类对象的分析。
                //要使用到一个关键字:instanceof  判断前面的引用是否是后面的数据类型或子类。
                if(a instanceof Cat2){ //如果动物是一只猫,
                    Cat2 c = (Cat2)a; //就将动物强转为狗。
                    c.eat();
                    c.catchMouse();


                }else if(a instanceof Dog2){ //如果动物是一只狗, 
                    Dog2 d = (Dog2)a; //就将动物类强转为狗。
                    d.eat();
                    d.lookHome();
                    
                }else{
                    a.eat();
                }
        }
                这种情况很少出现,因为在开发中,想使用谁,直接创建形式参数具体的子类的对象即可。
                即:public static void method(Cat2 c){}
                    main{
                        method(new Cat2());
                    }
    
                    public static void method(Dog2 d){}
                    main{
                        method(new Dog2());
                    }
        */

例子:
G:\CSDN_Android_\Code\day09 面向对象\01_多态\Demo4_多态好处和弊端.java
​            
​        

e.    
        多态中的面试题分析    
A:看下面程序是否有问题,如果没有,说出结果
    class Fu {
        //父类补充method方法
        public void method() {
            System.out.println("fu method");
        } 
    
        public void show() {
            System.out.println("fu show");
        }
    }
    
    class Zi extends Fu {
        public void show() {
            System.out.println("zi show");
        }
    
        public void method() {
            System.out.println("zi method");
        }
    }
    
    class Test1_多态面试题1 {
        public static void main(String[] args) {
            Fu f = new Zi();
            //f.method(); //结果:错误,因为在父类中没有method方法。
            f.show();
            //再次抒写    
            f.method();
        }
    }
        
        /**
            结果:
                f.method(); //结果:错误,因为多态中的成员方法 编译看左,运行看右,左边没有父类没有method方法,所以直接报错。
    
            所以:
                只需要在父类中添加method方法即可。
                    public void method() {
                        System.out.println("fu method");
                    } 
    
        */ 


B:看下面程序是否有问题,如果没有,说出结果
    class A {
        public void show() {
            show2();  //我    
        }
        public void show2() {
            System.out.println("我");
        }
    }
    class B extends A {
        public void show2() {
            System.out.println("爱");  //爱
        }
    }
    class C extends B {
        public void show() {
            super.show();     //爱             
        }
        public void show2() {
            System.out.println("你"); // 你    
        }
    }
    public class Test2_多态面试题2 {
        public static void main(String[] args) {
            A a = new B();
            a.show();  //爱  因为子类B继承了父类A,父类A中有show()方法,所以相当于子类B也有了show()方法,又因为show方法中调用的是show2()的结果,又因为子类B中存在show2()的方法,即根据编译看左,运行看右的规则,show()中show2()调用的是子类show2()方法,即结果是:爱。
            
            B b = new C();
            b.show(); //你  因为子类C继承了父类B,父类B中有show()方法,所以相当于子类C也有了show()方法,因为show方法中调用的是show2()的结果,又因为子类C中存在show2()的方法,即根据编译看左,运行看右的规则,show()中show2()调用的是子类show2()方法,即结果是:你。
        }
    }    
    
        结果:   爱
                你

​    



f.
    抽象类
        概述
            抽象的意思是看不懂,在Java中的意思是:表示该类中都是一些没有具体实现过程的方法,连{}都没有。且用abstract(抽象)关键字来修饰。
            java中定义没有方法体的方法,该方法由具体的子类来完成,这种方法就叫抽象方法,包含有抽象方法的类就叫抽象类。
    
        特点
            0)抽象类中有构造方法,但不能被实例化,只能通过父类引用指向子类对象的方式,即如下:
                * Animal a = new Dog();    Animal是抽象类还是Dog的父类,因为抽象所以Animal不能被实例化。 Dog是具体子类。但是可以: 父类引用指向子类对象 的方式来创建对象。
            1)抽象类和抽象方法都必须用 abstract 关键字来修饰。
                即
                    public abstract class 类名(){ //抽象类
                        public abstract void eat();  //没有具体实现的方法,连{}都没有。
                        public abstract void method(); //没有具体实现的方法,连{}都没有。
                    }
            2)抽象类中不一定要有抽象方法,但有抽象方法的类一定是抽象类或者接口。
            3)抽象类不能new,即被实例化,那该怎么用呢? 
                * 按照多态的方式,由具体的子类去继承该抽象类且完成实例化,其实这也是多态的一种:抽象类多态。
                    
            4)抽象类的子类
                    * 要么是还是抽象类
                    * 要么是普通类,但要重写抽象类中所有的方法,且方法必须有完善的实现步骤。 
                    
        抽象方法的由来:
            多个对象都具备相同的功能,当功能的具体内容不同,那么在抽取过程中,只抽取了功能定义,未抽取功能主体,那么只有功能声明,没有功能主体的方法就成为抽象方法。
    
        什么时候定义抽象方法
            * 当不知道该方法是怎样的实现过程且多个子类都需要这个方法时,可定义为抽象,是抽象方法的都必须放在抽象类中。
        为什么不能实例化抽象类
            * 因为实例化的类,都要去使用里面具体的方法,但抽象类中的方法都是抽象的没有其实现过程,去调用该方法没有什么意义。
    
        不可以去实例化抽象类,但可以去声明抽象类,即:父类引用指向子类对象。
            Animal a = new Cat(); //该Animal是抽象类,因为多态的成员方法是:编译看左(左边即父类,有该方法不管是否是抽象方法或普通方法),运行看右(右边即子类,调用是子类具体的方法)。
            c.eat();

例子:
G:\CSDN_Android_\Code\day09 面向对象\02_抽象类\Demo1_abstract_抽象类的概述及其特点.java



g.    
    抽象类的成员特点
        1)抽象类中成员变量的特点:
            * 成员变量:既可以是变量,也能是常量。但都不能被抽象。
            * abstract是否能修饰成员变量? 不能被修饰成员变量。
            * 是否有构造方法? 有构造方法,是用来给子类进行初始化用的。
            * 成员方法:既可以是抽象的(但强制要求子类重写该方法),也可以不是抽象的(用来继承,提供代码维护性[子类继承该抽象类,就能直接调用该非抽象方法])    
    
        2)抽象类中成员方法的特点:
            * 抽象方法,强制要求子类要做的事情。
            * 非抽象方法,子类继承的事情,提高代码的维护性[子类继承抽象类后,就可以直接使用该非抽象方法]。
        
        为什么要普通类去继承抽象类呢?
            * 因为工作中 遵守规则,方便开会后制定标准:统一规则,合作开发用的。
    
        p.s.
            抽象类中是否有构造函数?
                有,用于给子类对象进行初始化的。
            抽象类中可不可以没有抽象方法?
                可以,目的是让该类创建对象。
    
        p.s.
            抽象类和一般类的区别?
                相同点:
                    都是用来描述事物,都在内部定义了成员。        
                异同点:
                    一般类有足够的信息来描述事物。
                    抽象类描述事物信息可能有些不足。
            
                    一般类中没有抽象方法,只能定义非抽象方法。
                    抽象类中可以定义抽象方法,同时也能定义非抽象方法。
    
                    一般类可以被实例化。
                    抽象类不可以被是实例化。
                
                    抽象类可以是一个父类吗?
                        是的,因为子类需要覆盖里面的方法,才能对子类进行实例化。

例子:
G:\CSDN_Android_\Code\day09 面向对象\02_抽象类\Demo2_abstract_抽象类的成员特点.java
​    



h. 
    抽象类的作用
        葵花宝典案例
        例子:G:\CSDN_Android_\Code\day09 面向对象\02_抽象类\Demo3_abstract_葵花宝典的方式讲解抽象类的使用.java



i.
    抽象类练习题
        猫狗案例
            * A:案例演示
                * 具体事物:猫,狗
                * 共性:姓名,年龄,吃饭
                * 猫的特性:抓老鼠
                * 狗的特性:看家
例子: G:\CSDN_Android_\Code\day09 面向对象\02_抽象类\Test1_abstract_抽象类练习猫狗案例.java
​    

        老师案例
            A:案例演示
                * 具体事物:基础班老师,就业班老师
                * 共性:姓名,年龄,讲课。
                * 具体事物:基础班学生,就业班学生
                * 共性:姓名,年龄,学习
例子:G:\CSDN_Android_\Code\day09 面向对象\02_抽象类\Test2_abstract_抽象类练习老师案例.java


        员工案例    
            A:案例演示
                * 假如我们在开发一个系统时需要对程序员类进行设计,程序员包含3个属性:姓名、工号以及工资。
                * 经理,除了含有程序员的属性外,另为还有一个奖金属性。
                * 请使用继承的思想设计出程序员类和经理类。要求类中提供必要的方法进行属性访问。

例子:G:\CSDN_Android_\Code\day09 面向对象\02_抽象类\ziCat.class

g.        
    抽象类中面试题
 A:面试题1
    * 一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
        * 可以。意义在于 不让其他类去创建本类对象,而是让其子类去创建对象。
B:面试题2
  * abstract【不能】和哪些关键字共存 3个
    * private 如果定义为私有方法,子类就无法重写父类中抽象方法,但被abstract修饰的方法,必须要求子类去重写,所以不可以。
    * static 如果定义为静态,就可以直接类名.方法名()去调用, 但抽象类中的方法都是没有方法体的,所以这样没意义。
    * final  如果定义为final,该方法变成最终,不能被子类重写,但被abstract修饰的方法,必须要求子类对其父类中方法进行重写,发生冲突,所以抽象也不可以跟final共存。

  * abstract【能】和哪些关键字共存
    * public
    * public abstract
    * interface


h.
    接口
        概述
            抽象类中可定义接口或普通方法,而在接口中全部都是抽象方法,用于对外提供规则的都是接口。
            一个抽象类中的方法都是抽象的时候,可以将该抽象类以另一种的形式来表示:即接口。
        特点
            * 用 interface 来修饰
                * interface 接口{ }
            * 子类用 implements 来去实现,Java中是单继承,多实现的。
                * class 类名 implement 接口名, 接口名{}
            * 接口能被实例化吗?,
                * 不能实例化,因为接口中方法都没有方法体,这样做没意义,所以只能通过多态的方式去实现实例化。
                * 多态方式: 接口 接口名 = new 普通类(); 
            * 接口的子类:
                * 要么是抽象类,没意义。
                * 要么是具体类,但必须要重写接口中所有的抽象方法。(推荐使用)
        p.s.
            接口中的成员修饰符都是固定的:
                成员常量: public static final
                成员方法: public abstract
                由此可见,接口中的成员都是公共的修饰权限。
    
            接口是对外暴露的规则。
            接口是程序的功能扩展。
        
        p.s.        
            java中不直接支持多继承,因为会出现调用的不稳定性。
            所以java将多继承机制进行改良,在java中变成了多实现,一个类可以实现多个接口,接口的出现避免了单继承的局限性。
        体现:
            父类或接口中的引用指向或接收了直接子类的对象。
        作用:
            多态的存在,提供了程序的扩展性和后期可维护性。
        前提:
            必须存在继承或实现关系。
            需要有覆盖即重写的动作。
        好处:
            提供了代码扩展性,前期定义了代码可以使用后期的内容。
        弊端:
            前期定义的内容不能调用后期子类特有的内容。


​        
例子:G:\CSDN_Android_\Code\day09 面向对象\03_接口\Demo1_instance接口概述.java
​        

    接口中成员特点
        成员变量:
            * 只能是常量(抽象类中可是常量也能是变量),且必须是公共静态最终的。
            * 默认修饰符: public static final int NUM = 7;
            * 建议手动给出。
        构造方法:
            * 接口中没有构造方法
        成员方法:
            * 接口中只能是抽象方法且没有方法体的。
            * 默认: public abstract void method();
            * 建议手动给出。
例子:G:\CSDN_Android_\Code\day09 面向对象\03_接口\Demo2_interface_成员特点.java


    接口与类之间的关系
        * 类与类
            * 只能是继承关系,而且只能是单继承,但可以多实现。
        * 接口与类
            * 实现关系,可单实现,也可多实现,且一个类可以实现多个接口。
        * 接口与接口
            * 继承关系,可以单继承,也可多继承。(一个接口可以继承多个接口)

例子:G:\CSDN_Android_\Code\day09 面向对象\03_接口\Demo3_接口与类的关系.java


​    

    抽象类与接口区别
        1)成员区别
            * 抽象类:
                * 成员变量:可以是常量,也能是变量。
                * 构造方法:有,用于给子类初始化用的。
                * 成员方法:既可以是抽象的(子类继承后必须重写该方法),也能是非抽象的(子类继承后直接使用该方法)。
            * 接口
                * 成员变量:只能是常量,默认 public static final 修饰。
                * 构造方法:没有
                * 成员方法:只能是抽象的,默认 public abstract 修饰。
                
        2)关系区别
            * 类与类
                * 继承,且单继承
            * 类与接口
                * 实现,可单实现,也能多实现
            * 接口与接口
                * 继承,可单继承,也能能多继承 
                
        3)设计理念区别
            * 抽象类:
                * 被继承的关系, 体现的是一种 “is a” 的关系,抽象类中定义的是该继承体现的共性功能,即 猫 是 动物 的一种关系。动物就是共性功能。
            * 接口
                * 被实现的关系, 体现的是一种 “like a” 的关系,接口中定义的是该继承体系的扩展功能, 即 金毛看起来 像 狗 的一种关系。  金毛就是扩展功能。
    
        p.s.
            抽象类和接口的异同:
                相同:
                    都是不断向上抽象而来的。
                异同:
                    1) 抽象类是要被继承的,且是单继承。
                        接口是需要被实现的,可以多实现。
                    2) 抽象类中可以定义抽象方法和非抽象方法,子类继承后,要将抽象方法进行重写,但可以直接使用非抽象方法。
                        接口中只能定义抽象方法,但必须要由子类去实现。
                    3) 抽象类的继承,是 is a的关系,定义了继承该体系的基本共性内容,
                        接口的实现是 like a 的关系, 定义了该继承体现的扩展功能。


    猫狗案例加入跳高功能分析及其代码实现
        * A:案例演示
            * 动物类:姓名,年龄,吃饭,睡觉。
            * 猫和狗
            * 动物培训接口:跳高
例子:G:\CSDN_Android_\Code\day09 面向对象\03_接口\Test1_猫狗案例.java
原创粉丝点击