面向对象(三)

访问修饰符

在Java中访问修饰符有四种,用于对类、成员变量,成员方法的访问范围进行控制。

  • public,公开的,对外公开。
  • protected,受保护的,同包和子类都可以访问
  • 默认,同一个包可以访问
  • private,私有的,同一个类可以访问,对外不公开
访问修饰符 同类 同包 子类 不同包
public 可以 可以 可以 可以
protected 可以 可以 可以 不可以
默认 可以 可以 不可以 不可以
private 可以 不可以 不可以 不可以

类只能用public、默认修饰

面向对象的三大特征

封装、继承、多态

构造函数

  1. 子类必须调用父类构造器,完成父类的初始化
  2. 不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造函数,如果父类没有提供默认的无参构造函数,则必须在子类中使用super确定调用哪个父类的构造函数,否则就会报错,编译无法通过。如果想要显示调用某个父类的构造器使用super,super语句只能是第一条语句,this()和super()不能同时存在子类的构造函数中,只能写一个,都要在第一行。
  3. 所有对象都是Object类的子类,对父类构造函数的调用不限于直接父类,将一直向上追溯至Object类
  4. Java中只能单继承,每一个类只有一个直接父类
  5. 不能滥用继承关系

封装

在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。

要访问该类的代码和数据,必须通过严格的接口控制。

封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

封装的优点

  1. 良好的封装能够减少耦合。
  2. 类内部的结构可以自由修改。
  3. 可以对成员变量进行更精确的控制。
  4. 隐藏信息,实现细节。

继承本质

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

创建子类对象的时候,在内存里面发生了什么?建立查找关系,通过一个实例分析:

public class GrandPa {
    String name = "大头爷爷";
    int age = 100;
    String hobby = "旅游";
}

public class Father extends GrandPa{
    String name = "大头爸爸";
    int age = 30;
}

public class Son extends Father {
    String name = "大头儿子";
}

Java中的继承只能单继承,但是可以通过内部类继承其他类来实现多继承

继承的优点:
子类拥有父类的所有属性和方法(除了private修饰的属性不能拥有)从而实现了实现代码的复用;

继承初始化顺序
1、初始化父类再初始化子类
2、先执行初始化对象中属性,再执行构造方法中的初始化。
基于上面两点,我们就知道实例化一个子类,java程序的执行顺序是:
父类对象属性初始化---->父类对象构造方法---->子类对象属性初始化--->子类对象构造方法

super和this

super在对象的内部使用,可以代表父类对象。

  1. 访问父类的成员
  2. 用来区分子类和父类的成员
  3. 调用父类的构造函数,只能在子类的构造函数中调用,且只能是第一句,不能何this同时使用。

this在对象内部使用,可以代表当前对象。

1.访问当前对象的成员

2.用来区分形参和成员属性

3.调用对象的其它构造函数,只能在构造函数中使用,且只能是第一句,不能何super同时使用

方法覆盖

子类方法名和参数要跟父类一样,子类方法的返回值要么跟父类一样要么是父类的子类型;子类方法不能缩小父类方法的访问权限。

方法重写和重载的相同点和区别:

区别点 重载方法 重写方法
参数列表 必须修改 一定不能修改
返回类型 可以修改 一定不能修改
异常 可以修改 可以减少或删除,一定不能抛出新的或者更广的异常
访问 可以修改 一定不能做更严格的限制(可以降低限制)

