Java基础(二)

1. 访问控制权限

Java的四种访问控制权限

  • Java权限修饰符,可见关键字的为public、protected、private,实际上当省略权限修饰符时,也对应一种权限

  • 这种权限被称为default权限,或包访问权限。

  • 也就是说,被default权限修饰的类、类中的成员变量/方法,只能被同一包中的其他类访问

  • 四种访问控制权限的限定范围如下

    访问控制权限同一个类同一包中的其他类不同包中的子类不同包中的其他类
    publicYesYesYesYes
    protectedYesYesYes
    defaultYesYes
    privateYes

自己的理解

  1. public权限: 相当于没有权限控制,其他任何类都可以访问
  2. protected权限: 继承权限。当某些类中的成员不想向其他包中的所有类开放,只想向其子类开放时,可以使用该修饰符。
    这时,子类通过继承,可以访问父类中的protected成员
  3. default权限: 包访问权限。出于某些原因,类或类中的成员只能对同一个包中的类开放,这时可以使用default权限。
  4. private权限: 私有权限,只能被自己访问

一些总结

  1. 类中的成员变量,最好不使用public修饰符,避免客户端对其随意修改。最好使用private修饰符,通过gettersetter方法,提供访问入口
  2. 创建父类时,如果不想父类的成员是公开的,可以使用protected修饰符,使其只能被子类访问
  3. Java中,外部类只能被public和default修饰,内部类则可以被所有的修饰符修饰。
    此时,内部类就当于是外部类的成员。因此,可以被所有的修饰符修饰

附带:Java文件名与类名的一些规定

  • 一个Java文件中只能有一个public类,可以有任意个default类
  • 如果Java文件中存在public类,则public类的类名必须与Java文件名一致
  • Java文件中只有default类,则Java文件名可以任意命名,但不建议这样做。

2. 构造函数

  • 类的实例化需要调用类的构造函数实现

构造函数的分类

  • 无参构造函数: 没有入参的构造函数,称为无参构造函数。
    (1)若没有在类中定义构造函数,编译器会自动生成一个无参构造函数,其方法体为空
    (2)为了与自定义的无参构造函数相区别,编译器自动生成的无参构造函数被称为默认构造函数
  • 有参构造函数: 拥有一个或多个参数的构造函数,称为有参构造函数
    (1)如果自定义了有参构造函数,编译器不会自动生成无参构造函数,需要显式定义无参构造函数
    (2)有参构造函数可以在类实例化时,传入一些参数以初始化类中成员变量

构造函数的特点

  • 返回值: 构造函数无返回值,连void也不可以
  • 命名: 构造函数名与类名一致,成员方法也可以与类名一致,但必须右返回值
  • 默认构造函数: 未定义构造函数,编译器自动生成一个无代码的默认构造函数;如果已经定义构造函数(有参/无参),则编译器不会生成默认构造函数;如果只定义了有参构造函数,则类不会有无参构造函数
  • 调用次数: 构造函数在类实例化时调用(伴随着new操作),在对象的整个生命周期,只能调用一次;而普通成员方法,在程序执行到时被调用,可以调用无数次
  • 重载: 构造函数只能重载,不能重写,要求参数类型、个数和顺序至少有一个不同

子类与父类中的构造函数

  • 继承: 子类只能继承父类的无参构造函数(暂不理解为啥 😂)
  • 实例化: 子类实例化,会先调用父类的构造函数,再调用子类的构造函数
    (1)默认调用父类的无参构造函数;如果父类不存在无参构造函数,要么构建无参构造函数,要么显式调用父类的有参构造函数
    (2) 父类构造函数的调用,通过super()super(args ...)实现,必须在子类构造函数的第一行
    (3)通过super.func()super.func(arg ...),可以在程序的任意位置访问父类的普通成员方法
  • 权限访问控制: 构造函数的默认修饰符,与所属的类修饰符保持一致;当然也可以显式定义成任意的访问控制权限

3. Java的特性

封装

  • 本人认为:封装就是隐藏类的属性或实现细节,通过对外暴露接口,实现对类的访问或操作
  • 例如,我们一般将类的属性设置为private,通过public修饰的getter或setter方法,实现对其属性的访问或修改
  • 通过封装,将类的属性和方法组织到了一起;借助权限修饰符,实现对成员的访问权限控制

继承

  • 某些类之间拥有相同的属性或方法,可以相同的部分抽取出来构成基类
  • 其他类通过继承基类,便可以拥有基类的属性或方法
  • 基类被称为父类,继承基类的类叫做子类
  • 当类之间,存在IS - A的关系时,可以使用继承
  • 目的: 通过继承,可以实现代码的复用,

多态

  • 我们常常希望这样:这个类看起来是一只Animal,但执行其play()操作时,才知道原来这是一只蹦蹦跳跳的小兔子
  • 所谓多态,就是引用指向的对象、由引用发出的方法调用,在编译时无法确定,只有在程序运行时才能确定
  • 这样就可以不用更新程序,就能在程序运行时绑定不同的代码,使程序呈现不同的状态
  • 多态的三个前提:继承、重写、向上转型(父类引用指向子类对象)
    (1)只有通过继承,才能使得父类和子类拥有相同的属性或方法。
    (2)通过重写,可以使得子类具有自己的特定行为,使得相同的方法在父类和子类中具有不同的状态
    (3)向上转型,使得程序执行时,可以调用子类方法
    (4)不恰当的比喻 😂 :将多态比作逛四季园,继承是入园的大门,长得都一模一样;不真正进入,是无法知道自己选择的是哪个季节。重写是园中景色的布置,使其符合不同的季节主题。向上转型,是说通过一张未刮开的门票,决定最终进入哪个园子

