面向对象的四大特性:抽象、封装、继承、多态。
抽象
- 抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。
- 抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
封装
封装性就是尽量隐藏对象内部的细节,对外界只暴露出有限的接口和方法与之进行交互。封装的原则是使对象以外的部分不能随意的访问和操作对象的内部属性,从而避免了外界对对象内部属性的破坏。可以通过对类的成员设置一定的访问权限,实现类中成员的信息隐藏
权限(隐私)等级从小到大:public,protected, 包访问权限(无关键词),private
包访问权限:默认
- 当前包的其他类都有访问权限,但是包以外的其他类都是private的。
- 包访问权限为把类群聚在一个包中的做法提供了意义和理由。
接口访问权限:public
- 对每个人都是可用的
继承访问权限:protected
- 子类可访问
- 同包下的其他类也可访问
private:
- 访问权限仅限于类的内部,是一种完全封装的体现
访问权限的控制通常被称为具体实现的隐藏。把数据和方法包装进类中,以及具体实现的隐藏,都叫封装。封装的结果就是一个同时带特性和行为的数据类型。
- 问:为什么访问权限将权限的边界划在了数据类型的内部?
- 答:两个原因:
- 要设立客户端程序员可以使用和不可以使用的界限。可以在结构中建立自己的内部机制,而不用担心客户端程序员偶尔会将内部机制当作他们可以使用的接口的一部分。
- 要将接口和实现分离。如果客户端程序员除了调接口外什么也不可以做的话,服务端程序员就可以更改不是public的所有代码(例如protected,private等),而不会破坏客户端代码。
继承
复用代码有两种方式,一种是组合,一种是继承。
组合:(非常直观)
- 在新类中创建现有类的对象。
- 只是复用了现有程序的功能,而非他的形式
继承:(细致)
- 子类的对象拥有父类的全部属性与方法,称作子类对父类的继承。
- Java中父类可以拥有多个子类,但是子类只能继承一个父类,称为单继承。
- Java中所有的类都是通过直接或间接地继承java.lang.Object类得到的。
- 子类不能继承父类中访问权限为private的成员变量和方法。
- 子类可以重写父类的方法,即命名与父类同名的成员变量。
- Java中通过super来实现对父类成员的访问,super用来引用当前对象的父类。
- 组合和继承之间的选择:
- 组合技术通常用于想在新类中使用现有类的功能而非他的接口这种情形。
- 继承技术一般用于想要使用某现有类并开发他的特殊版本。通常,这意味着你在使用一个通用类,并为某种特殊需要而特殊化。
- 总结:
- “has-a” -> 组合,(车有门,轮子)
- ”is-a“ -> 继承,(车是一种交通工具)
- 向上转型:
- 子类引用可以(转化为父类引用)调用父类方法
- 到底是用组合还是继承,最清晰的方法其实就是判断是否需要子类向父类进行向上转型。
多态
“封装”通过合并特性和行为来创建新的数据类型,”实现隐藏“通过将细节私有化,把接口和实现分离开。而多态的作用是消除类型之间的耦合关系。
多态是指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用)。实现多态有两种方式:
方法重载(overload)实现的是编译时的多态性(也称为前期绑定)。
方法重写(override)实现的是运行时的多态性(也称为后期绑定)。运行时的多态是面向对象的精髓。
运行时多态的实现条件:
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
- 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
运行时多态是如何实现的?
- 后期绑定:
- 运行时根据对象的类型进行绑定,也称为动态绑定或者后期绑定
- 即:编译器一直不知道对象的类型,但是方法调用机制可以在运行时判断对象的类型,找到正确的方法体,并加以调用。
注:Java中除了static方法和final方法(private方法也属于final方法)外,其他所有的方法都是后期绑定。
关键字final和static
这里顺便提一下关键字final和static。
(1)final
修饰变量:
- 编译期常量:类加载的过程完成初始化,编译后带入到任何计算式中。只能是基本类型。
- 运行时常量:基本数据类型或引用数据类型。引用不可变,但引用的对象内容可变。
修饰方法:
- 不能被继承,不能被子类修改。
- 有效的关闭动态绑定
修饰类:不能被继承。
修饰形参:final形参不可变
(2)static
修饰变量:静态变量随着类加载时被完成初始化,内存中只有一个,且JVM也只会为它分配一次内存,所有类共享静态变量。
修饰方法:
- 在类加载的时候就存在,不依赖任何实例;
- static方法必须实现,不能用abstract修饰。
修饰代码块:在类加载完之后就会执行代码块中的内容。