几种语言概念的联系与区分

一.编译型语言与解释型语言

为了更好的对编译型语言和解释型语言进行理解和区分,我们先来了解一下他们的基本概念

计算机是不能理解高级语言的,更不能直接执行高级语言,它只能直接理解机器语言,所以使用任何高级语言编写的程序若想被计算机运行,都必须将其转换成计算机语言,也就是机器码。而这种转换的方式有两种:
1.编译
2.解释
由此高级语言也分为编译型语言和解释型语言。

百度百科上对于二者的定义如下:

编译型语言:

运行编译型语言是相对于解释型语言存在的,编译型语言的首先将源代码编译生成机器语言,再由机器运行机器码(二进制)。像C/C++等都是编译型语言。程序在执行之前需要一个专门的编译过程,把程序编译成 为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++、Delphi等.
而相对的,解释性语言编写的程序不进行预先编译,以文本方式存储程序代码。在发布程序时,看起来省了道编译工序。但是,在运行程序的时候,解释性语言必须先解释再运行。

解释型语言:

相对于编译型语言存在的,源代码不是直接翻译成机器语言,而是先翻译成中间代码,再由解释器对中间代码进行解释运行。比如Python/JavaScript / Perl /Shell等都是解释型语言。程序不需要编译,程序在运行时才翻译成机器语言,每执 行一次都要翻译一次。因此效率比较低。比如Basic语言,专门有一个解释器能够直接执行Basic程 序,每个语句都是执行的时候才翻译。(在运行程序的时候才翻译,专门有一个解释器去进行翻译,每个语句都是执行的时候才翻译。效率比较低,依赖解释器,跨 平台性好.)

这些说明读完后仍然不能让读者形成直观的印象。实际上,对于有一定编程经验的人来说,这些区别早就体现在日常的编程经历中了。C语言和MATLAB作为使用率较高的编程语言,就可以很好的说明这些问题。
回想一下C语言的编程过程我们知道,C语言在执行前一定要先编译一下,如果发现语法错误,就会发出编译不通过的提示。而C语言就是一种编译型的编程语言。而对于MATLAB,我们写完MATLAB代码之后是不是直接点执行就等待结果了,如果有那一句代码发生错误的话,程序就执行到那一句才会停下来报错,所以MATLAB是一种一边执行一边解释的语言,解释是一句一句的翻译。,从而不需要预先进行编译,所以称之为解释型语言。
用流程图来说明就是:

图片出自https://zhuanlan.zhihu.com/p/111763425
这样二者的差异就很明显了。

人类对于复杂的事物往往在给出不同体系的理论后试图去实现理论的统一,但往往不能如愿以偿。作为语言来说,如果有一种语言能够拥有各种优点,它必然会在各种语言的百花齐放中脱颖而出,进而占据优势地位使其他语言消亡,事实上,现在解释型语言和编译型语言都有不错的发展,这就说明了一个问题,他们二者种的任何一个都有无法克服的相对缺点。

实际上,编译性语言不如解释性语言跨平台性好,也就是说不同平台的兼容性有区别,所以才有了两种语言。
编译性语言例如c语言:用c语言开发了程序后,需要通过编译器把程序编译成机器语言(即计算机识别的二进制文件,因为不同的操作系统计算机识别的二进制文件是不同的),所以c语言程序进行移植后,要重新编译。(如windows编译成ext文件,linux编译成erp文件)。

解释性语言例如java语言,java程序首先通过编译器编译成class文件,如果在windows平台上运行,则通过windows平台上的java虚拟机(VM)进行解释。如果运行在linux平台上,则通过linux平台上的java虚拟机进行解释执行。所以说能跨平台,前提是平台上必须要有相匹配的java虚拟机。如果没有java虚拟机,则不能进行跨平台。

实际上,就像人没有绝对的好人与坏人,对于语言是编译型还是解释型的区分往往不是非黑即白的。一般是某个语言满足某一种类型的特点,他就可以被当作其中的一份子。一个明显的例证就是Java语言。

