五:java面向对象

73 阅读7分钟

包的三大作用

  1. 区分相同名字的类
  2. 当类很多的时候,可以很好地管理类
  3. 控制访问范围

包的基本语法

package  xx.xxx

包的本质:实际上就是创建不同的文件夹保存类文件

image.png

java中常用的包

  1. java.lang.*
  2. java.unit.*
  3. java.net.*

访问修饰符

java一共提供了四种访问修饰符号,用于控制成员变量(方法)的访问权限

  1. public:公开
  2. protected:对子类和同一个包中的类公开
  3. 默认:没有修饰符,向同一个包中的类公开
  4. private:只有类本身可以访问,子类和其他都不能访问

背下此图(重要)

image.png

注意事项

  1. 只有默认修饰符和public才能修饰类,protected和private只能修饰类中的属性,方法,不能修饰类本身。

封装

定义:把抽象出来的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(方法),才能对数据进行操作。

封装的好处:

  1. 隐藏实现的细节,调用者不用关心实现细节
  2. 对数据进行验证,保证安全合理

封装实现步骤:

  1. 将属性私有化private(不能直接修改)
  2. 提供一个公共的(public)set方法,用于对属性的判断和赋值
  3. 提供一个公共的(public)get方法,用于获取属性的值
public void setXxx(类型 参数名) {
    // 验证...
    属性 = 参数名
}

public XX getXxx() {
    // 权限判断
    return xx
}

继承

为什么需要继承

  1. 提升代码复用性。继承可以解决代码复用,让编程更加接近人类思维,当多个类存在相同的方法和属性的时候,可以抽象出父类,在父类中定义这些相同的方法和属性,所有的子类不需要重新定义这些属性和方法,只需要通过extends关键字继承。
  2. 代码的扩展性和维护性提高了

image.png

继承的细节

  1. 子类不能访问父类的私有属性和私有方法,应该通过父类提供的公共方法去访问。
  2. 子类必须调用父类的构造器,完成父类初始化。本质是在子类的构造器里面默认写了个super()函数调用,这个函数就是执行父类无惨构造器的的意思。
class Child extends Person {
    public Child() {
        // 系统默认自带这句话并执行          
        // super()
    }
}
  1. 当创建子类的时候,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则需要子类的构造器中使用super去指定使用父类中的哪个构造器,否则编译不通过。
  2. 如果希望调用指定的父类构造器,则需要显式调用一下super(参数列表)
  3. super在使用时候,必须放在构造器的第一行。
  4. super()和this()都只能放在第一行,因此这两个不能同时存在同一个构造器中。
  5. Object类是所有类的父类(基类)
  6. 父类构造器的调用不限于直接父类,将一直往上追溯到Object类。
  7. java是单继承机制,子类只能继承一个父类。

继承的本质(重要)

image.png

super关键字

super代表父类的引用,用于访问父类的属性,方法,构造器。super不能访问父类的私有属性。

class Child extends Person {
    public Child() {
        // 访问父类的构造器
        super()
        // 访问父类的属性
        System.out.println(super.name);
    }
}

super细节

  1. 好处:当子类的父类方法或者属性重名的时候,可以通过这种方法调用。
  2. super的访问不限于父类,如果爷爷类也有对应的成员,也可以使用super去访问,多个基类的访问遵循就近原则。

super和this的比较

image.png

方法的重写/覆盖overrite

注意细节:

  1. 子类的方法名和参数要和父类完全一致。
  2. 子类的返回类型和父类的返回姚磊要一样,或者子类的返回类型是父类的返回类型的子类。
  3. 子类方法不能缩小父类方法的访问权限。

重载和重写的异同

image.png

多态

方法或对象具有多种形态,是面向的对象的第三大特征,多态是建立在继承的基础上。

对象的多态(重要)

  1. 一个对象的编译类型和运行类型可以不一致
  2. 编译类型在定义对象的时候就确定了,不能改变
  3. 运行类型可以改变
  4. 编译类型看定义时等号 的左边,运行类型看等号的右边。

多态的注意事项

  1. 多态的前提是:两个对象(类)存在继承关系
  2. 多态的向上转型
  3. 多态的向下转型

本质:

  1. 父类的引用指向了子类的对象
  2. 语法: 父类类型 引用名 = new 子类类型();
  3. 特点:编译类型看左边,运行类型看右边。
  4. 可以调用父类的所有成员(要遵循访问权限),但不能调用子类的特有成员,因为在编译阶段,能调用哪些成员是由编译决定的,最终运行效果看子类的具体实现。
  5. 属性没有重写的概念,属性的值看编译类型。

java动态绑定机制(重要)

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定。
  2. 调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用。
public class Main {
    public static void main(String[] arr) {
        B b = new B();
        // 由于B类没有sum方法,所以调用父类的sum方法,父类的sum方法调用子类的getI方法得到i为20,
        // 为什么是调用子类的getI方法,因为java规定,调用对象的某个方法的时候,该方法会和该对象的内存地址进行绑定,
        // 也就是你new了B类,调用方法的时候,永远先使用B类中的方法。
        System.out.println(b.sum()); // 20 + 10 = 30
        // 调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用,也就是调用了父类的sum1方法,那么父类中的变量i就直接拿父类的,
        // 但是如果是方法的话,则会编程还是拿子类的
        System.out.println(b.sum1()); // 10 + 10 = 20

        // 一句话总结:属性就行,方法看运行
    }
}
class A {
    public int i = 10;
    public int sum() {
        return getI() + 10;
    }
    public int sum1() {
        return i + 10;
    }
    public int getI() {
        return i;
    }
}

class B extends A {
    public int i = 20;
    public int getI() {
        return i;
    }
}

一句话总结:属性就近,方法看运行

多态的应用

  1. 多态数组:数组定义为父类类型,里面保存的实际元素为子类类型
  2. 多态参数:方法定义的类型为父类类型,实际传参为子类类型

Object类详解

每个类都是使用Object类作为超类,所有对象(包括数组)都实现这个类方法(和JavaScript是一样的)

equals方法

==和equals的区别(经典面试题)

==是一个比较运算符

  1. ==既可以判断基本数据类型,又可以判断引用类型
  2. ==如果判断的是基本类型,则判断值是否相等
  3. ==如果判断的是引用类型,则判断的是内存地址是否相等

equals方法

  1. equals是Object类中的方法,只能判断引用类型
  2. 默认的判断是地址内存地址相等,子类中往往重写该方法,用于判断

hashCode方法

返回该对象的哈希码值。

  1. 两个引用,如果指向同一个对象,哈希值肯定一样。反之则不一样
  2. 哈希值主要是根据地址来生成的,但不是完全等于地址

toString方法

返回该对象的字符串表示,默认返回的是:全类名 + @ + 哈希值的十六进制。

Egg egg = new Egg();
System.out.println(egg.toString()); // Egg@2f4d3709

class Egg {
    public int i = 10;
    public int sum() {
        return this.i + 10;
    }
}

finalize方法

当垃圾回收器要回收一个对象的时候,就会先调用这个方法,系统自动调用。

作用:这个方法默认什么都不做,但如果我们重写这个对象,那么就可以加入自己的逻辑,然后等垃圾回收的时候这个函数自动被调用。

注意细节:垃圾回收器,不是一个对象变成垃圾后,对象立刻就会被回收,而是有时机的(GC算法)。

这个函数实际开发很少用,但面试喜欢问。