Java 面向对象编程特性:封装 继承 多态

谈到java的特性,很多程序员会在第一时间说出,“Java是面向对象编程的语言”。这句话本身是没有错的,但是,为了完全理解 Java和面向对象之间的关系(即完全理解什么是面向对象编程,与之不同的还有什么?java作为面向对象编程的一类语言,如何实现了面向对象编程思想),我们还需要简单了解一下具有其他编程思维的一些语言,例如机器语言,汇编语言,面向过程编程语言,了解这些语言的过程实际上也揭示了计算机语言从底层语言到高级语言的变化,从简陋到复杂,从晦涩到易懂的一个过程是如何演变的。

1 机器语言

10010100110110

机器语言也就是CPU能够识别的语言。我们都知道所有的计算机程序最终都将交由CPU运行,而CPU的运行机制又由硬件所决定,电气二极管只能有两种状态,通电和不通电,因而最底层的机器语言就只是只由 0 和1 两个数字组成的一串字符,0 表示不通电, 1 表示通电。
机器语言最大的问题在于其可读性简直是非人类的,并且不同类型的CPU识别机器语言的方式也不同,相同一串机器语言在不同的CPU中可能得出不同的结果。对于程序员而言,不仅需要使用非人类的0和1编写程序,还要准确判断这串字符能否被当前使用的CPU所正确执行,可以想见编程工作的困难程度。

为了避免直接编写一串0和1的机器语言,进而发明出了汇编语言和汇编编译器。

2 语言

MOV AX,C_S
MOV DS,AX
LEA DX,P_S

汇编语言在定义上仍然被认为是一种低级语言,这里描述的低级与高级更多的是描述其与人类语言的相似程度。汇编语言由英语单词缩写描述指令动作,由单词字符和 数字描述数据存储地址,一行指令表示一个程序动作,下面提供几个常见的汇编语言指令。

指令释义
MOVmove的缩写,传送字或字节
INinput的缩写,I/O段都输入
PUSH把字压入堆栈

可以看到,相较于机器语言,汇编语言至少是人类可读的,这使得编程有了巨大的效率提升。但是我们的CPU只能识别由0和1组成的机器语言,还需要经由汇编编译器编译成机器码后才能执行。

但是汇编语言仍然是有缺陷的,由于CPU指令集的指令是有限个的。程序员必须在CPU支持的指令格式下书写汇编语言,因而一行汇编代码能执行的动作是有限的,如果使用汇编语言书写一个复杂程序,需要巨大的时间成本。此外,汇编语言在错误预警和处理等方面也较为有限。

随着社会发展的需要,计算机程序的复杂程度日益攀升,一类相较于汇编语言更具可读性的计算机编程语言应运而生,也就是我们的高级语言,高级语言在编程语法上更加接近人类语言,同时同汇编语言和机器语言之间借由编译器进行翻译一样,高级语言也借由其编译器或解释器最终将代码翻译成CPU可以识别的语言。

3 面向过程编程

定义:
“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。主要要采取过程调用或函数调用的方式来进行流程控制。流程则由包涵一系列运算步骤的过程(Procedures),例程(routines),子程序(subroutines), 方法(methods),或函数(functions)来控制。在程序运行的任何一个时间点,都可以调用某个特定的程序。任何一个特定的程序,也能被任意一个程序或是它自己本身调用。

面向过程语言的概念由荷兰科学家,图灵奖获得者 Edsger Dijkstra 在1968年提出。大名鼎鼎的C语言既是一门面向过程语言。面向过程编程语言在编程时,首先需要分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用。其专注于过程中的每个步骤的实现。此外,Edsger Dijkstra 还提出了面向过程语言的三大要素:

  1. 模块化:将一个大程序划分成一个个小的部分,这样易于管理
  2. 隐藏细节:将大程序拆分成小模块后,对于使用的人来说,只要拿来现成的模块使用就好了,不需要知道模块内部的细节。就像开车的司机,只要会操作方向盘就好,不需要明白汽车内部发动机的具体结构。
  3. 抽象:模块隐藏细节之后,人们对于一个复杂程序系统就可以提取出抽象宏观的理解。就像语文课上的提炼中心思想一样。除去了繁复的细节,对于整体理解一个庞大系统是很有帮助的。

面向过程语言也同样具有抽象概念,即对过程中步骤的抽象,在C语言中,过程的抽象实际上由函数方法来实现,对外仅提供一个函数名称,内部实现的细节相对于调用是隐藏的。

