类到底是啥玩意儿?
咱程序员天天写类(class),可类到底是啥玩意儿?
当年学Java的时候,老师说过一句话:“类是对代码的建模单位。”
这话听着挺高大上,但啥是“建模”?咱那会儿也是一脸懵。
多年后的今天,咱终于琢磨明白了:类是对现实世界的抽象映射,是一种建模方式。
类的构成:属性、方法、构造器
说到类,咱得先唠唠它的构成。
类一般由三部分组成:
1. 属性:描述对象的特征,比如椅子的颜色、腿的数量。
2. 方法:描述对象的行为,比如椅子的“坐”方法。
3. 构造器:用来创建对象的,比如 `new Chair()`。
咱刚开始写代码的时候,写的都是那种简单的 `Bean` 或者 `POJO`,里头一堆 `private` 属性,然后配上 `public` 的 `setter` 和 `getter` 方法。
后来咱就开始琢磨了:这三样东西,缺一样行不行?
Java Code |
// 一个简单的类 class Chair { // 属性 private String color; private int legs; // 构造器 public Chair(String color, int legs) { this.color = color; this.legs = legs; } // 方法 public void sit() { System.out.println("坐下了,舒服!"); } // getter 和 setter public String getColor() { return color; } public void setColor(String color) { this.color = color; } } |
你看,这 `Chair` 类里头,属性、方法、构造器都齐活了。
但咱得问一句:这些东西,缺一样行不行?
缺了属性、方法、构造器,会咋样?
咱先说说缺了属性。
如果类里头没有属性,那这对象就没特征了,光有个空壳子,啥也干不了。
再来说说缺了方法。
如果类里头没有方法,那这对象就没行为,光有个特征,啥也干不了。
最后说说缺了构造器。
如果类里头没有构造器,那咋实例化对象呢?
不过,咱得注意一点:接口(interface)里头就没有构造器,也不能被实例化。
接口里头只有方法的声明,没有方法的实现。
从JDK8开始,接口里头可以有 `default` 方法,但这方法不能被子类继承和修改。
Java Code |
// 一个简单的接口 interface PowerSocket { // 方法声明 void plugIn(); // default 方法 default void powerOn() { System.out.println("通电了!"); } } |
你看,这 `PowerSocket` 接口里头,只有方法的声明,没有构造器,也不能被实例化。
这里想到上一篇文章《程序员方法论系列:面向对象理论,咱得从根儿上唠明白!》中我写到过的一句话:
【即,我想去买一把椅子中的椅子,是一个有了椅子这个class类的代码,但是并没有new这个对象,即这个对象只有形参,没有实参,其内部的属性并没有赋值,其方法并没有实际实现(可能是一个接口),可能我的脑子里有想法,比如对这个椅子的颜色,腿的数量有想法,但是这个想法并未这个对象的完整实参,充其量是一个抽象类实例,也不是一个类的完整实例化对象。】
在这句话中,我用了一个抽象的类去思考,这个东西在我的脑子里,但是没有实例化对象,即可以认为它是一个抽象类,也可以认为它是一个接口,因为它有一部分实现,这一部分实现是固有印象,或者是偏见了,每个人脑子里应该都会多各种事物有各式各样的固有印象吧。
如果这个固有印象是default的,那么“人心中的成见,是一座大山……”
跑题了...
我就是想说,我们写软件的目的,是为了将现实世界抽象出来,在一个虚拟的场景中运行,
那么我们必须要能有一个具象化现实世界各种事物(Object)和运行中的行为(Method)和观察中的印象(Field)对应的建模方式了。
而我们为了对应世界的各种标准和规范,即有规范的类,出现了接口(进行一定程度约定的类)。
抽象类 vs 接口:到底有啥区别?
说到抽象类和接口,咱得唠唠它们的区别。
抽象类可以包含属性、方法、构造器,甚至可以包含方法的实现。
接口只能包含方法的声明和 `default` 方法,不能包含属性(除了常量)和构造器。
Java Code |
// 一个抽象类 abstract class Furniture { // 属性 protected String material; // 构造器 public Furniture(String material) { this.material = material; } // 抽象方法 public abstract void use(); // 普通方法 public void clean() { System.out.println("打扫干净了!"); } } // 一个接口 interface PowerSocket { void plugIn(); } |
你看,抽象类 `Furniture` 里头有属性、构造器、抽象方法和普通方法。
接口 `PowerSocket` 里头只有方法的声明。
接口的规范:墙壁插口的例子
说到接口,咱得举个现实世界的例子。
比如墙壁上的电源插口,国内有两种:两脚插口和三脚插口。
这两种插口都定义了火线(带电)和零线(不带电),还定义了电流的方向和频率(220V,50Hz)。
Java Code |
// 两脚插口接口 interface TwoPinSocket { void plugIn(); } // 三脚插口接口 interface ThreePinSocket { void plugIn(); void ground(); } |
你看,这 `TwoPinSocket` 和 `ThreePinSocket` 接口,定义了插口的基本规范。
用电器(实现类)得按照这个规范来设计,才能插上去用电。
所以,类因此而构成,然而将现实世界的抽象化为类,有更广阔的运用空间。
希望本篇短文,能促进你思考为什么有类?为什么又分化成抽象类?为什么有接口?为什么有实现类?以及,类的定义中,缺少结构以后会如何演变?接口中有什么必备要素?实现类为什么可以有多个?以及实现类使用的接口,为什么不能单独实例化?
关于接口和实现类的关系,今天就不深入讨论,就说这么多。
想一想,想一想,有些东西,想了就好。
在下一篇,将去思考类还有什么用途,抛开IT行业之外,它的出现,到底是如何反作用于现实世界的。