方法的重写 (Overriding) 和重载 (Overloading) 是 java 多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

  • (1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载 (Overloading)。
  • (2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写 (Overriding)。
  • (3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

多态

多态分为:方法的多态和对象的多态

方法的多态:方法的重载和重写

对象的多态(重点)

几个重要的规则:

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

多态的细节

多态的发生,一定是两个类之间是存在继承关系

向上转型:父类引用指向子类对象,此时可以调用父类的所有成员,遵循访问修饰符,不能调用子类特有的成员。最终运行效果看子类具体的实现

向下转型:子类类型 引用名 = (子类类型)父类引用。只能强转父类的引用,不能强转父类的对象;要求父类的引用必须指向当前目标类型的对象;向下转型后,可以调用子类类型的所有成员;

属性没有重写之说,属性是没有多态,属性看的是编译类型

instanceof比较操作符,用于判断对象是否是某类型或者某类型的子类型,看的是运行类型

class AA{}
class BB extends AA{}
//编译类型是AA,运行时类型是BB
AA aa = new BB();

System.out.println(aa instanceof AA);//true 看的是运行时类型
System.out.println(aa instanceof BB);//true 看的是运行时类型

Java动态绑定机制(重点)

public class AA {
    public int i = 10;
    public int getI(){
        return i;
    }
    public int sum(){
        return getI() + 10;
    }
    public int sum1(){
        return i + 10;
    }
}
public class BB extends AA {
    public int i = 20;
    @Override
    public int getI(){
        return i;
    }

    @Override
    public int sum() {
        return i + 20;
    }

    @Override
    public int sum1() {
        return i + 10;
    }
}

AA aa = new BB();
System.out.println(aa.sum());//40
System.out.println(aa.sum1());//30



//当子类没有sum方法时候,怎么调用,使用方法的调用机制,一直向上找,在父类中发现有方法,就调用父类的方法,此时,发现父类方法中
//有有一个语句:getI() + 10,getI()在子类和父类中都存在,此时就会触发Java的动态绑定机制,来决定调用哪个方法

Java的动态绑定机制:
1.当调用对象方法的时候,该方法会和该对象的运行时类型绑定;

2.调用属性的时候,没有动态绑定机制,哪里声明,哪里调用;

public class AA {
    public int i = 10;
    public int getI(){
        return i;
    }
    public int sum(){
        return getI() + 10;
    }
    public int sum1(){
        return i + 10;
    }
}
public class BB extends AA {
    public int i = 20;
    @Override
    public int getI(){
        return i;
    }
}
//aa的编译类型是AA,运行时类型是BB
AA aa = new BB();
System.out.println(aa.sum());//30
System.out.println(aa.sum1());//20

当调用aa.sum方法的时候,先看方法的运行时类型为BB,先在类BB中查看,是否有sum方法,没有就会触发继承机制,在父类中查找,是否有sum方法,父类中存在,return getI() + 10;,这时会出现一个问题,getI在父类和子类中都存在,那么如何调用,这时就会触发动态绑定机制,方法会和运行时对象绑定,触发该方法的aa的运行时类型是BB,所以调用的是BB中的getI,所以输出的是20+10,输出30;,当调用sum1方法的时候,会使用同样的机制找到父类的方法sum1,此时语句为return i + 10;,属性没有动态绑定机制,哪里声明,调用哪里,先看AA中是否有i,发现有就返回10+10,输出20.

多态的应用

多态数组,定义父类对象数组,实际存放的是子类对象的实例

多态参数,形参是父类类型,实际传入的参数是子类类型

Object类

  1. equals方法

    经典面试题:== 与 equals的区别?
    == 是一个比较运算符,既可以判断基本类型也可以判断引用类型,判断基本类型判断的是值是否相等,判断引用类型,判断的是地址是否相同,即判断是不是同一个对象。

    equals是Object类的方法,只能判断引用类型,默认判断的是地址值是否相同,子类往往重写该方法,用于判断内容是否相同。

  2. hashCode

    1.提高具有哈希结构的容器的效率

    2.两个引用如果指向同一个对象,则哈希值一定一样

    3.两个引用如果指向不同的对象,则哈希值不一样

    4.哈希值主要根据地址来的,但不能完全将哈希值与地址等同

posted @ 2021-10-01 11:18  无涯子wyz  阅读(75)  评论(0)    收藏  举报