Java三大特性-封装、继承、多态
封装
- 在面向过程的语言中,封装指的是将一个需要重复执行的过程封装成一个函数,从而避免代码的冗余。 但是Java是面向对象的语言,在Java中,封装指的是将一个对象的属性和行为绑定在一起,使其形成一个不可分割的整体;隐藏自身的内部结构,并向外界提供访问的方法。
- 对于封装而言,一个对象它所封装的是自己的属性和方法,所以它是不需要依赖其他对象就可以完成自己的操作。
- 封装的好处:
- 通过方法来控制成员变量的操作,提高了代码的安全性。
- 把代码用方法进行封装,提高了代码的复用性。
- 降低了耦合性。可以灵活的修改本类内部的结构。
- 隐藏方法执行的细节。
public class Student {
/*
* 私有属性对外隐藏
*/
private String name;
private String id;
private int age;
public String getName() {
return name;
}
/*
* setter()、getter()是该对象对外开发的接口
*/
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAge() {
return age;
}
/*
* 控制成员变量, 提高了代码的安全性。
*/
public void setAge(int age) {
if(age>0 && age<150){
this.age = age;
}
}
/*
* 隐藏方法执行的细节。
*/
public void study(){
//学习的代码
}
}
复用类
复用代码是Java众多引人注目的功能之一。但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情。
组合
- 组合就是在新类中持有现有类的对象。
- 什么时候使用组合?
当你想要的对象中包含有别的对象的时候, 就要考虑使用组合;例如你想创建一个Car对象,它里面就应该包含有Engine等对象, 此时应该使用组合。
继承
- 继承是按照现有类型来创建新类。是对某一系列对象进行共性抽取的结果。
- 当你创建一个类的时候, 如果没有明确继承其它类, 那么会隐式的继承Object类;
- 什么时候使用继承?
- 当新类型与现有类型相似的时候就考虑使用继承;
- has-a关系使用组合来表达, is-a关系使用继承来表达;
- 继承的内存图解
- 继承的内存图分析:
- 继承中有关字段的分析
- 子类对象的字段可以分为继承自父类的字段区域和子类自有的字段区域; 子类字段区域通过关键字super指向了父类字段区域; 子类完全持有了父类的字段,只是有些字段由于有访问权限的限制, 导致子类对象不能直接访问;
- 由于在内存中分为了2个区域, 所以同名命名的方式是可以存在的, 这并不会导致寻址的时候出现异常;
- 在访问子类对象的字段时, 默认优先访问子类自有区域, 在自有区域没有查找到的情况下, 才访问父类字段区域;
- 当然, 可以通过super直接指定访问父类字段区域, 在子类和父类字段存在重名的情况下, 你只有通过super才能直接访问到父类区域的字段;
- 在多态的情况下, 由于类型提升为父类的类型, 因此只能访问到父类字段区域; 这种情况一定是在类的外部来访问对象的字段, private修饰的字段并不可见;
- 继承中有关方法的分析
- 子类方法也是完全持有了父类的方法, 但是访问权限依旧限制了有些方法并不能直接通过子类对象调用;
- 通过子类对象调用子类方法时, 优先调用的也是子类自有的方法, 然后才到子类的方法中查找;
- 通过final关键字修饰的方法, 编译器不允许子类有同名的方法; (即不可被重写)
- 被private修饰的方法, 只能在该区域使用, 这是访问权限所决定的; 因此,子类和父类中定义同名的私有方法, 是永远不会有冲突的, 因为它们永远只能在本区域中调用;
- 对于没有被private的同名方法, 由于默认总是以子类区域优先, 因此也总是优先调用子类区域中的方法, 如果试图调用父类中的方法, 你必须用super指定;
- 如果是在类的外部调用同名方法, 你只能调用到子类方法区域的方法, 因为super引用只是在子类内部才持有的; 这也是方法重写的根本原因;
- 如果是父类型的引用指向了子类对象, 那么通过该引用来调用方法时, 会不会只能调用父类区域的方法呢? 在前面的字段访问中, 如果类型提升, 就会只能访问父类区域中的字段; 但是在调用方法时, 并不是这样的; 因为java调用非静态方法(final和static是前期绑定的)是动态绑定的; 你可以理解为, 当使用父类引用调用方法时, java会通过某种机制获取该对象的类型, 然后再到指定类型的方法区去调用方法;所有,java调用一般方法总是优先调用子类自有的方法;这就解释了多态时调用的方法是子类重写后的方法的原因;
- 从前面的分析可以看出, 不管有没有进行向上转型, java调用方法总是会调用该对象类型的方法区中的方法, 并且也总是会优先调用子类自有区域的方法; 这样看来, 似乎向上转型变得没有任何意义了; 其实多态主要是针对编译时期设定的, 如果进行了向上转型, 编译器会强制你只能访问父类型中描述的字段和方法; 向上转型使得你无法访问子类特有的属性和方法;
- 继承中有关静态成员的分析
- 静态成员实际上就是类成员, 它们与对象无关;
- 调用静态成员有两种途径, 第一种是通过类名直接调用; 第二种是通过对象的引用调用; 其实第二种方式也是先拿到对象的类型,再通过类型来调用;
- 调用静态成员, 优先访问本类型自有区域, 然后再到父类型区域去查找;
- 继承中有关字段的分析
接口和多态
- 接口的定义
- 接口的定义:interface,一般命名形容词
- 接口中的方法都是抽象方法,默认用public abstract 修饰
- 接口中的属性:都是常量,一般大写,默认用public static final修饰
- 多态介绍
- 多态概念:同一个行为,对于传入不同的 对象 而言.具有完全不同的表现形式.
- 多态程序化含义:父类的引用指向子类的对象,该引用所调用的方法是子类重写的方法
- 多态三要素:继承、重写、向上转型