Java的一些特性:

Java和其他的语言不太一样。因为java针对不同的平台有不同的JVM,实现了跨平台。所以Java语言有一次编译到处运行的说法。

1.你可以说它是编译型的:因为所有的Java代码都是要编译的,.java不经过编译就什么用都没有。

2.你可以说它是解释型的:因为java代码编译后不能直接运行,它是解释运行在JVM上的,所以它是解释运行的,那也就算是解释的了。

3.但是,现在的JVM为了效率,都有一些JIT优化。它又会把.class的二进制代码编译为本地的代码直接运行,所以,又是编译的。

作为人带有主观的偏向性来看,我认为java是解释型的语言,因为虽然java也需要编译,编译成.class文件,但是并不是机器可以识别的语言,而是字节码,最终还是需要 jvm的解释,才能在各个平台执行,这同时也是java跨平台的原因。所以可是说java即是编译型的,也是解释型,但是假如非要归类的话,从概念上的定义,恐怕java应该归到解释型的语言中。

编译型与解释型的共同点

都要弄成二进制代码,才能执行。两类编程语言,你手写的源代码 都是那些if,else之类的英文单词,计算机并不认识这些单词,所以都会要转化成二进制才能运行。区别就在于“转化的方式”。

编译型与解释型的不同点

1.从效果上来比编译型语言要全部写完之后,然后通过某个编译器,去生成一个类似*.exe的二进制文件,然后手工双击这个文件才看的到效果;解释型语言则没生成你看的到的那种.exe文件,而是直接发出效果。那么区别之一就是:是否显性的生成二进制文件供你去双击。

2.运行的时候是否需要编译器编译型语言运行的是最终的二进制代码了,所以不在需要编译器在身边守护。但解释型语言则不然,它是边解释、边运行,所以运行的时候很可能还有部分代码没有解释好,所以需要编译器守护(解释型语言把该工具叫:解释器)。那么编译器在哪里?就在浏览器里,所以你要看html效果,必须是用浏览器这种工具,或者有编译工具在内的其他工具,如:模拟浏览器的工具。

3.执行速度对比编译型语言由于运行的已经是完全的二进制内容了,所以运行起来很干净利落,自然速度快。但解释型语言,运行的不一定是完全的二进制内容,因为它是边解释(成二进制),边运行。所以当它执行看出效果的时候,程序后半部分还不一定解释成二进制呢。所以它是“三心二意”的做事,速度没有前者快,但是CPU的运行速度如果很快,你可能看不出来,偶尔会看到“有点卡”的效果。原因就是:它边解释、边运行,你看到效果了,可能还有一少半的代码没解释成二进制呢,所以你看到的效果会是残缺的,这就是为什么查看网页的时候,很容易就看到这样的情况:先是出现一堆没有布局的文字,然后才出现那种布局好的效果。前者由于程序执行速度快,同等条件下对系统要求较低,因此像开发操作系统、大型应用程序、数据库系统等时都采用它,像C/C++、Pascal/Object Pascal(Delphi)等都是编译语言,而一些网页脚本、服务器脚本及辅助开发接口这样的对速度要求不高、对不同系统平台间的兼容性有一定要求的程序则通常使用解释性语言,如Java、JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。

4.可移植性对比编译型语言是运行二进制内容,所以:一旦CPU指令系统改变,之前的二进制文件可能运行不了。比如:如果到其他硬件平台上运行,就可能出现错误,就需要根据该平台重新编译出新的二进制文件。所以:可移植性差;而解释型语言则不然。它并没有实现弄成什么二进制内容,而是在需要的时候才开始编译、运行。所以:它自然具有可移植性,即:在任何平台都可以马上运行起来。注意:它的解释工具如:浏览器,本身就是编译型语言解释出来的二进制代码,所以浏览器本身不具有移植性,是需要针对不同的平台弄出对应的浏览器最终二进制文件的。这里千万不要混淆了。