#include <stdio.h>
//C语言的函数
int sum(){
    int i, sum=0;
    for(i=1; i<=100; i++){
        sum+=i;
    }
    return sum;
}

int main(){
    //调用函数时,函数实现细节相较于调用是隐藏的
    int a = sum();
    printf("The sum is %d\n", a);
    return 0;
}

4 面向对象编程

定义:
面向对象程序设计是种具有对象概念的编程典范,同时也是一种程序开发的抽象方针。它可能包含数据属性代码方法。对象则指的是(class)的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关连的数据。

4.1 面向对象编程的起源和由来

引用自:https://www.cnblogs.com/GGj147258/p/5617444.html
OO方法起源于面向对象的编程语言(简称为OOPL)。50年代后期,在用FORTRAN语言编写大型程序时,常出现变量名在程序不同部分发生冲突的问题。鉴于此,ALGOL语言的设计者在ALGOL60中采用了以"Begin……End"为标识的程序块,使块内变量名是局部的,以避免它们与程序中块外的同名变量相冲突。这是编程语言中首次提供封装(保护)的尝试。此后程序块结构广泛用于高级语言如Pascal 、Ada、C之中。
60年代中后期,Simula语言在ALGOL基础上研制开发,它将ALGOL的块结构概念向前发展一步,提出了对象的概念,并使用了类,也支持类继承。70年代,Smalltalk语言诞生,它取Simula的类为核心概念,它的很多内容借鉴于Lisp语言。由Xerox公司经过对Smautalk72、76持续不断的研究和改进之后,于1980年推出商品化的,它在系统设计中强调对象概念的统一,引入对象、对象类、方法、实例等概念和术语,采用动态联编和单继承机制。
从80年代起,人们基于以往巳提出的有关信息隐蔽和抽象数据类型等概念,以及由Modula2、Ada和Smalltalk和等语言所奠定的基础,再加上客观需求的推动,进行了大量的理论研究和实践探索,不同类型的面向对象语言(如:Object-c、Eiffel、c++、Java、Object-Pascal等)逐步地发展和建立起较完整的和雨后春笋般研制开发出来,OO方法的概念理论体系和实用的软件系统。
面向对象源出于Simula,真正的OOP由Smalltalk奠基。Smalltalk现在被认为是最纯的OOPL。
正是通过Smalltalk80的研制与推广应用,使人们注意到OO方法所具有的模块化、信息封装与隐蔽、抽象性、继承性、多样性等独特之处,这些优异特性为研制大型软件、提高软件可靠性、可重用性、可扩充性和可维护性提供了有效的手段和途径。
80年代以来,人们将面向对象的基本概念和运行机制运用到其它领域,获得了一系列相应领域的面向对象的技术。面向对象方法已被广泛应用于程序设计语言、形式定义、设计方法学、操作系统、分布式系统、人工智能、实时系统数据库、人机接口、计算机体系结构以及并发工程、综合集成工程等,在许多领域的应用都得到了很大的发展。1986年在美国举行了首届"面向对象编程、系统、语言和应用(OOPSLA’86)"国际会议,使面向对象受到世人瞩目,其后每年都举行一次,这进一步标志OO方法的研究已普及到全世界。

4.2 面向对象三大特性:封装,继承,多态。

特性释义
封装封装是指将一个计算机系统中的数据以及与这个数据相关的一切操作语言(即描述每一个对象的属性以及其行为的程序代码)组装到一起,一并封装在一个有机的实体中,把它们封装在一个“模块”中,也就是一个类中。
继承继承是指一个对象针对于另一个对象的某些独有的特点、能力进行复制或者延续。
多态从宏观的角度来讲,多态性是指在面向对象技术中,当不同的多个对象同时接收到同一个完全相同的消息之后,所表现出来的动作是各不相同的,具有多种形态;从微观的角度来讲,多态性是指在一组对象的一个类中,面向对象技术可以使用相同的调用方式来对相同的函数名进行调用,即便这若干个具有相同函数名的函数所表示的函数是不同的。

4.3 面向对象编程和面向过程编程的区别

先给结论

编程思想优势劣势
面向过程编程性能高。高耦合,编程量较多,维护困难,复杂业务的实现教困难。
面向对象编程易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护性能较低

所谓尺有所短,寸有所长,长短之间总是相较而言的。因而如果要更透彻、全面地认识面向过程编程和面向对象编程,我们不妨进行比较。
这里我试图通过两种编程思想,使用C和JAVA分别来模拟解决一个生活中的案例:烧开水。

