2017 - 10 -16 面向对象 多态 抽象类 接口 形参和返回值 链式编程 包 访问修饰符 内部类

1 多态
(1)同一个对象(事物),在不同时刻体现出来的不同状态
  举例:
     猫是猫,猫是动物。
     水(液态,固态,气态)。
(2)多态的前提:
       A:要有继承关系。
       B:要有方法重写。
             其实没有也是可以的,但是如果没有这个就没有意义。
             动物 d = new 猫();
             d.show();
             动物 d = new 狗();
             d.show();
       C:要有父类引用指向子类对象那个。

               父 f = new 子类;

(3)多态中的成员访问特点:
       A:成员变量
           编译看左边,运行看左边
       B:构造方法
           创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化
       C:成员方法
           编译看左边,运行看右边(成员方法存在重写)
       D:静态方法
           编译看左边,运行看左边
           (静态和类相关,算不上重写,所以访问还是左边的)
         
       由于成员方法存在方法重写,所以它看右边

class Fu{
      public int num =100;
      public void show(){
        System.out.println("show Fu");
}
      public static void function(){
        System.out.println("function Fu");
           }
}
class Zi extend Fu{
       public int num =1000;
       public int num2 =2000;
       public void show(){
        System.out.println("show Zi");
}
       public static void function(){
        System.out.println("function Zi");
}
}
class DuoTaiDemo{
      public static void main(String[] args){
        Fu f = new Zi();
        System.out.println(f.num);
        //报错 父类中找不到num2
        //System.out.println(f.num2);
        f.show();
        f.function();
}
}               
     输出结果:100 show Zi function Fu

(4) 多态的好处
    A:提高了代码的维护性(继承保证)
    B:提高了代码的扩展性(调用时,直接调用父类名,而不用直接调用子类名)
   例如:
    Dog a = new Dog();
    Cat b = new Cat();
    Pig c = new Pig();
    AnimalTool.useDog(a);
    AnimalTool.useCat(b);
    AnimalTool.usePig(c);
----------------------------------------
    Dog a = new Dog();
    Cat b = new Cat();
    Pig c = new Pig();
    AnimalTool.useAnimal(a);
    AnimalTool.useAnimal(b);
    AnimalTool.useAnimal(c);

(5) 多态的弊端
    不能使用子类的特有功能,只能使用父类中定义了的功能。

    那如何使用子类的特有功能?
      A:创建子类对象调用特有功能。(可以,但是很多时候不合理,而且太占内存了)
      Fu f = new Zi();
      f.show();
      //f.method(); 无法调用子类的method
      //所以创建另一个子类对象
      Zi z = new Zi();
      z.show();
      z.method();

      B:把父类的引用强制转换为子类的引用。(向下转型)
      Zi z = (Zi)f;
      z.show();
      z.method();
 -----------------------------------------
      对象间的转型问题:
        向上转型:
          Fu f = new Zi();
        向下转型:
          Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。
(6) 继承的时候:
       子类中有和父类一样的方法,叫做重写。
       子类中没有父亲中出现过的方法,方法就被继承过来了

2 抽象类
(1)抽象类的概述:
      动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。
      我们把一个不是具体的功能成为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。
   
(2)抽象类的特点:
     A:抽象类和抽象方法必须用abstract关键字修饰
     B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
     C:抽象类不能实例化
          因为它不是具体的
          抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢?
          用于子类访问父类数据的初始化
     D:抽象的子类
          a:如果不想重写抽象方法,该子类是抽象类
          b:重写所有的抽象方法,这个时候子类是一个具体的类

   **抽象类的实例化其实是靠具体的子类实现的,是多态的方式。
     Animal a = new Dog();

     a.eat();

abstract class Animal{
        //抽象方法
        //public abstract void eat(){} //空方法体,这个会报错,抽象方法不能有主体
        public abstract void eat();
}
  
