面向对象中级


面向对象(中级)

访问修饰符

作用域 当前类 同一包 其他包的子孙类 其他包的类
public
protected ×
friendly × ×
private × × ×

访问修饰符细节

只有默认的(没有修饰符)和public才能修饰类

封装

  1. 将属性进行私有化private

  2. 提供一个公共的(public)set的方法, 用于对属性判断并赋值

    public void setXxx(类型 参数名){  //Xxx表示某个属性
        //加入数据验证的业务逻辑
        属性 = 参数名;
    }
    
  3. 提供一个公共的(public)get的方法, 用于获取属性的值

    public 数据类型 getXxx(){  //权限判断, Xxx某个属性
        return xx
    }
    

继承

img

继承细节

  1. 子类继承了所有的属性和方法, 但是私有属性和方法不能在子类直接访问, 要通过父类提供公共的方法去访问

    public class Base{ //父类Base
        public int n1;
        private int n2;
        
        //通过父类提供一个public的方法, 返回了n2
        public int getN2(){
            return n2;
        }
        public void test100(){
            System.out.println("test100");
        }
        private void test200(){
            System.out.println("test200");
        }
        //通过父类提供的public的方法来调用test200()
        public void callTest200(){
            test200();
        }
    }
    
    public class Sub extends Base{   //子类Sub
        System.out.println("n1");
        //要通过父类提供公共的方法去访问n2
        System.out.println("n4=" + getN2());
        
        test100();
        callTest200();
    }
    
  2. 子类必须调用父类的构造器, 完成父类的初始化

  3. 当创建子类对象时, 不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器, 如果父类没有提供无参构造器, 则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作

  4. 如果希望指定去调用父类的某个构造器, 则显式的调用一下 : super(参数列表)

    1.调用父类的无参构造器, 如下 或者 什么都不写, 默认就是调用super()

    super();//父类的无参构造器

    2.调用父类的 Base(Sting name)构造器

    super("jack");

  5. super在使用时, 必须放在构造器的第一行(super只能在构造器中使用)

  6. super()this()都只能放在构造器的第一行,因此这两个方法不能共存在一个构造器中

  7. 父类构造器的调用不限于直接父类! 将一直往上追溯直到Object类

继承的本质

创建子类的过程中 Son son = new Son();

是先加载类, 1.Object - 2.GrandPa - 3.Father - 4.Son

img

注意此时name与父类和爷爷类的属性名字相同, 出现这种情况下时,按以下规则 :

img

如果父类属性为私有属性, 那么还是需要通过公共的方法去访问

img

如果此时父类的age属性是私有的, 而爷爷类的age属性是public的话, 可以直接用 son.age来访问吗?

答案是不可以!!! 它是一层一层往上找的, 如果在父类遇到私有的age属性, 就会直接报错, 无法绕过父类去访问爷爷类的age属性(可以通过爷爷类的public方法访问)

super关键字

super代表父类的引用, 用于访问父类的属性, 方法, 构造器

  1. 访问父类的属性, 但不能访问父类的private属性

    super.属性名

  2. 访问父类的方法, 不能访问父类的private方法

    super.方法名

  3. 访问父类的构造器

    super(参数列表)

super细节

  1. 当子类中有和父类中的成员(属性和方法)重名时, 为了访问父类的成员, 必须通过super. 如果没有重名, 使用super, this, 直接访问是一样的效果

    img

    img

  2. super的访问不限于直接父类, 如果爷爷类和本类中有同名的成员, 也可以使用super去访问爷爷类的成员, 如果多个基类中都有同名的成员, 使用super访问遵循就近原则

  3. 调用父类构造器的好处 :父类的属性由父类初始化, 子类的属性由子类初始化

super和this的比较

img

重写

方法重写也叫方法覆盖

img

方法重写细节

  1. 子类的方法的形参列表, 方法名称, 要和父类方法的形参列表, 方法名称完全一样
  2. 子类的返回类型和父类方法返回类型一样, 或者是父类返回类型的子类 比如 : 父类 返回类型是 Object, 子类方法返回类型是 String
  3. 子类方法不能缩小父类方法的访问权限

重写与重载的区别

img