4. 抽象与接口

4.1 抽象类与抽象方法

  • abstract关键字修饰的类,称为抽象类;被abstract关键字修饰的方法,称为抽象方法

抽象类和抽象方法的规则

  1. 定义: 抽象类,可以可以没有抽象方法;一个类包含抽象方法,必须被定义为抽象类
  2. 实例化: 抽象类无法实例化,只有继承抽象类、实现了抽象类中所有抽象方法的子类才能被实例化
  3. 访问权限: 抽象类的访问权限为public、default,抽象方法为public、protected、default。JDK 1.8 以前,抽象方法的默认访问权限为protected,1.8时为default
  4. 单继承: 子类只能继承一个抽象类,必须实现抽象类中所有的抽象方法;否则,子类也需要声明为抽象类
  5. static、final: 抽象类,不能使用final修饰;只有内部抽象类,才能使用static进行修饰;抽象方法不能使用static、final修饰;
    (1)抽象类需要被子类继承,不能使用final进行修饰
    (2)抽象方法需要被子类重写,不能使用final进行修饰
    (3)static修饰的方法属于类方法,可以直接通过类进行调用,而抽象方法不允许被调用。
    (4)static类,必须是内部类
  6. 普通类: 抽象类和普通类一样,可以有自己的成员变量、构造函数、普通成员方法
  7. 子类必须继承父类的一个构造函数(自己认为:子类必须 “重写” 父类的构造函数)

4.2 接口

  • 通过interface关键字修饰的类,实际并非为一个类

接口的特性

  1. 方法: 在JDK 1.8之前,接口中的方法都是public abstract方法,接口被叫做完全抽象类;JDK 1.8开始,允许定义default方法,使其不再是完全抽象类
  2. 成员变量: 接口中的成员变量都是public static final
  3. 多实现: 一个类可以实现多个接口
  4. 实例化: 接口无法实例化,也不包含构造函数

抽象类与接口的区别

  1. 设计层面: 抽象类提供了一种 IS-A 关系,接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约。
  2. 使用: 一个类只能继承一个抽象,可以实现多个接口
  3. 构造函数: 抽象有构造函数,接口没有
  4. 成员方法: 抽象类不仅可以拥有抽象方法,还可以拥有普通成员方法;抽象类中的方法可以有多种访问权限;接口中的方法只能为public abstract
  5. 速度: 抽象类速度更快,接口需要时间寻找类中的实现方法 —— 不是很理解 😂

5. 重写与重载

5.1 重写(Override)

  • 重写,又称覆盖,是子类与父类间的多态性
  • 子类重新定义父类中的方法,方法名和参数列表都相同,则称子类重写了父类的方法

为什么又称覆盖?

  • 子类重写了父类的方法,当子类调用该方法时,系统将自行调用子类的该方法,而不是父类的该方法。
  • 看起来就像是子类中的方法,后来者居上,覆盖了父类中的方法

如果想调用父类中的方法?

  • 由于子类重写了父类中的方法,导致系统自行调用子类中的该方法。
  • 如果想要调用父类中的该方法,可以使用super关键字,显式调用父类中的该方法

重写的规则

  1. 一个前提: 子类中的方法名和参数列表,必须与父类中的保持一致
  2. 子类方法的访问控制权限必须 >= 父类方法的访问控制权限
  3. 子类方法返回值、抛出的异常,必须为父类方法返回值、抛出的异常的同类或子类

5.2 重载(Overload)

  • 重载,是同一个类的多态性
  • 定义一个与类中已有方法同名,但参数类型、个数、顺序至少有一个不同的新方法,称为方法的重载
  • 注意: 参数顺序不同,并非简单地交换入参名字,必须要求参数类型要不同。public void hello(int a, int b)public void hello(int b, int a) 属于同一个方法,并非方法重载

重载的多态性

  • 方法名相同,但参数不同
  • 通过传入的参数,自动匹配对应的方法,从而实现同一个类的多态性

重载的规定

  1. 方法名相同,参数类型、个数、顺序至少有一个不同
  2. 访问权限、返回值、抛出的异常,都不做要求

5.3 重写与重载

重写与重载的比较

  1. 重写要求方法名和参数列表必须相同,而重载要求方法名相同、参数列表不同
  2. 重写对访问控制权限、返回值、抛出的异常都有要求,而重载不做任何要求
  3. 重写是父类与子类间的多态性,重载是同一个类的多态性

当存在复杂的继承关系时,调用一个类中的方法,会存在如下的查找链

  1. this.fun(A),先查看当前类中是否存在对应的方法
  2. super.fun(A),再查看子类是否继承了父类对应的方法
  3. this.fun(A.super), 对参数进行向上转型,看当前类中是否存在对应的方法 (A.super表示入参A的父类)
  4. super.fun(A.super),对参数进行向上转型,看子类是否继承了父类对应的方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值