第七章 封装、继承,多态,接口,抽象
封装:
封装,即隐藏对象的属性和实现细节,仅对外公开接口(方法/函数),控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中属性数据和函数都是类的成员。
封装的目的:是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员。
Java中的封装:
广义来说:一切公共代码的抽取都可以叫封装。
一般体现在公共方法的封装。工具类。
狭义来说:隐藏对象的属性和实现细节。
将属性私有化 ,使用private关键字修饰。
为使用private关键字修饰的属性添加 get和set方法。通过get和set方法来操作属性。
setAge()设置/getAge()获取
通过private关键字将年龄私有化,通过提供的setAge()方法去给年龄设置值。并且在setAge()方法中设置年龄的大小范围。从而达到一个目的:既能隐藏了对象的属性,又可以隐藏实现的细节。
封装的作用:封装的作用在于保护或者防止代码(数据)被我们无意中破坏。在面向对象程序设计中数据被看作是一个中心的元素并且和使用它的函数(方法)结合的很密 切,从而保护它不被其它的函数意外的修改。
封装的情形:
什么情况下封装:
编写实例类时,用到封装有很多好处,其中比较实际的是:拒绝直接调用声明字段,保护内部数据,更安全;
重复调用,避免代码冗余,程序编写效率高
继承:
继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。
继承(英语:inheritance)。这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
如果某类B“继承”另某类A,就把这个B称为“A的子类或派生类(subclass)”,而把类A称为“B的父类”也可以称为“A是B的超类或基类(superclass)”。
继承的作用:
- 提高代码的可重用性
- 起到扩展功能的作用
Java的单继承:
[权限修饰符] class 子类名 extends 父类名{}
方法重写:在Java和其他一些高级面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
重写和重载的区别:
重载(overload):发生在同一个类中 , 方法名相同,参数列表不同,不考虑返回值。
重写(override):发生在父子类中,子类继承父类的方法,方法名相同,参数也相同,但是实现方法体不同。
什么是多态
多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作(摘自“Delphi4 编程技术内幕”)。简单的说,就是一句话:允许将子类类型赋值给父类类型。
多态的前提是继承和方法重写。
多态:父类对象表现多种子类的形态的能⼒的特征,⼀句话多态就是⽗类引⽤⼦类对象。 向同⼀个⽗类的不同⼦类发送同⼀条消息,⾏为不同。
父类指向子类的内存地址
3. 向上转型
向上转型:⽗类引⽤⼦类对象(⾃动成⽴,缺点是失去调⽤⼦类独有⽅法的能⼒)
向上转型后该对象只能当成父类对象来用,原来子类中定义的属性和方法就被屏蔽掉不能被调用了。比如狗里有一个【看门】的方法,如果向上转型后作为【动物】类就不能调用dog类独有的【看门】的方法。
总结: 向上转型 从小的转向大的 缺点:不能调用子类里面的特有的方法
4.向下转型
向下转型:⼦类引⽤⽗类对象(强制转换,慎重)
此时可以调用子类对象中的方法和属性。
注意事项:ClassCastException
以上为继承多态 占据5% 继承多态。
继承多态,接口多态95%。
向下转型: 大的转化为小的 缺点:强制类型转换 ClassCastException类型转换异常
抽象的父类只有相应的行为,但是不具体。具体的行为要在每一个具体的子类中才有。
3.抽象方法和抽象类的格式
抽象类的存在不是为了创建对象,是为了让子类继承用的。
抽象类:使用abstract关键字修饰的类。
Java
[权限修饰符] abstract class 类名{}
抽象方法: 使用abstract关键字修饰的方法 注意:抽象方法没有方法体,也没有{}
Java
[权限修饰符] abstract 返回值 方法名();//没有大括号
4.抽象类和抽象方法使用
封装了⼀个类,但是这个类不能实例化---定义成抽象类。好处是让所有的⼦类必须实现⽗类的抽象⽅法。
1)使⽤abstract修饰的类是抽象类
2)抽象类有构造,但是不能new
3)使⽤abstract修饰⽅法是抽象⽅法,抽象⽅法没有⽅法体(即没有{})
4)抽象类可以没有抽象⽅法
5)有抽象⽅法的类必须是抽象类
6)抽象类归根结底还是⼀个类,只不过作为⽗类为⼦类服务。所以可以有普通的属性和普通⽅法。
7)抽象类的⼦类:如果抽象类的子类不想实现父类的抽象方法,就需要把这个子类也变成抽象的
接口:公共的规范,大家都要遵从这个规范使用。定制规则,展现多态。
接口其实就是一个特殊的抽象类;
Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。
两种含义:
一,Java接口,Java语言中存在的结构,有特定的语法和结构;
二,一个类所具有的方法的特征集合,是一种逻辑上的抽象。前者叫做“Java接口”,后者叫做“接口”。
我们入门级别的认知可以这样理解:
接口就是一个特殊的抽象类。 从功能方面考虑
也就是说接口和抽象类相比 又有一些特殊的地方。
2.java中的接口
- 接口定义的格式
Java
[权限修饰符] interface 接口名{}
接口的使用步骤
1.接口中的方法不能直接使用,必须有一个实现类来实现接口
Plain Text
[权限修饰符] class 类名 implements 接口1,接口2,接口3。。。{}public class Mouse implements USB{}
2.接口的实现类必须(覆盖重写)实现 接口中所有的抽象方法
3.创建实现类的对象,进行方法的调用。
- 注意:如果实现类没有覆盖重写接口中的方法,那么这个实现类自己就必须是抽象类。
接口中可以包含的内容
常量 (不可变的)
接口中的常量使用public static final 三个关键字修饰。
Plain Text
//定义常量的格式 public static final int AGE = 10;
直接使用 接口名.常量名
- 接口可以多实现。一个类可以实现多个接口。
- 抽象方法
注意事项:
接口中的抽象方法必须是两个固定的关键字修饰 public abstract
这两个关键字可以省略不写。
- 默认方法(jdk1.8以后的新增内容)
为什么要有默认方法? default 增强接口的通用能力。
Plain Text
default 返回值 方法名(){} //默认方法有方法体
注意事项:
类与类之间是单继承的
类与接口是多实现的:一个类可以实现多个接口(这个要将所有实现的接口中的抽象方法都实现),方便后期维护(修改,扩展)
接口与接口之间是多继承的:一个接口A如果继承了接口B和接口C,那么A接口可以同时拥有B和C接口的所有功能,并且还可以拥有属于自己的方法。
接口没有构造方法。
接口多态:一个USB接口可以表现出鼠标形态,键盘的形态,U盘的形态。。。。。。
面试题:接口和抽象类的区别? (提问)
1.构造方法
抽象类里面有构造方法 但是不能被new出来
接口里面没有构造方法
2.继承
抽象里面 java单继承 一个类只能继承一个抽象父类
接口可以继承多个接口,一个类可以实现多个接口
3.抽象方法
抽象类里面可以没有抽象方法,有抽象方法的类必须是抽象类
接口里面的方法是必须是抽象方法,只有方法名没有方法体,如果不是抽象方法就必须是default修饰的方法
抽象类里面的抽象方法是用public abstarct来修饰的 接口中的方法public abstract可以省略
- 变量
接口中的变量是用public static final修饰的
3. 面向接口编程
面向过程----》面向对象----》面向接口编程。95%
数据模型类:定义成员(私有的)变量/成员方法 ,添加get/set方法,添加构造方法,添加toString()方法
public interface IJump {
public abstract void jump();
}
package Work;
public abstract class Animal implements IJump {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public abstract void eat();
public abstract void jump();
}
package Work;
public class Dog extends Animal implements IJump {
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println();
}
@Override
public void jump() {
}
}
package Work;
public class Demo {
public static void main(String[] args) {
// IJump p = new Cat();
// p.jump();
Animal p1 = new Cat();
p1.eat();
p1.jump();
Animal p2 = new Dog();
p2.eat();
p2.jump();
}
}