(3)抽象类的成员特点:
      成员变量:既可以是变量,也可以是常量。
      构造方法: 有。
                用于子类访问父类数据的初始化。
      成员方法:既可以是抽象的,也可以是非抽象的。
      
      抽象类的成员方法特性:
       A:抽象方法,强制要求子类做的事情
       B:非抽象方法 子类继承的事情,提高代码复用性。

(4)抽象类的几个小问题
    A:一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义
    a:可以
    b:不让创建对象

    B:abstract不能和哪些关键字共存
         private 冲突  (不能被继承,但抽象要求重写)
         final   冲突  (不能被重写,但抽象要求重写)
         static  无意义 (抽象无方法体,static可以直接访问方法体)

3 接口
  为了体现事物功能的扩展性,java中就提供了接口来定义这些额外功能,并不给出具体实现。
(1) 接口的特点:
        A:接口用关键字interface表示
           interface 接口名{}
        B:类实现接口用implements表示
           class 类名 implements 接口名{}
        C:接口不能实例化
             那么,接口如何实例化呢?
              按照多态的方式来实例化
        D:接口的子类
           a:可以是抽象类,但意义不大
           b:可以是具体类,要重写接口中的所有抽象方法(推荐方案)

    由此可见:
        A:具体类多态(几乎没有)
        B:抽象类多态(常用)
        C:接口多态(最常用)

//定义动物培训接口
interface AnimalTrain{
     public abstract void jump();
}       

(2)接口成员特点
       成员变量:只能是常量
                 默认修饰符 public static final
       构造方法:没有,因为接口主要是扩展功能的,而没有具体存在
       成员方法:只能是抽象方法
                 默认修饰符public abstract

(3) 类与类:
         继承关系:只能单继承,可以多层继承。
    类与接口:
         实现关系,可以单实现,也可以多实现。
         并且还可以在继承一个类的时候同时实现多个接口。
    接口与接口:
         继承关系:可以单继承,也可以多继承

4 抽象类与接口的区别
   A:成员区别
    抽象类:
         成员变量:可以变量,也可以常量
         构造方法:有
         成员方法:可以抽象,也可以非抽象
    接口:
         成员变量:只可以是常量
         构造方法:无
         成员方法:只可以是抽象
   B:关系区别
    类与类:
         继承关系:只能单继承,可以多层继承。
    类与接口:
         实现关系,可以但实现,也可以多实现。
         并且还可以在继承一个类的时候同时实现多个接口。
    接口与接口:
         继承关系:可以单继承,也可以多继承
 **C:设计理念区别
    抽象类 被继承体现的是:"is a"的关系,抽象类中定义的是该继承体系的共性功能。
    接口 被实现体现的是:"like a"的关系,接口中定义的是该继承体系的扩展功能。

5 形式参数和返回值问题
     形式参数: 
         基本类型: 8种基本类型
         引用类型: 
           类:(匿名对象的时候已经用过)需要的是该类的对象
           抽象类:需要的是该抽象类的子类的对象
           接口:跟抽象类同理
     返回值类型: 
         基本类型: 8种基本类型
         引用类型: 
           类:返回的是该类的对象
           抽象类:返回的是该抽象类的子类的对象
           接口:返回的是该接口的实现类的对象

6 链式编程
    每次调用完毕方法后,返回的是一个对象。
  class StudentDemo{
     public Student getStudent(){
           return new Student();         
          }
}
     sd.getStudent().study();//链式编程

7 包
   A:其实就是文件夹
   B:作用
      a:把相同的类名放到不同的包中
      b:对类进行分类管理
  
   举例:
      学生:增加,删除,修改,查询
      老师:增加,删除,修改,查询
      。。。
   方案1:按照功能分
        cn.itcast.add
              AddStudent
              AddTeacher
        cn.itcast.delete
              DeleteStudent
              DeleteTeacher
        cn.itcast.update
              UpdateStudent
              UpdateTeacher
    方案2:按照模块分
        cn.itcast.teacher
              AddTeacher 
              DeleteTeacher
              UpdateTeacher
        cn.itcast.student
              AddStudent
              DeleteStudent
              UpdateStudent

    包的定义
          package 包名;
              多级包用.分开即可
    注意事项:
      A:package语句必须是程序的第一条可执行的代码
      B:package语句在一个java文件中只能有一个
      C:如果没有package,默认表示无包名

