面向对象三大特征

封装


封装是什么
封装(encapsulate)是指将数据及相关操作绑定在一起的一种编程机制,使其构成一个不可分割的独立实体。

对象代表什么,就得封装对应的数据,并提供数据对应的行为

封装的好处

  • 使用者能够完全得到自己想要的功能,又不需要思考过多的细节
  • 实现则会可以隐藏功能实现的细节,方便灵活修改而不影响使用者使用
  • 可以对数据进行验证,保证安全合理

封装的实现步骤
从语法角度来说,Java中的封装是依赖于访问权限修饰符来实现

  1. 完全不需要被外界知道的属性,在类中可以私有化
  2. 提供公共的(public) set方法,用于对成员变量判断并赋值
  3. 提供一个公共的(public) get方法,用于获取成员变量的值

继承


语法定义

继承是干什么的
Java在定义一个类时,可以显式地,直接让它继承另一个类,让类和类之间产生父子的关系
可以把多个子类中重复的代码抽取到父类中,子类可以直接使用
减少代码的冗余,提高代码的复用性,这就是Java的继承机制

继承的本质是成员的复用

继承的语法

	[访问权限修饰符] class 类名(子类) extends 被继承的类(父类){}

子类特点
子类可以得到父类的属性和行为,子类可以直接使用
子类可以在父类的基础上增加新的功能,使其更加强大

继承关系

被继承的类称之为 父类,继承父类的叫做 子类

Java只支持单继承,不支持多继承,但支持多层继承

每一个类都直接或间接的继承于 [[2.6 Object]]

从属关系(relation)上来说,继承中的父子类具有 “is-a” 关系。即子类 “is-a” 父类。子类可以近似地看成是一个父类,子类可以当作父类来使用

子类可以继承哪些内容

父类的内容非私有修饰private修饰
构造方法不能不能
成员变量
成员方法虚方法表 能否则 不能
[[虚方法表]]
访问权限修饰符
  1. private:只能够在同一类中能够访问,私有的,外面谁都不能用。

  2. (缺省的)不写任何关键字:同一包中的子类或者其它类能够访问,同包中都可以使用。

  3. protected:不同包的子类能够访问。

  4. public:不同包的其他类能够访问,相当于没有做访问权限。

publicprotected(缺省)private
同类
同包其他类
不同包子类
不同包其他类
子类对象的初始化

子类的类加载会触发父类的类加载,且类加载的顺序是“先父后子”的

流程

  1. 父子类加载(先父后子)
  2. 创建子类对象
    • 子类对象中会专门开辟一片独立的区域,用来存储父类的成员变量(父类成员区域, 近似看成一个父类对象, 被super关键字指向, 近似看做super指向当前子类对象的父类对象)
    • 子类自身的成员仍会存储在自身对象当中(this指向当前子类对象)
  3. 父子类成员赋值(先父后子)
    • 默认初始化
    • 显式赋值
    • 构造代码块赋值
    • 构造器赋值

父类的构造器优于子类的构造器执行

  • super关键字可以在子类构造器或成员方法中,用于调用父类构造器或父类成员
  • 在一个类的构造器中,如果第一行没有用 this/super 去调用其他构造器,那么一定隐含一个 super(); 表示调用父类的无参构造器,这种通过隐含 super() 的方法叫做 “子类对象的隐式初始化
  • 无参构造器是不能给成员变量赋值的,在创建子类对象时,如果希望能够给父类成员赋值,就必须在子类构造器第一行写 super(实参列表); 直接指出调用父类哪个构造器,这种方式称为 “子类对象的显式初始化
引用数据类型的类型转换

引用数据类型转换和前提 → 继承

转换是什么
引用数据类型变量 = 引用 + 对象
对象只能改变状态,所以 只能是转换了引用的类型

// 父类引用指向子类对象
Father fs = new Son();

// 上述代码可以写成:
Son s = new Son();
Father fs2 = s;

// 改变的是引用的类型,原始对象并没有发生变化

类型转换分类

  • 自动类型转换
    把子类引用转换成父类引用,即 “向上转型”
  • 强制类型转换
    把父类引用转换成子类引用,即 “向下转型”
继承中对象的访问特点
成员变量

就近原则:谁离得近就用谁

public class Fu{
	String name ="Fu";
}
public class Zi extends Fu{
	String name ="Zi";
	