5.升级上对比编译型语言弄出来的二进制文件如果要升级,自然要重新下载一个新的二进制文件了。所以重新下载,安装,覆盖是最大的特点。比如QQ的升级,就是要重新下载,重新安装,重新覆盖,等个半天,而且很耗费CPU资源,体验性就不大好;而解释型的语言,只要重新写好源代码即可。用户提要到最新效果,只要刷新一下即可。所以体验性好。比如:某网站平台升级了,用户只要重新刷新一下…

6.应用领域编译型语言应用领域通常是那些安装软件,如:桌面上的那种安装软件;解释型的语言的应用领域通常是:互联网,网站等,那种刷新了一下就可以看到最新效果的领域。

实现原理角度分析

实现原理,简单来说就是:是不是做成了“实时采集”;

编译型语言没有做“实时采集”。它选择了一次性解决问题,表现为:先弄出完整的二进制代码之后,再让用户去执行该二进制代码,这样省事、省力、省心。但造成可移植性差、升级麻烦的后果。

解释型语言,采用了“实时采集”的措施,做成“边解释、边运行”。但这样带来的直接弊端就是:边走边看,因此速度自然要慢一些。不过现在的CPU、内存等硬件能力都很强大,这个方面的影响可以忽略。而它带来的非常便捷的升级,让它更显示出独特的魅力。所以它在移动互联网的领域,在只要刷新一下就可以看到最新效果的领域,是独一无二的霸主。

结论

二者都是客观事物,各有优势和劣势,没有绝对的正确和错误之分。但随着硬件的升级和设计思想的变革,编译型和解释型语言越来越笼统,主要体现在一些新兴的高级语言上,而解释型语言的自身特点也使得编译器厂商愿意花费更多成本来优化解释器,解释型语言性能超过编译型语言也是必然的。

部分内容出自:
https://zhuanlan.zhihu.com/p/26302914
https://zhuanlan.zhihu.com/p/111763425
https://www.jianshu.com/p/54e2aeca013b
https://blog.csdn.net/u012184539/article/details/81348780
https://www.cnblogs.com/zjushuiping/archive/2013/01/06/2848478.html

二.动态类型语言与静态类型语言

发展历史

在对二者进行说明之前,我们先来了解一下动态语言和静态语言的发展历史。动态语言是“微机时代”的代表,为编写KB级项目而设计的,从技术上讲非常过时。windows95出现之后,绝大多数动态语言都“死掉”了。微机时代计算机并不是独立学科,而是属于电工学的一个分支。所以严格意义上,当时没有程序员,只有“写代码的电工”。微机时代的计算机使用软盘储存数据,最大容量才1.4MB,程序都特别简单,一个完整的商业操作系统才几百kb。当时的三大操作系统(MS-DOS、Amiga、Unix)均在500kb以下。由于动态语言的语法简洁,可以有效节省磁盘空间,因此在那个储存空间非常紧张,计算机还十分“脑残”的年代,非常有优势,处于统治地位。但从windows95诞生,计算机进入图形化时代,程序就开始变得越来越庞大。商业软件从平均几KB,增大到几MB,几十MB,甚至几百MB。计算机成为独立学科,职业程序员大量出现。“微机时代”宣告结束,“IT时代”到来。从此,动态语言越来越难以编写出合格的程序。硬盘普及,磁盘空间不再紧张。智能IDE的出现,拉动静态语言全面崛起,终结了动态语言的统治地位。通常我们所说的动态语言、静态语言是指动态类型语言和静态类型语言。
原文链接:https://www.zhihu.com/question/316509027/answer/627889515

动态类型语言(Dynamically Typed Language):

动态类型语言是指在运行期间才去做数据类型检查的语言,也就是说,在用动态类型的语言编程时,永远也不用给任何变量指定数据类型,该语言会在你第一次赋值给变量时,在内部将数据类型记录下来。Python和Ruby就是一种典型的动态类型语言,其他的各种脚本语言如VBScript也多少属于动态类型语言。

