2. 面向对象三大特征
2.1 封装
封装的概念
封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式
- 简单的来说就是我将不想给别人看的数据,以及别人无需知道的内部细节, “锁起来” ,我们只留下一些入口,使其与外部发生联系。
我们如何给我们的数据 “上锁” 呢?
- 我们使用,public、private、protected 等权限修饰符 在类的内部设定了边界,这些不同程度的 ”锁“ 决定了紧跟其后被定义的东西能够被谁使用。
封装的好处
隐藏实现细节,提供公共的访问方式,提高了代码的复用性,提高安全性
好处1:隐藏实现细节,提供公共的访问方式
隐藏实现细节怎么理解呢?
-
我们将一些功能封装到类中,而客户端的程序员,不需要知道类中的这个方法的逻辑原理,类程序员只需要给他一个对外的接口,客户端程序员只需要能够调用这个方法即可,
-
例如:夏天宿舍很热,我们(用户)只需要操作遥控器即可使用空调,并不需要了解空调内部是如何运行的
提供公共的访问方式又怎么理解呢?
我们先来看一段标准案例
public class Student {
//定义成私有成员变量(private)
private String name;
private int age;
//无参构造
public Student() {
super();
}
//带参构造
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
//成员变量的set和get方法(与外界联系的桥梁)
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
public class StudentTest {
public static void main(String[] args) {
//创建学生类对象 s
Student s = new Student();
//对象s调用类中的公共方法setName()和setAge()
//set方法给成员变量赋值
s.setName("BWH_Steven");
s.setAge(20);
//get方法获取成员变量
System.out.println(s.getName() + s.getAge());
}
}
我们可以看到在上面的案例中,成员变量都使用 private 修饰,而下面的 get 和 set 方法均使用了public修饰,其实被private修饰的属性就是我们想要锁起来的数据,而 set、get 方法就是我们打开这把锁的钥匙
被private所修饰的内容是,除类型创建者和类型的内部方法之外的任何人都不能访问的元素,所以我们这些数据就被我们通过private “锁” 了起来,而我们外界是可以通过创建对象来调用一个类中的公共方法的,所以被 public修饰的 set 和 get 方法外界所能访问的,而这两个方法又可以直接访问我们的私有成员变量,所以 set 和 get 方法就成为了私有成员与外界沟通的钥匙。
好处2:提高了代码的复用性
功能被封装成了类,通过基类与派生类之间的一些机制(组合和继承),来提高代码的复用性
好处3:提高安全性(此处待修改)
关于安全性的问题,实际上还是存在争议的,我们先看一种说法:
public class Student {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
//在setAge()方法中加入了校验的内容
//不合法数据是不允许传递给成员变量的
public void setAge(int age) {
if (age < 0 || age > 120) {
System.out.println("Error");
}else {
this.age = age;
}
}
public int getAge() {
return age;
}
}
public class StudentTest {
public static void main(String[] args) {
Student s = new Student();
System.out.println(s.getName() + s.getAge());
//错误的方式!!!
s.name = "BWH_Steven";
s.age = 20;
System.out.println(s.getName() + s.getAge());
//正确的方式!!!
s.setName("BWH_Steven");
s.setAge(20);
}
}
我们用private来修饰我们的成员变量不是没有任何依据的,如果我们的成员变量修饰符改为public,这句意味着外界可以使用对象直接访问,修改这个成员变量,这可能会造成一些重大的问题
例如:外界通过对象去给成员变量赋值,可以赋值一些非法的数据,这明显是不合理的。所以在赋值之前应该先对数据进行判断。StudenTest 是一个测试类,测试类一般只创建对象,调用方法,所以这个判断应该定义在Student类中。需要使用逻辑语句,而逻辑语句应该定义在方法中。所以在Student类中提供一个方法来对数据进行校验但是如果偏偏不调用方法来赋值,还是通过 对象名.变量
直接赋值,这样我们的方法内的逻辑就没有起作用所以我们必须强制要求使用我的方法,而不能直接调用成员变量这也正是我们使用 private 修饰成员变量的原因!
注:此处举例为 JavaBean 类,一般很少在 set get 中去添加一些逻辑,一般都是一种简单的赋值,而且诸多框架和不错的项目均使用了这种规范方法。
2.2 继承
继承就是在一个已有类的基础上派生出新类(例如动物类可以派生出狗类和猫类),子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为
提高了代码的复用性,提高了代码的维护性(通过少量的修改,满足不断变化的具体要求),让类与类产生了一个关系,是多态的前提。但是缺点也很显著:让类的耦合性增强,这样某个类的改变就会影响其他和该类相关的类。
特点:Java只支持单继承,不支持多继承(C++支持),但是Java支持多层继承(继承体系)形象的说就是:儿子继承爸爸,爸爸继承爷爷,儿子可以通过爸爸继承爷爷。
注意:
A: 子类只能继承父类所有非私有成员(成员方法和成员变量)
B:子类不能继承父类的构造方法,但是可以通过super关键字去访问方法
C: 不要为了部分功能而继承(多层继承会使得子类继承多余的方法)
2.3 多态
多态是同一个行为具有多个不同表现形式或形态的能力,例如:黑白打印机和彩色打印机相同的打印行为却有着不同的打印效果,
-
对象类型和引用类型之间存在着继承(类)/ 实现(接口)的关系;
-
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
-
如果子类重写了父类的方法,最终执行的是子类覆盖的方法,如果没有则执行的是父类的方法。