Java 面向对象精讲【中】
简介
📢博客主页:https://www.infoq.cn/profile/F7BF297568FAA8/publish
📢欢迎点赞 👍 收藏 ⭐留言 📝 欢迎讨论!
📢本文由 XiaoLin_Java 原创🙉
📢不要等待机会,而要创造机会。✨
七、继承
面向对象的继承思想,可以解决多个类存在共同代码的问题
被继承的类,称之为父类、基类
继承父类的类,称之为子类,拓展类
父类:存放多个子类共同的字段和方法
子类:存放自己特有的字段和方法
7.1、继承的语法
在程序中,如果一个类需要继承另一个类,此时使用 extends 关键字
注意:Java 中类只支持单继承,不支持多继承,但是支持多重继承。也就是说一个子类只能有一个直接的父类,父类也可以再有父类。一个父类也可以有多个子类
Object 类是 Java 语言的根类,任何类都是 Object 的子类,要么是直接子类,要么是间接子类
7.2、子类可以继承到父类哪些成员
子类继承父类之后,可以拥有到父类的某一些成员(字段和方法),根据访问修饰符来判断:
父类中用 public 和 protected 修饰的成员,子类均可以继承
如果父类和子类在同一个包中,使用缺省访问修饰的成员,此时子类可以继承到
如果父类中的成员用 private 修饰,子类继承不到,因为 private 只能在奔本类中访问
父类的构造器,子类也无法继承,因为构造器必须和类名相同
7.3、方法的重写
当子类存在一个和父类一模一样的方法时,我们就称之为子类覆盖了父类的方法,也称之为重写。那么我们就可以在子类方法体中,重写编写逻辑代码
方法调用的顺序为:通过对象调用方法时,先在子类中查找有没有对应的方法,若存在就执行子类的,若子类不存在就执行父类的,如果父类也没有,报错。
方法重写需要注意的点:
private 修饰的方法不能被子类所继承,也就不存在重写的概念
实例方法签名必须相同(方法签名=方法名+方法参数列表)
子类方法的返回值类型和父类的返回值类型相同或者是其子类
子类方法中声明抛出的异常小于或者等于父类方法声明抛出的异常类型
子类方法的访问权限比父类的访问权限更大或者相等
一般开发都是直接拷贝父类的方法定义粘贴到子类中,重新编写子类的方法体
7.4、super 关键字
在子类中的某一个方法中需要去调用父类中被覆盖的方法,此时得使用 super 关键字。
如果调用被覆盖的方法不使用 super 关键字,此时调用的是本类中的方法。super 关键字表示父类对象的意思
7.5、抽象
抽象方法用 abstract 来修饰方法,被 abstract 修饰的方法具备两个特征:
该方法没有方法体
要求子类必须覆盖该方法
7.5.1、抽象方法
使用 abstract 修饰的方法,称为抽象方法
抽象方法的特点:
使用 abstract 修饰,没有方法体,留给子类去覆盖
抽象方法必须定义在抽象类或者接口中
7.5.2、抽象类
使用 abstract 修饰的类,称为抽象类
抽象类的特点:
抽象类不能创建对象,调用没有方法体的抽象方法没有任何意义
抽象类中可以同时拥有抽象方法和普通方法
抽象类必须有子类才有意义,子类必须覆盖父类的抽象方法,否则子类也得作为抽象类
7.6、Object 类和常用方法
Object 本身表示对象的意思,是 Java 中的根类,要么是一个类的直接父类,要么就是一个类的间接父类。任何类都直接(间接)继承了 Object 类
因为所有类都是 Object 类的子类, 所有类的对象都可以调用 Object 类中的方法,经常使用的方法有
7.6.1、boolean equals(Object obj)
boolean equals(Object obj):拿当前调用该方法的对象和参数 obj 做比较
在 Object 类中的 equals 方法和“ == ”符号相同,都是比较对象是否是同一个的存储地址。
7.6.2、toString 方法
toString 表示把对象中的字段信息转换为字符串格式
打印对象其实就是打印对象的 toString()方法,但是 toString()方法默认打印的是对象的 hashCode 的值
所以一般我们都会重写 toString()方法
7.7、== 符号详解
每一次使用 new 关键字,都表示在堆内存中创建一块新的内存空间
如果是基本数据类型:比较的是两个值是否相等
如果是对象数据类型:比较的是是否为同一块内存地址
八、多态
8.1、接口
接口是一种约定规范,是多个抽象方法的集合。仅仅只是定义了应该有哪些功能,本身不实现功能,至于每个功能具体怎么实现,就交给实现类完成。
接口中的方法是抽象方法,并不提供功能实现,体现了规范和实现相分离的思想,也体现了组件之间低耦合的思想。接口仅仅提供方法的定义,却不提供方法的代码实现
所谓耦合度,表示组件之间的依赖关系。依赖关系越多,耦合性越强,同时表明组件的独立性越差,在开发中往往提倡降低耦合性,可提高其组件独立性,举一个很简单的例子:
集成显卡:显卡和主板焊死在一起,显卡坏了,只能换主板
独立显卡:显卡和主板相分离,显卡插到主板上即可,显卡坏了,只换显卡,不用换主板
8.1.1、接口的定义
接口可以认为是一种特殊的类,但是定义类的时候使用 class 关键字,定义接口使用 interface 关键字,接口中的方法都是公共的抽象方法
注意:从 Java 8 开始, Java 支持在接口中定义有实现的方法
类可以继承类,但是只能单继承的,接口也可以继承接口,但是却可以继承多个接口,也就是说一个接口可以同时继承多个接口
8.1.2、接口实现类
和抽象类一样,接口是不可以创建对象的,如果想实现接口的功能,就必须定义一个类去实现接口,并且覆盖接口中的所有方法,这个类称为实现类,这种类和接口的关系称为实现关系
接口:定义多个抽象方法,仅仅定义有哪些功能,不做任何实现
实现类:实现接口,重写接口中的抽象方法,完成具体功能的实现
8.2、多态
在继承关系,是一种”is A”的关系,也就说子类是父类的一种特殊情况
此时我们可以认为猫和狗都是一种特殊动物,那么可以使用动物类型来表示猫或者狗
此时对象 animal 具有两种类型:
编译类型:声明对象时候的类型(Animal)
运行类型:对象真实的类型(Cat)
当编译类型和运行类型不一致的时候,多态就产生了
所谓的多态就是表示一个对象有多种形态,简单来说就是同一引用类型,由于引用的实例不同,对同一方法产生的结果也不同
多态一定建立在方法重写或者实现之上,可以是继承关系(类和类),也可以是实现关系(接口和实现类),在开发中,一般都指接口和实现类之间的关系,多态在在开发中有两种定义格式
8.2.1、操作继承关系(开发中不是很多)
父类引用变量指向于子类对象,调用方法时实际调用的是子类的方法
Animal 类:
Cat 类:
Test 类:
运行结果:
8.2.2、操作实现关系
ISwimable 接口:
Fish 类:
Test 类:
结果:
8.2.3、多态中方法调用问题
如果我们把子类对象赋值给父类对象
那么 animal 对象在调用 shout 方法的时候,他调用的是子类自己的方法还是父类的方法呢?
我们可以看得出,在编译时期,JVM 会先去找父类的方法,如果找到了就去找子类的同名方法,如果子类也有就运行子类的方法,否则就运行父类的方法,如果连父类的方法都没有找到的话,直接编译失败失败
8.2.4、类型转换和 instanceof 运算符
8.2.4.1、自动类型转换
自动类型转换:把子类对象赋给父类变量(多态)
8.2.4.2、强制类型转换
把父类类型对象赋给子类类型变量(前提:该对象的真实类型应该是子类类型)
当需要调用子类特有的方法时,必须经过强制类型转换,不过有一个要求:父类必须是真实的子类类型才可以转换
8.2.4.3、instanceof 运算符
判断该对象是否是某一个类的实例
语法格式
8.2.4.4、多态总结
面向接口编程,体现的就是多态,其好处:把实现类对象赋给接口类型变量,屏蔽了不同实现类之间的实现差异,从而可以做到通用编程
8.3、面试题
接口和抽象类的区别
接口中所有的方法隐含的都是抽象的,但是抽象类中可以同时包含抽象方法和普通方法以及静态常量
类可以实现很多个接口,但是只能继承一个抽象类
类如果要实现一个接口,那么他必须要实现接口声明的所有方法,但是类可以不实现抽象类中的所有方法,但是这个类必须是抽象类
接口中不存在构造方法,因为接口的成员变量都是 static final 变量,是在编译的时候就完成了初始化操作了,无需通过构造方法来进行初始化操作,而抽象类必须有构造方法
抽象类和接口的概念的区别:
抽象类是从一些类中抽取他们的共有的属性,方法的修饰符可以是 public 或者是 protected 以及缺省,抽象类注重对类本身的抽象,抽象方法没有方法体,仅仅是声明了该方法,让继承他的子类去实现
接口主要是对类的行为抽象,接口也可以有变量和方法,但是变量以及方法的修饰符必须是 public static final(缺省时会默认加上)和 public abstract(缺省时默认也是这个)
版权声明: 本文为 InfoQ 作者【XiaoLin_Java】的原创文章。
原文链接:【http://xie.infoq.cn/article/9825ee8890cc1880672c2ea80】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论