如何通俗理解类和类型的差别?
如何通俗理解类和类型的差别?
我们日常编程经常遇到类和类型的概念,有时不免会对这两个东西产生纠结,它们究竟是同一种东西呢?还是有什么差别?
好的,我们今天就来通俗地聊一下,类和类型的差别。
数据总是有类型的,这个好理解,对吧?比如长度以米为单位来计算,重量以千克为单位来计算。为什么不能都用米或者千克来计算呢?为什么不能直接放一起加减乘除呢?因为它们是分别计量不同类型对的象的,所以本来就不是一个类型的数据,无法使用相同的计量单位,也不可能直接相加减。这是我们生活中关于数据类型的一个常识。
那么,C#中呢(其实不管什么语言中都是一个理)?数据,也是为描述对象服务的,对象类型不同,用于描述它们的数据类型自然也就不同。我们说,在程序员眼里,万物皆对象,那是否就有千万种数据类型呢?显然不是这样的。大道至简嘛,一定有一套相对简单的描述方案。C#约定了一切的数据类型的原始基类只有一个,叫做Object类型,这个除了为了表达和理解、以及溯源方便,有C#编程经验的同学,还应该知道因为有了Object类型,有些数据就可以通过“装箱”和“拆箱”操作来实现数据类型的转换。
然后,在Object的基础上,C#派生了两个基本的数据类型,分别是值类型和引用类型。
值类型比较好理解,就是数据对象本身不仅显示它的数据类型,也包含了数据的值。比如,一个数字3它是整数类型,或者一个字符“a”它是char字符类型。从外观上我们就能很好的理解它就是一个值类型的数据。
引用类型呢?就没有这么直观了,但是,我们仍然可以通俗地理解为:引用类型的数据对象和它的值是分离的,它们之间存在一个引用关系。当我们要读取一个引用类型的数据的时候,我们首先拿到的是数据对象的引用,然后再“顺着”引用去取到它的值。比如,我们知道字符串类型的数据是引用类型的,那么,如果有一个字符串:
string x = “abc”;
我们的程序是如何拿到x中的“abc”的呢?它就需要有一个过程,先通过x找到存放于内存中的“引用”,这个引用是啥?就是真正存放x数据“abc”的地址,这样我们就能通过这个引用拿到x的数据“abc”了。
因为网上有一些所谓的大咖发表一些微博或者帖子,说面试经常碰到一些内心有点鄙视的人(当然是程序员,很可能是新手程序员)对于值类型和引用类型表达不清楚。我个人认为,但凡入门了C#的同学,应该对值类型和引用类型是有所了解的,至少他了解的程度能够满足他当前编程的需要。但是,正如许多不喜欢“应试教育”的同学一样,他一时不能完整清晰地说出来,不代表他真的不理解这两者是什么或者有什么差别。
所以,为了今后更多的同学不被这样的弱智面试问题坑到,咱们这里再正儿八经的把值类型和引用类型分别简单地复述一遍,供同学们万一遇到了兴许能派上用场。
当然,深入理解值类型和引用类型,需要了解一点内存数据管理的小知识,这里简单普及一下。内存中的数据存放有两种方式:一种是栈,一种是堆。
栈中的数据先进后出,只有一个出入口,不是特别灵活,也只能分配给确定大小的数据,但是栈的效率非常高,这个很重要。
另一种是堆,它不仅能存储较大的数据量,而且还能动态分配存储空间,不像栈只有一个出入口,堆可以动态的任意取值,这个特性也给它带来了巨大的使用便利。但是,堆的这种结构使得它不如栈的效率高,这就是它的局限性。
我们回到值类型和引用类型的讨论,来看看他们在内存的堆栈中是如何分配的?
创建值类型时,系统运行时会直接为其在栈上创建数据存放空间,并将数据对象(即变量)的值与变量一起分配内存地址。这样读取变量的时候,可以直接读取变量的值。所以,值类型数据的存取效率较高。
那么,引用类型呢?系统运行时会为其分配两个空间,一个在堆上用于存放数据本身的值,另一个在栈上用于存放一个读取堆中数据的引用(实际上也是一个内存地址,或者叫指针)。
这样说来,引用类型的数据存取,显然效率较低一些,但它能存储更大量的数据,比如一些长文本等等。
好了,通过以上的描述,我们应该明白了什么是数据类型,以及两种不同类型的数据特征,如果再遇到那些神面试,应该也能应付了吧。至于值类型和引用类型的数据细分,这里我们就不继续讨论了,相信大部分同学自有分别。
接下来,我们再聊聊类。
类,在几乎所有的面向对象的编程语言中,绝对具有举足轻重的地位。因为它是描述对象的一个最重要的概念。
C#中,微软官方是这样定义的:
类是最基本的 C# 类型。类是一种数据结构,可在一个单元中就将状态(字段)和操作(方法和其他函数成员)结合起来。类为动态创建的类实例(亦称为“对象”)提供了定义。类支持继承和多态性,即派生类可以扩展和专门针对基类的机制。
上面这段话包含了诸多复杂的含义。我们简单的理解,类就是描述特定对象的一个总称。
但是,我们日常编程经常遇到类和类型,有时不免会对这两个东西产生纠结,它们究竟是同一种东西呢?还是有什么差别?
我个人比较倾向于这个问题应该更多的是中文的一词多义带来的困惑。在计算机语言的语法中,类型通常是使用Type来描述的,而类是用Class来定义的,它们具有两个完全不同的语言内涵。
我们回头再来细细的品味一下前面我说的“类就是描述特定对象的一个总称”这句话的完整意思,它实际上包含了两层含义:
第一,所谓特定对象,就是具有相同或相似特征的一类对象。
第二,所谓总称,是指类通常不是一个简单和单一的描述,而要把一类对象描述清楚,需要多重组合的描述来完成。这个多重组合的描述,在C#里,就是由字段、属性和方法来构成的,它们共同完成对具有相同或相似特征的对象(其实就是数据)的完整描述。
这里的第二层含义,我们在实际编程中经常去做,不停地创建各种自定义类。我们的类有时候是字段和属性使用多一点,有时候是方法使用多一点,这都无妨,代表了不同类的定义和用途而已。
我们需要注意的是,类的第一层含义。正是因为这一层含义,让类的定义,具有了分类的属性和特征。
事实上,胡乱的、毫无规划地创建一个类,在语法上也是成立的,很多入门新手就是这样干的。Class MyClass的确是很简单的事情。但是,正是因为有了第一层的含义,我们不能为所欲为,在创建一个类之前,我们需要对我们要处理的对象和数据需要做一些基本的整理和规划,甚至要定义好它们的用途和使用规则以后,我们再来着手创建真正的类。
其实,这些我们自定义的类,就是C#类型的一种,它是在C#基本类型之外,允许程序员自主创建的数据类型。并且,它归类于引用类型。
所以,从这个意义上来说,类和类型既有差别,本质上又还是同一种东西。这正是人类语言的智慧所在,回头看看,前人将Type和Class翻译为类型和类,是多么的贴切和恰当,如果你从来都不会混淆它们,似乎都是不对的。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何用命令行给mySQL添加用户
- [877]ModuleNotFoundError:no module named ‘tools.nnwrap‘ 解决办法
- Selenium自动化:代码测试与无代码测试
- 个人独立博客搭建教程(win),如何快速搭建博客
- dotnet OpenXML 解压缩文档为文件夹工具
- webpack实战——预处理器(loader)【上篇】
- Mac安装git,brew出现的问题
- dotnet OpenXML 简单聊聊 PPT 文本解析
- R语言作图——Ridgeline plot(山脊图)
- dotnet OpenXML 的 spcPct 和 spcPts 表示距离的不同
- 深入剖析.NETCORE中CORS(跨站资源共享)
- 网络安全实验室平台(基础关)
- Unity 基于excel2json批处理读取Excel表并反序列化
- dotnet OpenXML 文本 Text Line Break 的作用
- CVE-2020-1362 漏洞分析