java-06 面向对象高级 封装 继承 多态
1.概述
java 面向对象的三大特性就是封装、继承 和多态。接下来会详细解释这三大特性的意义和作用
2.封装
2.1 封装的概念及作用
封装就是将类特有的属性隐藏起来,对外部只能是有特定的方式访问,同时,外部只需要调用该类实例的方法,并不需要知道该类实例的方法是如何实现的。就好比开车,我们只需要知道怎么开走一辆车,不需要知道发动机或其他部件是怎么工作的
作用:高内聚、低耦合。提高了安全性和可维护性,方便外界调用。
2.2 权限访问修饰符
权限访问修饰符是实现封装的重要部分。之前我们已经见到过一些权限修饰符例如public、 private等。接下来我们会详细了解他们之间的区别
2.2.1 四大权限访问修饰符
1. private (私有) 2.default (默认,就是不写) 3.protected (受保护) 4. public(公开)
2.2.2 四大访问修饰符的区别及作用域
1. private : 私有访问修饰符,被该修饰符修饰的属性或方法只有在本类才可以访问,其同一包中子类、不同包中的子类、同一包中的其他类、不同包中的其他类均不能访问。 私有级别最高。
2. protected:受保护访问修饰符,被该修饰符修饰的属性或方法本类可以访问、同一包中子类可以访问、不同包中子类可以访问、同一包中的其他类可以访问。不同包中的其他类不能访问。
3. default:默认修饰符(就是不写修饰符),被该修饰符修饰的属性或方法本类可以访问、同一包中的子类可以访问、同一包中的其他类可以访问,不同包中的子类不可以访问、不同包中的其他类不可以访问。
4.public: 公开修饰符,被该修饰符修饰的属性或方法在任何位置都可以被访问。
总结:private修饰只有自己可见、protected修饰子类和同一包可以访问、defult(不写修饰符)只有同一包中的类可以访问(不论是不是子类)、public修饰随处可见。
2.2.3 get/set方法
为了保证类属性的安全性,一般将类自己的属性全部私有化,然后提供公开(public)的方法用来修改或者获取属性的值,这一类方法写法很相似,获取统一用getXXX,设值统一用setXXX(XXX代表属性名)。
注意:这里对于boolean属性有一些特殊,获取boolean属性的值并不用getXXX 而是用isXXX
1 public class Person { 2 /** 3 * 属性全部私有化 使用get/set方法 4 */ 5 private String name; 6 private int age; 7 private boolean ismale; 8 9 10 public String getName() { 11 return name; 12 } 13 public void setName(String name) { 14 this.name = name; 15 } 16 public int getAge() { 17 return age; 18 } 19 public void setAge(int age) { 20 this.age = age; 21 } 22 //boolean 属性的get方法不使用getXXX 使用isXXX 23 public boolean isIsmale() { 24 return ismale; 25 } 26 public void setIsmale(boolean ismale) { 27 this.ismale = ismale; 28 } 29 }
2.3 封装的基本要求(建议)
-
把所有的属性私有化。
-
对每个属性提供
getter
和setter
方法。 -
如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。
-
建议重写
toString
方法,但这不是必须的。
-
3. 继承
3.1 继承的基本概念
继承是在现在已有的类中添加一些新的特有属性或方法,从而产生一个新的类的过程。新产生的类包含了原有的类的所有属性和方法(不严谨,先这么理解)。我们把被继承的类叫父类,新产生的类叫做父类的子类或派生类。
继承的实现方式: 实现接口、继承一个抽象类、继承一个普通类。
请注意,所有的类在不指明继承关系时,默认都会继承Object类,即使指明继承关系,也会间接继承Object类(因为他的父类会继承Object类) Object类是所有的类的老祖宗
3.2 接口与抽象类
java中有两种比较特殊的类,甚至我们不能称他们为一个正常的类,因为他们就是为了给别人继承的。 这两种特殊的类一个是抽象类、一个是接口。我们下面来详细的说一下这两种特殊的类。
3.2.1 接口
1. 概念:接口是java用来声明一系列方法的“类”,接口只提供类的声明或静态变量。换句话说,接口只是声明了一种标准,任何一个类实现该接口就必须实现这个标准。
2. 接口是不能被final修饰的,他只能被public 或 abstract 修饰。同样,接口中的常量只能是被public、static、final 修饰的,接口中的方法也只能被 public或abstract修饰(默认就是public的)
3. 接口的声明方式 [public] [abstract] interface 接口名 { 接口体 } ,同样接口是可以继承接口的(支持多继承)。但是接口不能继承类
4. 接口继承时使用extends关键字
3.2.2 抽象类
1.概念:抽象类是一种比较特别的类,该类中的方法既可以实现,也可以不实现,不实现的原因可能是该方法在不同的子类中有不同的实现方式。当我们遇到在当前类可以定义该方法但是无法实现时,可以使用抽象类。
2.抽象类是不允许创建对象的,并且抽象类一定有 abstract 修饰。同样 abstract修饰的类不能被private修饰的。该类中的方法可以实现,也可以不实现,若不实现,则需要使用abstract修饰。
3.抽象类声明方式 [public] abstract class 类名 { 类体 } ,抽象类可以继承类(单继承),也可以实现接口(多继承)
4.继承类使用 extends 关键字 ;实现接口使用 implements 关键字
3.3 单继承与多继承
java 中的类是不支持多继承的,但是java中的接口是支持多继承的。所谓多继承就是一个子类可以继承多个父类。
3.4 extends 与 implements
3.4.1 extends
extends 关键字用来继承一个类 或者 接口继承一个或多个接口
//接口的继承 可以多继承 public interface TestInterface extends Accessible,ThreadFactory{ void test(); } //类的继承 只能是单继承 public class TestClass extends Object{ }
3.4.2 implements
implements 关键字用来指明类实现哪一个接口,可以多实现(即多继承)
//类实现接口 使用 implements public class TestClass implements Runnable,Serializable{ }
3.5重写与重载
3.5.1 方法的声明
java类或抽象类或接口中都会有方法的声明 这里分别说一下这三种情况下方法的声明方式
1. 类中方法的声明 : [访问修饰符] [static] 返回值类型 方法名(参数列表) { 方法体 }
2. 抽象类中方法的声明 : 第一种是与类中的相同 。 但当我们声明不实现方法时 就有了一些变化 :[访问修饰符(一般public)] abstract 返回值类型 方法名(参数列表);(注意分号必须写)
3.接口中方法的声明: 返回值类型 方法名(参数列表); (注意分号必须写,修饰符不用写,默认public)
返回值:即是该方法执行完毕后所返回的值的类型 参数列表:即是该方法所接收的形式参数的列表
//1.普通类声明的方法 public String say(String word) { //方法体 return word; //返回值 } //2.抽象类声明的方法 public abstract void add(int a,int b); //3.接口中的方法 int sub(int a,int b);
3.5.2 方法的重载
概念: 当两个方法有相同的方法名,不同的参数列表的时候,成这两个方法是重载方法。
作用:可能方法对不同的参数做不同的处理,这时就要用到重载方法。如做相加操作,整数和小数一定是不同的,但是都是add方法,发生了重载
要求: 方法名必须相同,参数列表必须不同(不同是指类型不同或者个数不同或者类型的顺序不通均可)对返回值没有特殊要求(可以相同也可以不同)
发生地点: 同一类中的同名方法。
3.5.3 方法的重写
概念:当子类继承父类的方法时,可能会出现父类方法无法满足子类要求的情况,这时子类就要修改父类这个方法,称为方法的重写。
作用:子类可以覆盖掉父类的方法,实现自己想要的功能。
要求:方法名和参数列表必须相同。返回值范围小于等于父类(如果是引用类型,则必须与父类返回值相同或者是父类返回值派生类型的子类)。权限修饰符不能比父类方法更低。
注意:父类声明成final的方法是不能被重写的。同样,父类的static方法不能被重写,但是可以被子类再次声明。
3.6 super 关键字
super关键字用于在子类中调用父类的方法。 super();可以在子类中调用父类的构造方法,注意 super关键字只能写在方法的第一句。(构造方法默认调用,不写super也会调用父类构造方法)
3.7 属性查找
java 中的属性查找顺序是从当前类开始找起,若找到直接使用,若找不到则去其直接父类寻找,依次想上寻找,直到Object类,如果还未找到,则会报告一个错误。(注意子类属性覆盖父类属性的问题)
4.多态
4.1多态的概念
概念:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
实现多态的技术称为动态绑定,是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法 (重载方法和重写方法是多态的基础)
4.2 实现多态的条件
1.有继承关系的存在 2.有方法的重写 3.父类引用指向子类对象
4.3 多态的好处
1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和Sphere为了实现多态,完善或者覆盖这两个接口方法。
4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。
5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
5. final 、instanceof关键字与转型
5.1 final 关键字
用来修饰变量、属性、方法或类。
final 修饰的变量或者属性不可改变其值,只能进行依次赋值,一旦赋值以后就不能再改变其值了。
final 修饰的方法不能被子类重写,但是不影响重载
final 修饰的类不能被继承。
注意!final不能修饰接口!因为接口就是用来被继承的 而且接口只允许使用public和abstract修饰。
5.2 instanceof 关键字
instanceof 关键字用来判断一个实例引用是否为某一个类的对象 其返回值是一个boolean值
instanceof 关键字判断时,当一个实例是某个类的子类的实例,也认为该实例是这个父类的实例
总结:如果一个类的实例是这个类本身的实例,那么它也是它的父类、它的父类的父类的实例,也是由它实现的接口的实例
5.3 转型
当父类引用指向子类对象的时候,该引用只能调用父类中定义过的方法,无法调用子类新实现的方法,这时就需要用到转型,将父类引用转型成子类引用。
当转型不成功时会抛出一个 ClassCastException 异常。所以转型之前我们可以使用instanceof 关键字判断一下当前引用是否是我们期望转型成的对象,如果是再进行转型。