8 不同包下类之间的访问
   
     第一个问题:找不到Demo       需要用包名.Demo
     第二个问题:程序包不存在     需要建立工程包
     第三个问题:Demo在包中不是公共的,无法访问    设置访问权限。

    导包:
      格式:import 包名;
      这种方式导入时到类的名称
 
   **面试题:
      package,import,class有没有顺序关系?
       有
      package>import>class
      package:只能有一个
      import:可以有多个
      class:可以有多个,以后建议是一个

9 访问修饰符
                                            public    protected     默认    private
 同一类中                               √                √              √            √
 同一包子类,其他类             √                √              √
 不同包子类                           √                √         
 不同包其他类                       √ 

10 内部类

(1)内部类概述:把类定义在其他类的内部,这个类就被称为内部类。
       举例:在类A中定义了一个类B,类B就是内部类。
(2)内部类的访问特点:
        A:内部类可以直接访问外部类的成员,包括私有。
        B:外部类要访问内部类的成员,必须创建对象。  
(3)内部类位置:
        成员位置:在成员位置定义的类,被称为成员内部类。
        局部位置:在局部位置定义的类,被称为局部内部类。(例如方法中)
(4)成员内部类:
    如何直接访问内部类的成员?
      外部类名.内部类名  对象名 = 外部类对象.内部类对象;
       Outer.Inner oi = new Outer().new Inner();
            oi.show();
(5)成员内部类的修饰符:
     **private:为了保证数据的安全性
     **static:为了方便访问数据
          注意:静态内部类访问的外部类数据必须用静态修饰

        案例:我有一个人(人有身体,身体内有心脏) 
              不能直接让外部访问,必须要保证安全性。
          class Body{
               private class Heart{
                    public void operator(){
                        System.out.println("心脏搭桥");
               } 
      }
              public void method(){
                 if(如果你是外科医生){
                     Heart h = new Heart();
                     h.operator();
                  }
          }
}
(6) 用static修饰后的内部类访问
         class Outer{
              private int num = 10;
              private static int num2 = 100;
             //内部类用静态修饰是因为内部类可以看出是外部类的成员
              public static class Inner{
                     public void show(){
                           System.out.println(num);
              }
                     public static void show2(){
                           System.out.println(num);
              }
      }
}
         //格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
          Outer.Inner oi = new Outer.Inner();
            oi.show();
            oi.show2(); 
                       
         //show2()的另一种调用方式

            Outer.Inner.show2();

静态内部类的作用:

https://www.zhihu.com/question/28197253
***11 成员内部类的面试题
       要求请填空,分别输出30,20,10
   class Outer{
         public int num = 10;
         class Inner{
            public int num = 20;
            public void show(){
                    int num = 30;
                    System.out.println(?);   // num
                    System.out.println(??);  // this.num
                    System.out.println(???); // Outer.this.num /new Outer().num
                }
        }
}     

12 局部内部类
      A:可以直接访问外部类的成员
      B:在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能

    ***面试题:
         局部内部类访问局部变量的注意事项?
         A:局部内部类访问局部变量必须使用final修饰
         B:为什么?
            局部变量是随着方法的调用而调用,随着调用完毕而消失。
            而堆内存的内容并不会立即消失,所以,我们加finaal修饰。
            加入final修饰后,这个变量就变成了常量,既然是常量,你消失了,我在内存中存储的数据是20,所以,我还是有数据在使用。
    (反编译之后,就是一个常量)
     class Outer{
             private int num = 10;
             public void method(){
                   final int num2 = 20;
                   class Inner{
                       public void show(){
                         System.out.println(num);
                         // 从内部类中访问本地变量num2,需要被声明为最终类型
                         System.out.println(num2);
                   }
              }
            Inner i = new Inner();
            i.show();
      }
}
发布了31 篇原创文章 · 获赞 2 · 访问量 9204
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章