多态

  1. 方法重载和方法的重写体现多态

  2. 对象的多态

    1. 一句话的编译类型和运行类型可以不一致

      Animal animal = new Dog(); //编译类型(名义上)是Animal,运行类型(实际上)是Dog
      
    2. 编译类型在定义对象时, 就确定了, 不能改变

    3. 运行类型是可以变化的

    4. 编译类型看定义时 =号 的左边, 运行类型看 =号 的右边

多态的细节

  1. 向上转型

    多态的前提是 : 两个对象(类)存在继承关系

    多态的向上转型

    1. 本质: 父类的引用指向了子类的对象

    2. 语法: 父类类型 引用名 = new 子类类型();

    3. 特点: 编译类型看左边, 运行类型看右边.

      可以调用父类中的所有成员(需遵守访问权限)

      不能调用子类中特有成员

      最终运行效果看子类的具体实现

      (编译类型是编译器javac执行的, 运行类型是java执行的)

    img

  2. 向下转型

    1. 语法: 子类类型 引用名 = (子类类型) 父类引用

    2. 只能强转父类的引用, 不能强转父类的对象

    3. 要求父类的引用必须指向的是当前目标类型的对象

    4. 当向下转型后, 可以调用子类类型中所有 的成员

      img

属性重写问题

  1. 属性没有重写之说!!! 属性的值看编译类型
  2. instanceOf比较操作符, 用于判断对象的运行类型是否为XX类型或者XX类型的子类型

动态绑定机制

  1. 调用对象方法的时候, 该方法会和该对象的内存地址/运行类型绑定
  2. 调用对象属性时, 没有动态绑定机制, 哪里声明, 哪里使用

多态数组

//创建一个Person类, Student和Teacher继承于它

//2个Student 对象和2个Teacher 对象, 统一放在数组中, 并调用每个say方法

img

//如何调用子类特有的方法, 比如Teacher有一个teach, Student有一个study , 怎么调用

img

多态参数

方法定义的形参类型为父类类型, 实参类型允许为子类类型

Object类详解

equals方法

== 与 equals的对比

  1. == 是一个比较运算符, 既可以判断基本类型, 又可以判断引用类型
  2. 如果判断基本类型, 判断的是值是否相等
  3. 如果判断引用类型, 判断的是地址是否相等, 即判定是不是同一个对象

equals方法 : 是Object类中的方法, 只能判断引用类型

默认判断的是地址是否相等, 子类中往往重写该方法, 用于判断内容是否相等. 比如 Integer, String…

hashCode方法
AA aa = new AA();
AA aa2 = new AA();
AA aa3 = aa;
System.out.println("aa.hashCode = " + aa.hashCode());
System.out.println("aa2.hashCode = " + aa2.hashCode());
System.out.println("aa3.hashCode = " + aa3.hashCode());
  1. 提高具有哈希结构的容器的效率
  2. 两个引用, 如果指向的是同一个对象, 则哈希值肯定是一样的
  3. 两个引用, 如果指向的是不同对象, 则哈希值是不一样的
  4. 哈希值主要根据地址号来的, 但是不能完全将哈希值等价于地址
toString方法
  1. 默认返回 : 全类名 + @ + 哈希值的十六进制
  2. 子类往往重写toString方法, 用于返回对象的属性信息
  3. 重写toString方法, 打印对象或拼接对象, 都会自动调用该对象的toString形式(快捷键)
  4. 当直接输出一个对象时, toString方法会被默认的调用
Finalize方法
  1. 当对象被回收时, 系统自动调用该对象的finalize方法. 子类可以重写该方法, 做一些释放资源的操作
  2. 什么时候被回收 : 当某个对象没有任何引用时, 则jvm就认为这个对象是一个垃圾对象, 就会使用垃圾回收机制来销毁该对象, 在销毁该对象前, 会先调用finalize方法
  3. 垃圾回收机制的调用, 是由系统来决定, 也可以通过System.gc()来主动触发垃圾回收机制

断点调试

在断点调试过程中, 是运行状态, 是以对象的运行类型来执行的.


文章作者: 冬瓜冬瓜排骨汤
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 冬瓜冬瓜排骨汤 !
  目录