静态类型语言(Statically Typed Language):

静态类型语言与动态类型语言刚好相反,它的数据类型是在编译其间检查的,也就是说在写程序时要声明所有变量的数据类型,C/C++是静态类型语言的典型代表,其他的静态类型语言还有C#、JAVA等。

二者区别

1.静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型;比如C/C++ 是静态类型语言的典型代表,其他的静态类型语言还有 C#、JAVA 等。动态语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型;像是Python 和 Ruby 就是一种典型的动态类型语言,其他的各种脚本语言如 JavaScript 也属于动态类型语言。

2.静态类型语言编译时会进行类型匹配检查,所以不能给变量赋予不同类型的值。为了解决这一问题,静态类型的面向对象语言通常通过向上转型的技术来取得多态的效果。动态类型语言的变量类型在运行期是可变的,这意味着对象的多态性是与生俱来的。一个对象能否执行某个操作,只取决于有没有对应的方法,而不取决于它是否是某种类型的对象。

3.静态语言的优势:由于类型的强制声明,使得IDE有很强的代码感知能力,故在实现复杂的业务逻辑、开发大型商业系统、以及那些生命周期很长的应用中,依托IDE对系统的开发很有保障;由于静态语言相对比较封闭,使得第三方开发包对代码的侵害性可以降到最低;动态语言的优势:编写的代码数量更少,看起来更加简洁,可以把精力更多地放在业务逻辑上。虽然不区分类型在某些情况下会让程序变得难以理解,但整体而言,代码量越少,越专注于逻辑表达,对阅读程序越有帮助。

4.静态语言由于强制声明数据类型,让开发工具(IDE)对代码有很强的判断能力,在实现复杂的业务逻辑和开发大型商业系统、以及那些声明周期很长的应用中,开发者可以依托强大的IDE来更高效、更安全地开发。

5.动态语言思维不受约束,可以任意发挥,把更多的精力放在产品本身上;集中思考业务逻辑实现,思考过程就是实现过程。
部分内容出处:https://m.php.cn/faq/416848.html

具体来说:

理解静态与动态之别,我们要从变量赋值这个操作为切入点。静态类型语言中,变量的类型必须先声明,即在创建的那一刻就已经确定好变量的类型,而后的使用中,你只能将这一指定类型的数据赋值给变量。如果强行将其他不相干类型的数据赋值给它,就会引发错误。
原图出自https://zhuanlan.zhihu.com/p/109803872
在静态语言中,一旦声明一个变量是int类型,之后就只能将int类型的数据赋值给它,否则就会引发错误,而动态类型则没有这样的限制,你将什么类型的数据赋值给变量,这个变量就是什么类型
原图出自https://zhuanlan.zhihu.com/p/109803872

更形象的说明:

在知乎上看到一个作者对二者进行了有趣的说明,摘抄如下:
原文链接:https://www.zhihu.com/question/316509027/answer/627889515

