java——封装,继承,多态

140 阅读11分钟

4月「掘金·日新计划」第26天

1.4、封装

封装:将数据(属性 成员)和方法(函数) 包装在中,加上具体实现的隐藏(访问修饰符,后面文章会具体说),共同被称作封装。

    1. 类:用户自定义的数据类型,也称类类型(结构体)

    2. 对象:类的具象(具体对象),也就是结构体变量

    3. 封装类

      1. 相当于c语言的结构体
      2. struct在java中是class
      3. 函数指针,在Java中叫方法,直接写函数,可以直接访问变量
    4. 使用类

      1. 定义:Student stu1 = new Student();
      2. 使用:stu1.age点后是类的方法
  1. 访问修饰符

    1. 作用

      1. 信息隐藏:隐藏对象的实现细节,不让外部直接访问到。(防止用户修改)
    2. 种类

      1. private:只有该类可以访问

      2. protected:该类及其子类的成员可以访问,同一个包中的类也可以访问

      3. public:该类或非该类可以访问

      4. 默认:同一个包中的类可以访问

    3. 理解包,类

      1. 同一个类 就是同一个类里面的,类相当于结构体

      2. 同一个包 圈中的就是包

    4. 可以作用于类,成员,方法

      private应用在密码等

  2. 构造方法(初始化)

    1. 构造方法负责对象的初始化,为属性赋合适的初始值
    2. 构造方法语法规则 构造方法名与类名一致 没有返回类型,什么都不写(void是无类型变量) 方式实现主要为字段赋初值
    3. 构造方法调用 new操作符(实例化对象时,自动调用
    4. Java系统保证每个类都有构造方法 即使你没写构造方法,系统也会自动帮你写上
  3. this、static关键字

    1. this关键字(第3和最后一个用的最多)(1this就是调用他的对象stu3,2成员变量和形参同名问题,3构造方法)

      1. 在类的方法中,使用this代表的是调用此方法的对象的引用(this就是调用这个方法的对象stu3)

        //类中使用this,就调用了对象的name变量
        void testThis(){
            System.out.println(this.name);//this就是stu3.name
        }
        ​
        Student stu3 = new Student(18,"xiaowei",99.9);
        stu3.testThis();//stu3对象调用方法,方法里的this就是stu3对象
        /*
        xiaowei
        */
        
      2. this可以看做是一个变量,它的值是当前对象的引用(同上一个意思,this就是stu3)

        void testThis(){
            Student stutmp = null;  //没有指向的变量
            stutmp = this;          //把当前对象的变量赋给stutmp
            System.out.println(stutmp.name);//直接使用
            System.out.println(this.name);
        }
        ​
        Student stu3 = new Student(18,"xiaowei",99.9);
        //stu3.introduce();
        stu3.testThis();
        /*
        xiaowei
        xiaowei
        */
        
      3. 使用this可以处理方法中的成员变量和形参同名问题

        变量和形参同名

        Student(int age, String name, double score){
            System.out.println("构造方法三");
            this.age = age;     //成员变量和形参同名age = age;
            this.name = name;//name = name
            this.score = score;//score = score
        }
        Student stu3 = new Student(18,"xiaowei",99.9);
        stu3.introduce();
        /*
        age=18,name=xiaowei,score=99.9
        */
        
      4. 当在方法内需要用到调用到该方法的对象时,就可以this 和第一个一样

      5. 在类的构造方法中可以调用this(参数列表)来调用该类的指定构造方法 构造方法,调用了1后又有了3

        Student(){
            System.out.println("构造方法一");
        }
        Student(int newage){
            System.out.println("构造方法二");
            age = newage;
        }
        Student(int age, String name, double score){
            this();//只能调用一个,使用这个就不能使用this(18);
            System.out.println("构造方法三");
            this.age = age;
            this.name = name;
            this.score = score;
        }
        Student stu3 = new Student(18,"xiaowei",99.9);
        /*
        构造方法一
        构造方法三
        */
        
    2. static关键字(直接使用类名访问变量,类方法直接使用不需要实例化,静态代码块)

      1. static关键字,注意事项

        1. 静态方法中只能访问外部的静态成员

        2. 静态方法中不能出现this关键字(先于对象之前,this是对象的引用)

          static void test(){
              System.err.println(name);       //静态方法只能访问静态成员
              System.out.println(this.age); //静态方法中不能出现this关键字
          }
          
      2. 用来修饰类成员,修饰成员变量称为类变量(静态变量)

        int age;
        String name;
        double score;
        static int data;    //类变量
        ​
        Student stu3 = new Student(18,"xiaowei",99.9);
        //Student.score = 10;
        Student.data = 10;  //类变量,可以通过类.变量名 访问变量
        stu3.data = 10;     //当然也可以使用对象.变量名 访问
        
      3. 修饰方法叫,类方法(静态方法)

        public class Test {
            //不加static的访问,需要实例化类
            public static void main(String[] args) {
                Test s1 = new Test();
                System.out.println("ret = " + s1.add(1,3));
            }
            //加static 的访问方法,直接访问使用
            public static void main(String[] args) {
                System.out.println("ret = " + add(1,3));
            }
            //加上static  main就可以直接访问
            static int add(int a, int b){
                return a+b;
            }
        }
        ​
        /*
        ret = 4
        */
        
      4. 当类被加载的时候就会被加载,优先于对象的存在 可以不依赖于对象进行访问(类变量,类方法)

      5. 用来修饰语句块——称为静态代码块,先于构造方法执行,只会执行一次,用来对静态成员做初始化

        //静态代码块,与构造方法类似,都是初始化变量,只是这个是初始化静态变量
        static{
            System.out.println("静态代码块");
            data = 110;
        }
        
      6. 调用的时候可以直接通过类名.成员来访问 类名.成员

  4. 包(package)

    1. 可以编写属于自己的java包,为了保证包名的唯一性,要求唯一的前缀,推荐使用互联网上的域名倒置作为唯一前缀

    2. 标准Java库是由一系列包组成,包括java.lang java.util等等

    3. 标准包就是层次型包结构,就如同硬盘上嵌套的子目录一样,我们可以使用嵌套层次结构来组织包

    4. 为了更好的规范代码,防止命名冲突和混乱, 所以java出现了打包机制

    5. 当把类组织起来放进一个包内时,也就给包中的成员赋予了相互访问的权限,就拥有了该包内的程序代码

    6. 包访问权限把类聚集在一个包中这一做法提供了意义和理由

1.5、继承

父类更抽象更一般,子类更具体更特殊 继承的意义,代码重用

  1. 什么是继承

    1. 继承,基于已存在的类来构建新类
    2. 当从已存在类继承时,就重用了它的方法和属性,还可以添加新的方法和属性来定制新类以应付需求
    3. 约定:从其他类导出的类叫子类,被导出的类叫父类
    4. 在java中,除了Object类外,所有类都是子类,都有唯一的父类
  2. extends关键字

    1. 在java中,用extends关键字来表示一个类继承了另一个类

      public class Teacher extends Person{
      }
      
  3. super关键字

    1. 私有属性方法,子类无法继承
    2. super和this的特点相似:super代码父类对象的引用,this该类对象引用
    3. 当子父类的成员出现同名时,可以通过super来区分
    4. 子类的构造方法中,通过super关键字调用父类的构造方法
    5. 当构造一个子类对象的时候一定会先调用父类的构造方法来构造父类的对象。调用父类构造方法的语句必须是子类构造方法中的第一条指令。
  4. 方法重写

    1. 什么是方法重写,重载(方法名称一样,参数列表不一样),重写(完全做到重写,都一样,实现功能不一样)
    2. 方法重写是指子类可以根据需要对父类继承来的方法进行改写,是多态机制的前奏
    3. 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值
    4. 重写方法不能比被重写方法有更加严格的访问权限 不能降低访问权限,可以增加
    5. 父类中的私有方法,不能被重写 能写上,但是主函数不能调用,报错
    6. 在子类重写的方法中继续使用父类被重写的方法可以通过super.函数名获取
  5. Object

    1. java中,所有类都直接或间接继承自java.lang.Object类,可以说Object是java中所有类的祖先即根类
    2. java中任何类都继承了Object类中的方法,主要有 toStrring() equals()hashcode() clone() getClass() finalize()
  6. 抽象类和抽象方法

    1. java中可以定义没有方法体的方法称为抽象方法,该方法由子类具体实现,含有抽象方法的类称为抽象类

    2. 抽象类

      1. 定义中含有抽象方法的类叫抽象类
      2. 抽象类用abstract来修饰
      3. 抽象类代表一种抽象的对象类型
      4. 抽象类才能实例化
      5. 抽象类中可以有具体方法,可以没有抽象方法
    3. 抽象方法

      1. 只有方法头没有方法体的方法

      2. 抽象方法用abstract修饰

      3. 抽象方法代表一种不确定的操作或行为

      4. 抽象方法不能被调用

      5. 实际用途

        1. 定义 一个模板方法用一些抽象的操作定义一个算法,而子类将重定义这些操作以提供具体行为
        2. 意图 定义了一个操作中的一个算法框架,把一些步骤推迟到子类去实现。模板方法模式让子类不需要改变算法结构
    4. 接口

      1. 接口语法 interface 接口名{ //公有静态常量、抽象方法 }

      2. 接口的特点

        1. 接口中只能存放静态常量抽象方法
        2. java接口是对功能的扩展
        3. 通过实现接口,java类可以实现多实现 一个类可以同时继承一个父类并且实现(implements)多个接口
        4. 接口与接口之间可以使用extends实现继承
      3. 接口与抽象类的区别 接口强调行为,继承是类似于亲属关系

        1. 抽象类和具体实现之间是一个继承关系,也就是如果采用抽象类的方式,则父类和子类在概念上应该是相同的 is-a
        2. 接口和实现类在概念上不要求相同,接口只是抽取相互之间没有关系的类的共同特征,而不去关注类之间的关系,它可以使没有层次关系的类具有相同的行为
        3. 抽象类是对一组具有相同属性和行为的逻辑上有关系的事物的一种抽象,而接口则是对一组具有相同属性和行为的逻辑上不相关的事物的一种抽象
    5. 内部类

      1. 就是将一个类定义在另一个类的内部,内部的类简称内部类
      2. 内部类可以很好的实现隐藏,可以使用protected private修饰符
      3. 内部类可以直接访问外部类的所有成员,包括私有的成员
      4. 外部类不能直接访问内部类的成员,必须首先建立内部类的对象才能访问
    6. 匿名内部类

      1. 通常用在:线程、安卓按键响应

        1. 匿名内部类是没有名称的内部类,没办法引用它们。必须在创建时,作为new语句的一部分来声明并创建它们的实例
        2. 匿名内部类必须继承一个类(抽象的,非抽象的都可以)或者实现一个接口。所有父类(或父接口)是抽象类,则匿名内部类必须实现其所有抽象方法
        3. 语法:实例 newinterface/superclass(){类体} 这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口,并同时创建该匿名类的一个新实例

1.6、多态

多态性是指同一个操作作用于某一类对象,可以有不同的解释,产生不同的执行结果

区别:继承是子类使用父类的方法,而多态则是父类使用子类的方法(把子类强转为父类对象)。

  1. 必要条件

    1. 需要存在继承或实现(接口)关系
    2. 同样的方法调用而执行不同操作、运行不同代码(重写
    3. 在运行时父类或者接口的引用变量可以引用其子类的对象
  2. 作用

    1. 多态通过分离做什么和怎么做,从一个角度将接口和实现进行分离
    2. 多态消除了类型之间的耦合关系
    3. 多态的存在提高了程序的拓展性和后期的可维护性
  3. 对象的上下转型

    1. 由子类转型成父类,在继承图上是向上移动的,一般称为向上转型(强制转换就是)

      Animal a1 = new Dog();
      Animal a1 = new (Animal)Dog(); //实际上就是强转,但是一般不需要写出来
      
    2. 向上转型是从一个较专用类型向通用类型转换,所以总是安全的(体现编译报错),也就是说,子类是父类的超集

    3. 向上转型过程中,类接口中唯一可能发生的事情是丢失方法,而不是获取方法

    4. 与之相反的操作是向下转型不安全(可能需要instanceof操作符协助)(体现在运行过程)

    5. instanceof操作符 返回值指出对象是否是特定类或者是它的子类的一个实例