封装、继承、多态
导航
封装
封装就是,需要让使用者知道的菜暴露出来,不需要使用者知道的都隐藏起来。封装就是把对象的属性和操作结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。
我们程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
封装的优点:
- 提高代码的安全性。
- 提高代码的可复用性。
- 高内聚:封装细节,便于修改内部代码,提高可维护性。
- 低耦合:简化外部调用,便于调用者使用,便于扩展和协作。
来一个实现封装的简单案例,感受一下:
class Person{
String name; //未封装
private int age; //封装
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 0 && age < 150) {
this.age = age;
}else {
System.out.println("输入年龄有误!");
}
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class Test{
public static void main(String[] args) {
Person pe = new Person();
pe.name = "小猪";
// pe.age = 18; 不能直接访问age属性
// pe.setAge(-1); -1岁,不符合内部实现逻辑,无法赋值
pe.setAge(18);
System.out.println(pe);
}
}
-----------------------------------------------------
输出结果:
Person [name=小猪, age=18]
封装的实现,我自己简单认为,就是使用private保护成员变量,然后提供get()和set()方法供外界访问修改。
private是访问修饰符的一个,关于访问修饰符,介绍如下~
访问修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
-
default (即默认,不使用任何关键字): 使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。使用对象:类、接口、变量、方法。
-
public : 被声明为 public 的变量、类、方法、构造方法和接口能够被任何其他类访问。使用对象:类、接口、变量、方法
-
protected : 能被同一包中的其他类及子类访问,也能被不同包的子孙类访问,但不能被不同包的其他类访问。使用对象:变量、方法。 注意:不能修饰类(外部类)
-
private : 私有访问修饰符是最严格的访问级别,所以被声明为 private 的方法、变量和构造方法只能被所属类访问。使用对象:变量、方法。 注意:不能修饰类(外部类)
我们可以通过以下表来说明访问权限:
修饰符 | 本类 | 同包子类 | 同包其他类 | 不同包子类 | 不同包其他类 |
---|---|---|---|---|---|
public | √ | √ | √ | √ | √ |
protected | √ | √ | √ | √ | × |
default | √ | √ | √ | × | × |
private | √ | × | × | × | × |
验证访问修饰符的访问规则,需要多个包多个文件,文档中不方便展示。建议动手写点demo试一下,加深理解和印象。
继承
在访问修饰符中,提到的“子类”是什么呢?这就是继承的相关知识点了。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。父类更通用,子类更具体。
简单打个比方,人类属于动物类,我们就可以说,人类继承于动物类。
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类名 {
}
class 子类名 extends 父类名 {
}
关键字对是否可以继承的影响:
修饰符 | 同包子类 | 不同包子类 |
---|---|---|
public | √ | √ |
protected | √ | √ |
default | √ | × |
private | × | × |
Java 中使用extends不支持对类的多继承,但支持多重继承:
extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。实例:
public class Perspn {
private String name;
private int age;
public Animal(String myName, String myid) {
//初始化属性值
}
public void eat() { //吃东西方法的具体实现 }
public void sleep() { //睡觉方法的具体实现 }
}
public class student extends Perspn {
}
implements关键字
使用 implements 关键字,进行接口的继承时,可以同时继承多个接口(多继承),实例:
(关于接口的具体细节,请看这篇文章:待更新)
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {
}
this 与 super 关键字
this关键字:指向自己的引用。
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
(关于this与super的具体细节,请看这篇文章:待更新)
final关键字
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写。
(关于final关键字的具体细节,请看这篇文章:待更新)
(关于重写的具体细节,请看这篇文章:待更新)
Object类
object类,是java语言的根类,所有类都继承于该类。
多态
多态是同一个行为具有多个不同表现形式或形态的能力。举一个例子:
比如我们按下 F1 键这个动作:
- 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
- 如果当前在 Word 下弹出的就是 Word 帮助;
- 在 Windows 下弹出的就是 Windows 帮助和支持。
类的多态
一个对象,有多种形态。子类对象,可以赋值给父类类型。然后再可以通过强制类型转换,转回为子类型。实例:
class Animal {
}
class Cat extends Animal {
}
class Dog extends Animal {
}
public class Test {
public static void main(String[] args){
Animal a = new Cat(); // 子类对象,赋值给父类类型
Cat b = (Cat)a; // 再强转回子类类型
Dog c = (Dog)a; // 编译不会报错,但运行会报错,因为a不是Dog类
}
}
方法的多态
重写,就可以看作是方法的多态。在运行时,如果有重写的方法,则会执行子类的方法。如果是子类新增的而父类没有的方法,如果此时形态为父类,则无法调用,需要强转回子类,再进行调用。(关于重写的具体细节,请看这篇文章:待更新)实例:
class Animal {
public void breathe() {
System.out.println("呼吸");
}
public void eat() {
System.out.println("吃吃吃");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("吃小鱼干");
}
public void climbTree() {
System.out.println("爬树");
}
}
class Dog extends Animal {
}
public class Test {
public static void main(String[] args){
Animal a = new Cat(); // 子类对象,赋值给父类类型
a.eat();
//a.climbTree(); 无法调用到,需要先强转回子类型
Cat b = (Cat)a;
b.climbTree();
a.breathe();
b.breathe(); // 没有重写的方法也可以调用,这是直接继承来的
}
}
--------------------------------------------
输出结果为:
吃小鱼干
爬树
呼吸
呼吸
变量的多态
变量不存在多态,变量前面的对象是什么类型,就会找谁的。实例:
class Animal {
String classname = "Animal";
}
class Cat extends Animal {
String classname = "Cat";
}
class Dog extends Animal {
}
public class Test {
public static void main(String[] args){
Animal a = new Cat(); // 子类对象,赋值给父类类型
Cat b = (Cat)a;
System.out.println(a.classname); // a为Animal 类
System.out.println(b.classname); // b为Cat 类
}
}
--------------------------------------------
输出结果为:
Animal
Cat
instanceof 运算符
instanceof可以用于判断判断操作对象是否是某一个特定的类型(类类型、接口类型、或是否继承于某类 ),该运算符我在《Java基础语法》一篇中已经介绍过,这里复制过来:
运算符 | 描述 |
---|---|
instanceof | 判断操作对象是否是某一个特定的类型 |
示例:
String name = "HHM";
boolean result = name instanceof String;
System.out.println("result:"+result );
----------------------------------
输出结果:
result:true // 由于 name 是 String 类型,所以返回真
class Animal {}
public class Cat extends Animal {
public static void main(String[] args){
Animal a = new Cat();
boolean result = a instanceof Car;
System.out.println("result:"+result );
}
}
输出结果:
result:true