动态语言和静态语言最大的区别,在于可读性、可维护性的不同。小学生刚刚学习写作文的时候,总有很多字不会写。有的老师会让学生,把不会写的字,画成一个圈儿,即O。一个句子,原本应该写成写成“今天下雨了”。而有些小学生不会写“雨”字。就可以写成“今天下O了”。这个“O”可以代表任何东西,当然也可以代表雨。对于判作业的老师来说,这个“O”就是动态的。直到老师猜出这个“O”是雨之后,才能确定这个句子是不是病句。这种画圈儿的规则,是一把双刃剑,整体讲是弊大于利的。好处是可以让学生只掌握很少的汉字,就能开始学习写作文。但缺点是圈儿一旦变多,就会失控。常常连作者自己都分不清,每个圈儿分别代表啥?写的时候很容易,可第二天连自己都看不懂。而对于高年级的学生,就不允许使用“O”了。遇到不会写的字,就要去查字典,只有写出所有的字,才能把作文写完。对于判作业的老师来说,这就是静态的,有没有病句,一眼便知。虽然写出作文的门槛提高了,但表述更加清晰,无论任何时间翻出来,都能一目了然。编程语言比我们的例子要复杂,但道理是一样的,区别就是它不能只画“O”,而是不同的东西,需要用不同的“名字”表示,为了便于说明,下面的“名字”都使用一个字母来命名。比如一个句子是“板凳宽,扁担长,板凳不让扁担绑在板凳上”。用动态语言表示,则写成“A宽,B长,A不让B绑在A上”。写起来很省事,但维护起来就费劲了。因为A和B可以代表任何东西,凭什么一定就是“板凳宽,扁担长”,而不是“肥皂宽,牙刷长”?而用静态语言表示,则是“板凳A宽,扁担B长,A不让B绑在A上”。通过对比发现,静态语言比动态语言,多了一开始的“板凳”和“扁担”这两个词语。相当于从一开始,就标明了A是板凳,B是扁担。虽然要多写四个字,但可以避免歧义,增强可读性。只要用脑子记住“A是板凳,B是扁担”,岂不就能达到同样的效果?仅仅一个句子当然是可以的,人人都能记得住。而商业程序的代码量,一般在十万行以上。你不仅需要记住什么代表板凳和扁担,你还得记住水桶,暖壶,扫帚,簸萁,锅,碗,瓢,盆,油,盐,酱,醋,烟,酒,茶,糖。。。所以,为了解决这个问题,动态语言就需要靠加注释,来弥补自身可维护性的不足。可这样做也是不靠谱的。因为如果对代码进行封装,所需要注释的文字量,就会超过代码量本身,到时候你根本不是“写代码加注释”,而是“写注释加代码”。总之,动态语言只适合写非常非常小的程序,中型以上的程序,通常要使用静态语言编写,才会比较容易维护。我个人只在编写1000行以内的小工具时,才会使用动态语言,如Python、Lua等。但即便如此,还是常常一不小心,就陷入“第二天看不懂”的窘境。当然,“不适合”并不代表“绝对不能”,就像“徒手搬砖只适用于小型建筑,大中型建筑要使用工程机械”,这说法我一般认为是正确的。但总有一些人会举极端的例子来反驳,说万里长城和金字塔是用手磊出来的,这就实在没意思了。。。动态语言存在的的第二个问题,就是容易产生BUG,并且很难在第一时间发现。假如我们遇到一个游戏,它是用静态语言编写的,其中有一段代码是这样的(伪代码):角色 A=李逍遥;怪物 B=树妖;技能 C=御剑术;武器 D=钢剑;然后我们编写了一段代码:“A装备着D,发动了C,击败了B”这段代码很容易翻译,就是“李逍遥装备着钢剑,发动了御剑术,击败了树妖”。假如我们一时不小心,把代码写成“李逍遥装备着树妖,发动了钢剑,击败了御剑术”的话,会怎么样?这时候IDE会立刻报错,并提示你出现了三个错误。1,树妖是怪物,不能装备2,钢剑是武器,不能当做技能使用3,御剑术是技能,无法被击败如果不排除这些错误,你的程序就无法继续顺利编写下去。所以你只好先排除这三个问题之后,才能继续写代码,套用前面的例子,也就是高年级学生“查字典”了。由于绝大多数的问题,都必须在写代码的过程中,通过“查字典”排除掉,所以只要你的程序可以顺利写完,运行起来也基本不会有太大的问题了。但如果这个程序是使用动态语言编写的,则不会报错。既然B可以是任何东西,那凭什么必须是钢剑,而不能是树妖?这完全符合动态语言的语法规则,IDE当然不会报错。所以直到你的程序写完,BUG一堆一堆的冒出来,IDE却始终认为你的代码完全正确。所以使用动态语言,有很多错误,IDE是不会帮你检查的。你就要在每一个可能出错的地方,加上注释,提醒自己A是啥东西,B又是啥东西。。。。。最后你会发现,若要保证你自己写的程序不出BUG,而且日后还可以正常维护的话,那么你需要写的注释,比代码本身还多。写着写着,你就不像在编程了,而像在写一本说明书。