我们知道,如果要喝开水,按照我们日常的做法,就是拿个热水壶,然后装入水,接上电源加热直到水沸腾。实际上这种流程化的思维方式就是面向过程的,专注于所需完成工作本身,一步步执行。

这里我用C语言来表示这个过程,更简化了其过程,

  1. 获得水的温度
  2. 加热水
  3. 判断水是否沸腾(达到100℃)
  4. 直到满足温度 不小于 100,结束程序。

示例代码:

#include <stdio.h>
#include <stdlib.h>

int get_water_temperature() {
	int water_temperature = rand() % 100;
    return water_temperature;
}

int heat_up(int water_temperature) {
	if (water_temperature < 100) {
        if(water_temperature >= 90) {
        	water_temperature = 100;
        } else {
        	water_temperature = water_temperature + 10;
        }
    }
    printf("Heat up to:%d\r\n", water_temperature);
    return water_temperature;
}


int main() {
	int water_temperature = get_water_temperature();
    printf("Current Temperature:%d\r\n", water_temperature);
    while(water_temperature < 100) {
    	water_temperature = heat_up(water_temperature);
    }
    printf("The water boil");
    return 0;
}

但如果使用面向对象编程,我需要首先做一些长远的思考。先设想有如下几个对象

  • 液体
  • 水,水属于液体的一种
  • 加热器,可以用来加热液体的

可以直观的感受到编程思维的不同,运用面向过程的编程思想,我们专注于解决问题的步骤, 把每个步骤以函数实现,依此调用。但是运用面向对象的编程思想,当问题摆在眼前,我们首先要去思考这个问题涉及几个相关的对象模型,也就是解决这个问题我面对的虚拟主体是什么。

这里我使用Java编程
构建了如下类

  • 抽象类 Liquid.class ,表示液体,液体类封装了两个成员变量,name 和 temperature
  • 继承于Liquid.class的类 Water.class,表示水
  • Boiler.class,表示加热器

然后main函数中实例化相关的对象,并进行函数调用。为了方便阅读,这里做了很多简写,Java新手会发现代码并不能正常运行

/**
* 液体类
*/
public abstract class Liquid {
    
    protected String name;
    //温度
	protected int temperature;
    
    public Liquid(String name, int temperature) {
        this.name = name;
    	this.temperature = temperature;
    }
    
    public int getName() {
    	return this.name;
    }
    
    public int getTemperature() {
    	return this.temperature;
    }
    
    public void setTemperature(int temperature) {
        this.temperature = temperature;
    }
}

/**
* 水类 - 液体类的子类
*/
public class Water extends Liquid {
	public Water(String name, int temperature) {
        this.name = name;
    	this.temperature = temperature;
    }
}

/**
* 加热器类
*/
public class Boiler {

	public void heatUp(Liquid liquid, int targetTemperature) {
    	while(liquid.getTemperature() < targetTemperature) {
        	liquid.setTemperature(targetTemperature);
        }
        System.out.printf("%s加热到%d度了", liquid.getName(), targetTemperature);
    }
}


public static void main(String[] args) {
    //获取水
    Water water = new Water("水", (int) (Math.random() * 100));
    //获取热水器
    Boiler boiler = new Boiler();
    //加热
    boiler.heatUp(water, 100);
    
}

在上述示例中看来,似乎Java在编程实现烧水这项工作时,无论是编程量还是复杂程度都比C要多得多。
但如果此时,情况发生变化,例如说我不仅要烧开水,我还想喝热果汁。面向对象的优势就来了。
我可以使用Java语言马上构建一个 Juice.class 继承于 Liquid.class 我们的 Boiler.class 的 heatUp 函数是针对于 Liquid 的,因此与水同为液体的果汁也能够调用加热方法。

public class Juice extends Liquid {
	public Juice(String name, int temperature) {
        this.name = name;
    	this.temperature = temperature;
    }
}

public static void main(String[] args) {
    //获取水
    Liquid water = new Water("水", (int) (Math.random() * 100));
    //获取热水器
    Boiler boiler = new Boiler();
    //加热
    boiler.heatUp(water, 100);
    
    //获取果汁
    Liquid juice = new Juice("果汁", (int) (Math.random() * 100));
    //加热
    boiler.heatUp(juice, 100);
}

面向对象编程聚焦于 某类实体的 共同特征 进行封装,声明这类实体所拥有的属性和能够提供的服务,因而能够针对一类实体进行编程,这便是其可重用性。
在这里,实体可以是某类服务,也可以指代业务问题中的某个实际物理对象。例如我们需要管理公司员工的信息,那么就可以针对于员工这个群体进行抽象,员工作为人具有姓名,身高,年龄,电话号码等信息,员工作为公司的一员有工号,薪资,任职年限等信息。对实体的抽象是面向对象编程的基本思维方式所在。

我们理解面向过程与面向对象的区别时,需要发散思维来看,特别是已经接触过Java的程序员,不妨设想一下没有“对象”的编程语言如何解决一些问题。软件编程的一大难题是适应变化,世界无时不刻发生变化。当面对变化时,当面对较复杂的情况时,面向对象编程较面向过程编程自有其优势所在。

5 Java的面向对象编程

Java作为一门面向对象编程的高级语言,是如何实现面向对象的?我们可以从面向对象的三大特性来解释Java的面向对象机制。

5.1 Java的封装

Java的封装性体现在 class类 和 访问修饰符中。Java通过类文件将一个个对象分隔开来。并通过访问修饰符来控制其他对象的访问权限

Java修饰符
修饰符释义
当前类及其子类可以访问,同包的类可以访问
public所有类可以访问
protected当前类及其子类可以访问
private当前类可以访问

程序员可以把属性和方法在类中声明,并通过访问修饰符机制控制外界的访问和函数调用,以此起到隔离封装的作用。

5.2 Java的继承

Java通过在类名后追加 extends 并指定父类类名来实现继承

public class Dog extends Animal {
    //该示例表示 Dog 类 继承于 Animal 类
}

由于父类中已经进行了一次抽象并声明了其属性和提供的函数,并且可以将这部分属性和函数继承给子类,因此通过底层建筑向上的层层封装,可以将一类实体的特征按照父子类的关系进行非常良好的聚合。这在代码重用性和复杂关系的梳理上是非常有益处的。多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。初始化子类时先初始化父类,即调用构造函数时隐式执行父类构造函数。下图展示了其包含关系。
在这里插入图片描述

5.3 Java的多态

多态可以理解为多形态,即一个对象的实例化可以有多种形态,java的多态是基于实现接口和继承的。我们在回顾一下关于面向对象多态的定义

从宏观的角度来讲,多态性是指在面向对象技术中,当不同的多个对象同时接收到同一个完全相同的消息之后,所表现出来的动作是各不相同的,具有多种形态;
从微观的角度来讲,多态性是指在一组对象的一个类中,面向对象技术可以使用相同的调用方式来对相同的函数名进行调用,即便这若干个具有相同函数名的函数所表示的函数是不同的。

这里将多态视为宏观和微观两种角度。首先从宏观角度讲,即 接受 相同的消息 表示出不同的动作。
如下代码

//定义整数计算器接口
public interface IntCalculator {
	
	public int calculate(int i);
}

public class Totalizer implements IntCalculator {
	@Override
    public int calculate(int i) {
        //累加操作
    	return ++i;
    }
}

public class Reducer implements IntCalculator {
    @Override
    public int calculate(int i) {
        //累减操作
    	return --i;
    }
}

public class Test {
    public static void main(String[] args) {
		int i = 0;
        IntCalculator totalizer = new Totalizer();
		IntCalculator reducer = new Reducer();
		System.out.printf("操作结果%d", totalizer.calculate(i));
        System.out.printf("操作结果%d", reducer.calculate(i));
    }
}

如上述代码,最终执行结果
操作结果1
操作结果-1
进程已结束,退出代码为 0
可见,通过实现接口,实例化两个不同的对象接收相同的消息,其执行动作不同。当然,通过继承也能完成。

其次是微观角度的,即一个对象中的相同函数名的不同函数,可以用相同的调用方式进行调用。
java类中的函数名是可以相同的,但是其参数必须不同,保证函数的唯一性。当然调用方式是可以相同的,即便在同一个函数中,借由用于判断的类型参数等也可以在函数体内通过条件判断语句进而执行不同的动作。

如下代码示例(仅作案例讲解,请勿考虑其实际意义)

public class ElementExcel {

	public static ElementExcel of(File file, String suffix) {
    	if(suffix == null) {
            return new ElementExcel();
        }
        
        if(".xls".equals(suffix.trim())) {
        	//做相应处理
        } else {
        	//做相应处理
        }
        return new ElementExcel();
    }
	
    public static ElementExcel of(InputStream inputStream) {
    	//做相应处理
        return new ElementExcel();
    }
    
    public static ElementExcel of(MuiltpartFile multpartFile) {
    	//做相应处理
        return new ElementExcel();
    }
}

借由java接口实现和继承以及java函数定义规则和条件判断语法支持,java很好的体现了面向对象多态特性。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值