	public void ziShow(){
		String name = "ziShow";
		System.out.println(name); // ziShow
		System.out.println(this.name); // Zi
		System.out.println(super.name); // Fu
	}
}
  • 出现同名成员变量:
    • name局部位置开始往上找
    • this.name本类成员位置开始往上找
    • super.name父类成员位置开始往上找
成员方法

当父类的方法不能满足子类现在的需求时,需要进行 [[#方法的覆盖/重写|方法重写]]

构造方法
  • 父类中的构造方法不会被子类继承,但可以通过 super关键字 调用
  • 子类构造方法的第一行都有一个默认的 super();
  • 子类中所有的构造方法默认先访问父类中的无参构造,再执行自己
    • 为了调用父类方法前先完成父类数据空间的初始化
  • 如果想调用父类的有参构造,需要在 super(); 中写入参数
super关键字

super关键字 代表父类存储空间,即指向当前类的 父类“对象”的一个引用

  • this 代表当前类的当前对象
  • super 代表当前类的父类对象

两者比较大的区别:this在当前类中不受访问权限控制,super访问父类成员受访问权限控制

关键字访问成员变量访问成员方法访问构造方法
thisthis.成员变量this.成员方法this.(…)
supersuper.成员变量super.成员方法super.(…)
继承中的方法重写

方法的覆盖,也叫方法的重写(override),指在子类中,拥有和父类同名的成员方法,并且能够改写这个父类成员方法的内容

方法重写的本质是:覆盖了 虚方法表 中的方法

格式

// 父类方法
public void test(){
	System.out.println("father");
}

// 子类方法
@Override
public void test(){
	System.out.println("son")
}

@Override重写注解

  1. @Override写在重写后的方法上,用于校验子类重写时语法是否正确
  2. 语法错误时会有红色波浪线
  3. 重写方法都要加@Override注解,代码安全

注意事项

  1. 重写方法的名称、形参列表必须与父类中严格保持一致
  2. 子类重写父类方法时,访问权限必须大于等于父类
  3. 子类重写父类方法是,返回值类型必须和父类保持兼容
  4. 建议:重写的方法尽量和父类保持一致
  5. 只有被添加到 虚方法表 中的方法才能被重写
优缺点
  • 优点
    • 继承的出现减少了代码冗余,提高了代码复用性
    • 继承的出现有利于功能的扩展,提升了程序的可维护性,更好地应对需求变更
    • 继承是[[#多态|多态]]的前提
  • 缺点
    • 子类继承父类必须无条件的接受父类的所有成员
    • 父类中队成员进行修改,会严格体现到每一个子类中
final关键字

final有最终的、最后的意思
他是一个修饰符,可以用来修饰:

  • 方法:不能被重写
  • :不能被继承
  • 变量:常量
修饰方法

final修饰方法表示最后的方法,最终的方法,表示该方法无法被重写 (但是仍然可以被继承)

语法

[访问权限修饰符] final 返回值类型 方法名(形参列表){
		方法体
}

注意事项

  • final修饰成员方法,表示该方法无法被重写,但是仍然是可以继承的。

  • 什么样的成员方法应该设置为final呢?

    1. 方法的设计已经比较完善,不需要子类进行修改了,子类只需要乖乖继承,使用父类的实现即可。比如一旦修改就会导致问题、bug等时,就可以设置为final修饰。
    2. 写规则,即便是父类的方法不是很完善,但只要是希望子类不要改写方法都可以这么做。(要么你就用,不爽你就自己实现一个)
  • 日常开发,程序员还是比较 少见 有需要把方法设置成final修饰的。同样比较多见于JDK源码中,比较常见的有:像Object类中的getClass()方法.

修饰类

final修饰类时,表示最后的类,最终的类。
即表示这个类不能被继承。

语法

 [访问权限修饰符] final class 类名{  
	 //类体  
 }

注意事项

  • 什么样的类需要设置成final?

    • 不需要或不想要被子类继承的类,才需要设置为final修饰。
    • 当你认为当一个类的设计已经足够完善,功能足够强大了,不需要再让子类去扩展它了。
    • 这时出于安全的考虑,就可以将一个类设置为final。这样类中成员,既不会被继承,更不会被修改。
  • 正常情况下,我们很少会主动把一个类设置成final,因为没有太多的必要性。实际开发中,也要 慎重 将一个类设置final。

  • 常见的final修饰的类,都在JDK的源码当中。比如四类八种基本数据类型的包装类、Void、String、System、Scanner等等。

修饰变量
局部变量
  • 方法体
    • 用final修饰后表示该变量一旦声明并初始化赋值,就不可再修改它的取值了
  • 方法的形参列表
    • 用final修饰形参后表示实参一旦传入就无法在方法体中修改了
成员变量

final修饰成员变量表示该成员变量变成了一个 常量
它在内存中的位置,生命周期,使用方式等都不会改变。

语法

[访问权限修饰符] final 数据类型 变量名;

成员常量的赋值,有且必须有一次

有些固定的变量,比如 PI 的值,可以用final修饰

常量

  • 在实际开发中,常量一般作为系统的配置信息,方便维护
  • 命名规范:全部大写,单词之间用下划线隔开
静态成员变量

静态成员常量: 静态属于类。 在类中只有一份。

final修饰静态成员变量表示一个静态的"常量",在 类的全局仅有一份,所以final修饰静态成员变量,也称之为 “全局常量”
它是一个真正意义上的常量,不会因为创建对象而更改,实际开发中的常量多使用它。

语法

[访问权限修饰符] static final 数据类型 变量名;
引用数据类型

final修改基本数据类型:记录的值不能发生改变
final修饰引用数据类型:记录的地址值不能发生改变,内部的属性值还是可以改变的

语法

final 类名 对象名 = new 类名(参数);

多态


概念

同类型的对象,表现出的不同形态
即:

  1. 同一种事物
  2. 不同的情况
  3. 不同的状态

发生条件

  • 必须存在 继承,多态一定发生在父子类之间
  • 必须存在方法重写
  • 必须存在父类引用指向子类对象
调用成员的特点

对象的创建

  1. 创建父类对象,用父类引用接收,用对象名. 访问
  2. 创建子类对象,用子类引用接收,用对象名. 访问
  3. 创建子类对象,用父类引用接收,用对象名. 访问

访问范围
访问范围是由 引用的数据类型 决定的

  1. 如果引用是父类类型,那么访问范围只有父类及以上
  2. 如果引用是子类类型,那么访问范围是子类+父类

访问结果
访问结果是由 对象的实际类型 决定的

  1. 如果对象是一个子类类型,方法调用要体现出子类的行为
  2. 如果对象是一个父类类型,方法调用的结果就是父类行为

对于成员变量: 编译看左边,运行看左边
对于成员方法: 编译看左边,运行看右边.

优缺点

优点

  • 要实现多态必须要继承,而继承提高了代码复用率,提升了程序的可维护性
  • 使用多态后,用父类引用指向不同的子类对象,之后只需要调用同名方法,就能自动根据不同的子类对象得出不同的行为,大幅度简化代码
  • 在多态形式下,右边的对象可以实现解耦合,即可以随时更改对象名

缺点

  • 父类引用限制了子类对象的功能,这意味着子类独有的成员是无法使用父类引用访问的
  • 而如果这时候需要访问子类独有成员的话,就需要 强转引用数据类型,且是“向下转型”,稍有不慎就会产生异常

所以强转能够成功的前提条件是:
引用所指向的真实对象,必须是强转后的引用能够指向的对象。所以可以是强转后的引用的类型的对象或者子类对象

父类的引用转换成子类的引用,在继承链中属于向下,属于"向下转型"。编译器默认不允许,需要显式地写代码完成类型转换。

语法:

子类类名 对象名 = (子类类名) 父类引用
instanceof关键字

向下转型 是一种强转,它成功的条件相对比较苛刻。在操作之前,要先慎重考虑。

强转失败会导致程序抛出异常:ClassCastException,导致程序终止执行。
正是由于强转的条件苛刻,而且失败后果很严重,所以Java当中提供了检测手段,来保障强转的安全性。
需要使用关键字: instanceof

语法

引用名 instanceof 类名

上述语法返回一个boolean类型值:

  1. true表示该引用指向的对象,是后面类名的一个对象或者子类对象。

  2. 反之,false则表示不是。

  3. 当引用指向null时,使用该语法,结果会直接返回false。

总结

  • 强转类型可以转换成真正的子类类型,从而调用子类独用的功能
  • 转换类型与真实对象类型不一致时会报错
  • 转换时用instanceof关键字进行判断
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值