常见语言分类

以下语言,皆属于动态类型:
1.PHP
2.Ruby
3.Python

常见的静态类型语言则有:
1.C
2.C++
3.JAVA
4.C#
链接:https://www.jianshu.com/p/54e2aeca013b

三.强类型语言与弱类型语言

弱类型定义语言(Implicit type conversion,类型不安全的语言):

数据类型可以被忽略的语言。它与强类型定义语言相反, 一个变量可以赋不同数据类型的值。举例:在VBScript中,可以将字符串 ‘12’ 和整数 3 进行连接得到字符串 ‘123’, 然后可以把它看成整数 123,而不需要显示转换

例如PHP/ASP/Ruby/Python/Perl/ABAP/SQL/JavaScript/Unix Shell等注意:强类型定义语言在速度上可能略逊色于弱类型定义语言,但是强类型定义语言带来的严谨性能够有效的避免许多错误。

强类型定义语言(Explicit type conversion,强制数据类型定义语言,类型安全的语言):

一旦变量被指定某个数据类型,如果不经强制转换,即永远是此数据类型。举例:若定义了一个整型变量a,若不进行显示转换,不能将a当作字符串类型处理
强类型语言是指需要进行变量/对象类型声明的语言,一般情况下需要编译执行。例如C/C++/Java/C#

优劣分析

对比起强类型,弱类型的缺点大概如下:
(1)弱类型不符合“所见即所得”,定义的变量类型是不可预见并且可以改变的。
(2)为了兼容弱类型,语言执行引擎要做了大量的兼容工作,包括类型识别,内存管理,类型转换等,增加了语言内部处理的复杂度,会导致执行效率的降低。
(3)变量的类型是不可控的,因此执行过程中拥有大量的变量类型“隐形转换”,在开发同学不清楚隐性转换规则的情况下,容易产生不可预知的结果。这个特性也完全不符合所见即所得的简单性。但是,它们之所以可以发展起来,脱颖而出,也是有原因的,存在就有它的道理。
弱类型等语言特性,降低了程序员编写语言的门槛。编程言语是人类和机器沟通的桥梁,终极追求其实是“降低人和机器的沟通成本”,追求“人人皆可编程”的境界。
例如,从机器语言的0和1开始,后来变成汇编语言,汇编语言发展出来C,后来再有现在的脚本语言。编程学习的门槛不断降低,程序员的数量也随着指数增长。
而且,我相信未来还会继续发展出更低学习门槛的语言,促进程序员数量的再一次指数增长。弱类型的语言也有优点:
(1)屏蔽了语言的复杂性和容易导致错误的地方,例如:内存管理、指针、变量的类型等。虽然,它屏蔽了比较复杂的特性,但是,并不代表它们不存在,这样的做法是对人友好(编程更简单,考虑的东西更少),但是对机器不友好。
(2)项目开发效率高。
(3)学习门槛低。
它虽然带有不少的问题,但是,也包含了很明显的优点。
PHP比较大范围地用于Web开发,Javascript统治浏览器端的开发

原文链接:https://www.zhihu.com/question/20370449/answer/58395126
原文链接:https://www.zhihu.com/question/19918532/answer/23217475

全部内容的总结

有两幅图可以清晰的说明一些问题:
1.
图源知乎
2.
图源知乎
红色区域外:well behaved (type soundness)红色区域内:ill behaved
如果所有程序都是灰的,strongly typed
否则如果存在红色的程序,weakly typed

编译时排除红色程序,statically typed
运行时排除红色程序,dynamically typed

所有程序都在黄框以外,type safe

原文链接:https://www.zhihu.com/question/19918532/answer/63732584

©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页