之因此写下这篇文章,是由于女友这学期要修Java,但在这以前只接触过C语言,对于面向对象的概念一时难以理解,因而这里写一篇文章来说一讲。我以前并无接触过Java,本来只是打算讲讲OOP
的一些概念的,不事后来仍是打算开始学习一下Java,而且整理一个笔记系列,这篇文章就作个开头吧。有关Java的内容基本上是基于对《On Java 8》和《Java核心技术 卷一》这两本书。
把这些内容发布在公众号上,但愿也能对有相同需求的人提供帮助,可是须要注意,在我后续的文章里,都假定读者有必定C语言基础。java
抽象是计算机科学中一个很是重要的概念,它和具体正好相反。抽象是为了下降复杂度。在文学做品中经常以具体事物来比喻抽象的东西:程序员
一往情深深几许?深山夕照深秋雨。
可是具体的事物每每是繁琐的复杂的,在计算机科学中,经过抽象,可以更好的解决问题。
首先咱们在课堂上应该都听过老师讲解二进制时讲过二进制的1
和0
与计算机内部的电路开关状态对应,CPU中有很是很是多的电路。让咱们来看一下咱们的计算机程序,无论是一个简单的计算1+1
仍是一个相似Windows这样的操做系统,它们在运行的时候,其实都是这些电路中电子在跑来跑去。CPU内部有数以亿计的晶体管。
在一堆晶体管的基础上,咱们抽象出门电路,与门、或门、非门等等,不用知道在电路中电子怎么运动的,也不须要知道输入多少电压对应二进制的哪一位,只要知道有什么样的输入能获得什么样的输出就好了。
在这之上,又能够抽象出更复杂的电路,触发器、寄存器,咱们只要知道怎么操做会获得什么结果,而没必要知道怎么获得的结果。
最初的程序,咱们使用1和0
组成的机器语言编写,它能直接被计算机CPU识别运行。可是对于人类来讲仍是难以理解。
在机器语言的基础上,产生了汇编语言。汇编语言是对机器语言的一种抽象,以下是一个实现两数相加的汇编程序:编程
datas segment x dw 1234h y dw 5678h z dw ? datas ends codes segment assume cs:codes,ds:datas start: mov ax,datas mov ds,ax mov ax,x add ax,y mov z,ax mov ah,4ch int 21h codes ends end start
在汇编中,使用例如mov
、add
这样的指令,咱们不用操心具体写什么样的机器码,汇编器会最终帮咱们将代码翻译成机器语言。但在汇编中,咱们还要操心例如将数据移动到某个CPU的寄存器中这样的问题。
再对汇编进行抽象,咱们发展出了高级语言,例如在Python中:架构
print(2+3)
这样不只能计算加法的结果还能显示在屏幕上,咱们编写的代码更解决人类的天然语言,不用去关心数据是否是要从内存放进CPU,怎么实现了数据的相加,怎么将数据显示在屏幕中。
好了,如今咱们有了一个高级语言,如今咱们要写一些程序大体是这样:函数
函数 函数1 函数2 函数3 函数4 ... 数据 数据1 数据2 数据3 数据4 ...
这时候是一种面向过程的编程模式,随着时代的发展,当咱们的需求愈来愈多,一个程序可能会写出很是很是多的函数,有一些函数要实现的功能相似,但又不得很少写不少行代码。
以一个工厂举例,一家工厂,须要工人,生产线,原材料采购,市场销售,技术研发,若是用面向过程的思想去解决,那么这个程序员要考虑一家工厂从设计产品到购买材料到投入生产到销售这一系列环节中全部的功能,全部的数据。
这个时候就须要面向对象的思想了。工具
面向对象编程(Object-Oriented Programming OOP)是一种编程思惟方式和编码架构,面向对象是一种对现实世界理解和抽象的方法。学习
在工厂的例子中,使用面向对象的思路来解决,那么咱们会将问题分而治之,让工人来负责生产,技术员来负责研发,销售负责贩卖产品,采购负责买材料。优化
如下摘录自《On Java 8》:编码
- 万物皆对象。你能够将对象想象成一种特殊的变量。它存储数据,但能够在你对其“发出请求”时执行自己的操做。理论上讲,你老是能够从要解决的问题身上抽象出概念性的组件,而后在程序中将其表示为一个对象。
- 程序是一组对象,经过消息传递来告知彼此该作什么。要请求调用一个对象的方法,你须要向该对象发送消息。
- 每一个对象都有本身的存储空间,可容纳其余对象。或者说,经过封装现有对象,可制做出新型对象。因此,尽管对象的概念很是简单,但在程序中却可达到任意高的复杂程度。
- 每一个对象都有一种类型。根据语法,每一个对象都是某个“类”的一个“实例”。其中,“类”(Class)是“类型”(Type)的同义词。一个类最重要的特征就是“能将什么消息发给它?”。
- 同一类全部对象都能接收相同的消息。这实际是别有含义的一种说法,你们不久便能理解。因为类型为“圆”(Circle)的一个对象也属于类型为“形状”(Shape)的一个对象,因此一个圆彻底能接收发送给"形状”的消息。这意味着可以让程序代码统一指挥“形状”,令其自动控制全部符合“形状”描述的对象,其中天然包括“圆”。这一特性称为对象的“可替换性”,是OOP最重要的概念之一。
Grady Booch 提供了对对象更简洁的描述:一个对象具备本身的状态,行为和标识。这意味着对象有本身的内部数据(提供状态)、方法 (产生行为),并彼此区分(每一个对象在内存中都有惟一的地址)。spa
在Java中使用class
关键字定义类,使用例如Worker w1 = new Worker()
来实例化类为一个对象。
/* 这是一个类,它表示一种类型,例如工人,就是一类人, 它有name这个属性(field),work这个方法(method) */ public class Worker { String name; public void word() { ... } } /* w1是一个对象,对象是类的实例,好比工厂里有100个工人,w1就是工人中的一个实例 w1这个对象的name属性是张三 w1能够调用work方法 定义了类以后,每个这个类的实例对象,都会有类定义的属性与方法 */ Worker w1 = new Worker(); w1.name = "张三"; w1.work();
面向对象编程将数据以及对数据的操做打包起来放到对象里,外界无需知道程序内部实现的细节,只要经过相似xx.xx()
的形式去调用,封装能够隐藏起对象的属性和实现细节。
咱们能够把编程的侧重领域划分为研发和应用。应用程序员调用研发程序员构建的基础工具类来作快速开发。研发程序员开发一个工具类,该工具类仅向应用程序员公开必要的内容,并隐藏内部实现的细节。这样能够有效地避免该工具类被错误的使用和更改,从而减小程序出错的可能。彼此职责划分清晰,相互协做。当应用程序员调用研发程序员开发的工具类时,双方创建了关系。应用程序员经过使用现成的工具类组装应用程序或者构建更大的工具库。若是工具类的建立者将类的内部全部信息都公开给调用者,那么有些使用规则就不容易被遵照。由于前者没法保证后者是否会按照正确的规则来使用,甚至是改变该工具类。只有设定访问控制,才能从根本上阻止这种状况的发生。
Java 有三个显式关键字来设置类中的访问权限:public(公开),private(私有)和protected(受保护)。这些访问修饰符决定了谁能使用它们修饰的方法、变量或类。
public
(公开)表示任何人均可以访问和使用该元素;private
(私有)除了类自己和类内部的方法,外界没法直接访问该元素。private 是类和调用者之间的屏障。任何试图访问私有成员的行为都会报编译时错误;protected
(受保护)相似于 private,区别是子类(下一节就会引入继承的概念)能够访问 protected 的成员,但不能访问 private 成员;default
(默认)若是你不使用前面的三者,默认就是 default 访问权限。default 被称为包访问,由于该权限下的资源能够被同一包(库组件)中其余类的成员访问。使用访问控制,咱们让使用咱们编写的类的程序员不要接触咱们不想让他们访问的部分,同时咱们能够修改程序,优化咱们的代码而不影响应用程序员的使用。
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World"); } }
在上面这个简单的helloworld程序中,咱们使用了System.out.println()
来打印文字到屏幕上,可是咱们并不知道这个方法的实现细节,哪怕在版本更新中重写了这个方法的实现,只要接口和功能没变,咱们的代码就没有问题。
随着工厂不断发展,业务越作越多,出现了各类不一样的职位分工,这些员工在不少方面有类似之处,但具体作的事情略有不一样,那咱们是否是要写不少个员工类呢?岂不是会有不少重复的代码吗?
咱们能够这样作:先定义一个员工类,它拥有名字、年龄、薪水、工做时间等等公有的属性与方法,而后有各类类型的员工继承这个工人类,员工类能够称为父类,细分的工种称子类。
子类会拥有父类全部的属性与方法。父类作出改变,也会反映在子类上。
子类也能够添加本身独有的属性与方法,例如工人可能会有领取防御用品的方法。
在咱们的例子中,咱们经过员工类派生出各类类型的子类,有工人、销售、研发等等,他们都继承了父类的work()
方法,但是,不一样的职位作的工做会相同吗?
答案显然是否认的。
那么咱们工厂调用员工去工做,怎么实现不一样类型的员工作不一样的事情呢?要写上不少的类型判断吗?根据不一样类型完成不一样行为?
看下面一个例子:
void toWork(Employee employee) { employee.work(); // ... }
使用toWork()
方法,表面看上去只能使用Employee
类,让咱们接着往下看:
Work work = new Work(); Technician tech = new Technician(); Salesman sale = new Salesman(); toWork(work); toWork(tech); toWork(sale);
能够看到传入任何类型的员工都能获得执行。
能够看到咱们没有作任何的类型判断,因为工人、技术员、销售都是员工的子类,在toWork()
中它们都能被看成员工
类型,这种特性在Java中被称为向上转型(upcasting)
。
发送消息给对象时,若是程序不知道接收的具体类型是什么,但最终执行是正确的,这就是对象的“多态性”(Polymorphism)。面向对象的程序设计语言是经过“动态绑定”的方式来实现对象的多态性的。编译器和运行时系统会负责对全部细节的控制;咱们只需知道要作什么,以及如何利用多态性来更好地设计程序。
面向对象归根结底是一种程序设计的思想,并非有class
关键字就是面向对象。经过这种设计思想,咱们在应对复杂庞大的问题时,能写出可读性更高、复用性更强的程序。若是你去阅读Linux内核的源代码,会发现虽然其使用C语言
编写,但仍然有着面向对象的思想在其中。
扫码关注公众号: