类型
就是数据类型,数据结构其实就是数据类型的一个延伸。
1)数据类型就是一系列性质相同的值的集合,并对它们进行有效的表达。可见,数据类型来源于生产实践,不是凭空想象出来的。
2)数据类型配备了一系列与之相配套的操作。可见,某些操作是专门针对某一类数据类型的,不能混用。
3)数据类型,可以看成数据的“型号”,有不同的size。
计算机硬件系统分为运算器,控制器,存储器和I/O系统。
运算器+控制器:CPU
存储器:内存。程序要运行,必须要从硬盘加载到内存中才能运行。内存就是程序运行的空间。
数据类型(数据型号),指数据在内存中所占的空间。
好的程序员要考虑程序运行时的内存使用是否合理,有没有浪费内存,有没有出现内存泄漏(内存空间不能被释放)等等内存问题。
内存浪费,一是浪费硬件投资,二是挤占其他程序所需的内存空间,拖慢系统。程序性能不好。
扩展存储器:如硬盘,程序不运行时,就放在扩展存贮器中。即便断电,数据也不会丢。
启动一个程序快,要求内存大,硬盘快。
编程语言的数据类型和数学中的数据类型,大多数情况下一样,有时会有显著区别。
e.g. 数学中 :int 3 / int 4 = 0,75.
编程中,int 3 / int 4 = 0. 因为配备给整数的运算方法和配备给小数的运算方法不一样,整数运算的答案也要是int(在操作符部分会详解)。
编程语言分为
1)强类型(受数据类型约束很强),如:C#
长整型赋值给整型的变量,会报错。以此保证数据的完整性和安全性。
不允许类型的混用,保证了数据的正确性
C语言的强弱性没有C#强。C语言中,整型和bool是混用的,if判断条件只要不是0,都是true。
C#为了模仿弱类型的灵活性,引入了动态类型dynamic
//用dynamic可以获得类似Javascript在类型上的灵活性
dynamic myVar = 100;
Console.WriteLine(myVar);
myVar = "Mr.Okay!";
Console.WriteLine(myVar);
2)弱类型(不怎么受数据类型的约束),如:Javascript, 基本上不受数据类型的约束,很灵活,但是优点也是缺点,很容易把逻辑弄乱。写C和Javascript,一定要注意数据类型。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script>
function ButtonClicked()
{
var myVar = 100;
myVar = "Mr.Okay";
alert(myVar);
}
</script>
</head>
<body>
<h1> Hello Javascript! </h1>>
<input type="button"value="Click Me"onclick="ButtonClicked()"/>
</body>
</html>
类型系统非常重要,有很多相关面试题。
1)sbyte,带正负号,由于带符号,所以要用最高一位来给正负号。
2)byte,不带正负号
3)Char,Unicode16位,能放65535个字节,对于全世界的大多数语言都够用了。Unicode中收入的常用汉语也就几千个字符。
4)short,有正负号的短整型,若一个数字的范围在-32768 --- +32768之间,用一个短整型代表就行了,不会占用过多的内存空间。
5)ushort,无正负号的短整型。
6)int 带正负号的整型,32位,-2147483648 --- +2147483648。比方说某个幼儿园的孩子,数目不超过200,用一个短整型ushort表示就够了,不需要用int。
7)uint,32位,无正负号的整数,0 --- 4294967295
8)long,64位,带正负号的长整型。
9)ulong,64位,不带正负号的长整型。一般用于大型系统中,表示身份ID,长度足够用了。
float,可以精确到~6-9位小数。
基类型(BaseType也叫“副类型”)
在面向对象设计中,被定义为包含所有实体共性的class类型,被称为“基类”。
一个类型可以知道自己的基类型是谁,在整个继承链上,位于什么位置。两大作用:
1) 静态作用
非静态的类成员,就是实例成员。
一个程序在没有执行的时候,就是程序的静态时期,即:编辑期和编译期(build)。静态分析程序。
如:写好一段代码,其中需要访问一些类型的成员(变量,实例等),用编译器编译它,此时依然是静态期,此时编译器可以用所要访问的类型,去检验代码,如果有误,编译器直接报错。保证了程序的正确性。
2)动态作用
一个程序在执行起来后,就是程序的动态时期,即:运行期。动态调试程序。
C#的反射技能(高级技能),给定一个类型或对象,可以立即知道其中有哪些成员,并根据需要来操作这些成员。e.g.
Type myType = typeof(int);
Console.WriteLine(myType.Name); //类型名称
Console.WriteLine(myType.FullName); //类型全名
Console.WriteLine(myType.BaseType); //基类
Console.WriteLine(myType.BaseType.BaseType.FullName); // 基类的基类
e.g. Type myType = typeof(FormatException);
PropertyInfo[] pInfos = myType.GetProperties();
foreach (var p in pInfos)
{
Console.WriteLine(p.Name);
}
//打印出FormatException的 Properties。
Console.WriteLine(myType.Name); //类型名称
Console.WriteLine(myType.FullName); //类型全名
Console.WriteLine(myType.BaseType); //基类
Console.WriteLine(myType.BaseType.BaseType.FullName); // 基类的基类
//打印出FormatException的 Methods。
MethodInfo[] mInfos = myType.GetMethods();
foreach (var m in mInfos)
{
Console.WriteLine(m.Name);
}
类型的运算
e.g.
double result = 3.0 / 4.0;
Console.WriteLine(result); // 结果为0.75
double result = 3 / 4;
Console.WriteLine(result); // 结果为0,3和4是整型,运算结果也为整型,即便有double。
可见,数据类型知道自己该进行什么运算。如果是整型,除法的结果就是取整。
程序运行时,变量在内存的存贮
1. Stack 栈:内存分为堆和栈。
用于调用方法,比较小,一般只有几兆
2. Stack overflow:栈溢出
栈比较小比较快,但是会爆掉。如果:
a)算法没写好,函数调用过多,会涨爆。
b)程序有错误,分配了过多的内存,也会爆。
e.g 1. 下列程序,方法自己调用自己,只递不归,无限循环下去,就会撑爆栈,导致栈溢出。
class BadGuy
{
public void BadMethod()
{
int x = 100;
this.BadMethod();
}
}
static void Main(string[] args)
{
BadGuy bg = new BadGuy();
bg.BadMethod();
}
e.g 2. 直接到栈上切内存,只要切大了,栈就会爆掉,导致栈溢出。
unsafe
{
int* p = stackalloc int[99999999];
}
3. Heap 堆
存放对象和实例,比较大,可以有几个G
4. 使用Performance monitor查看进程的内存使用量
e.g.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Liu6HeapSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
List<Window> winList;
private void Button_Click(object sender, RoutedEventArgs e)
{
winList = new List<Window>();
for (int i = 0; i < 15000; i++)
{
Window w = new Window();
winList.Add(w);
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
winList.Clear();
}
}
}
Build编译上述代码。Build指编译自己的代码,以便和其他的代码组件“组装”在一起。build就是“组装”。软件工程师有个分支,叫build工程师,就是专门给大型软件做build。
右键点击,选中Open Folder,bin\Debug下有个应用程序。双击程序,使其从硬盘加载到内存中,开始执行之后,就形成一个进程。也就是这个程序正在运行的一个实例。程序运行起来后,会产生一个同名的进程,进程还会有进程ID,简称为pID(process id)。
windows+r,打开运行窗口,输入perfmon
打开性能监视器
5. 内存泄
堆不会爆掉,但是在堆里分配了很多对象,最后忘了回收这些对象,浪费内存,称作“内存泄漏”。
C++需要手动释放内存。
c#有内存垃圾收集器,会自动回收不用的内存。C#不容易出现内存泄漏。相对安全很多。
6.总结:类型在C#中的作用
变量都有自己的类型,程序会根据变量类型,将变量分配到堆或者栈(注意:实例永远放在堆里)。