第6、7节 详解类型、变量与对象(特别重要)
什么是类型(Type)
类型又称为数据类型(Data Type),数据结构是类型的延伸。
- 定义:A data type is a homogeneous collection of values(性质相同值的集合), effectively presented, equipped with a set of operations which manipulate these values(一些具体操作是专门针对某种数据类型的).
1)是数据在内存中存储时的“型号”;
2)小内存容纳大尺寸数据会丢失精确度、发生错误;
3)大内存容纳小尺寸数据会导致浪费;
4)编程语言的数据类型与数学中的数据类型不完全相同。
注意:型号指的是一条数据在内存中所占有的空间;内存是计算机程序运行的空间;扩展存储器是程序未运行时存储的空间,例如计算机的硬盘。硬盘转速越高,程序由硬盘向内存转移的速度越快,固态硬盘(SSD硬盘)比电磁性的硬盘更快。 - 强类型语言与弱类型语言的比较
当用一门编程语言编写程序时,若数据受数据类型的约束,则称该编程语言为“强类型语言”;反之,若数据受数据类型的约束很弱或者不受数据类型的约束,则称该编程语言为“弱类型语言”。
强类型语言保证了数据的完整性和正确性。
C#语言是强类型编程语言。
示例1:
int x; //int:4字节,32bit
x = 100;
long y; //long:8字节,64bit
y = 100L;
x = 100L;有误
bool b;
b = true;
b = 100;有误
示例2:比较 C# 和 C 的 if 语句
1)C#语言(强类型语言)
int x = 100;
if (x = 200)有误 //if条件语句的判断条件只能是bool类型的值ture或false
{
Console.WriteLine("It's OK!");
}
2)C语言(弱类型语言)
int x = 100;
if (x = 200) //非0即为真,所以为了避免发生这样的错误,一般写成 if(200 == x)
{
printf("It's OK!\n");
}
结果:
示例3:
JavaScript(动态类型)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title> //敲出<title>的另一半</title>只需要在打出“<title”之后,再敲“shift+/”即可
<script>
function ButtonClicked() {
var myVar = 100; //整型
myVar = "Sue!"; //字符串类型,说明JavaScript语言是一种弱类型的语言
alert(myVar);
}
</script>
</head>
<body>
<h1>Hello, JavaScript!</h1>
<input type="button" value=" Click Me" onclick="ButtonClicked()" /> //type、value、onclick之间不能用逗号隔开,只能用空格
</body>
</html>
![](https://i-blog.csdnimg.cn/blog_migrate/abf7aa0480f1ccfb886b75cf1fb47c27.png#pic_center)
C#语言对弱类型/动态类型的模仿(dynamic)
dynamic myVar = 100; //模仿JavaScript的弱类型
Console.WriteLine(myVar);
myVar = "Miss.Wang!";
Console.WriteLine(myVar);
类型在C#语言中的作用
- 一个C#类型中所包含的信息有
1)存储此类型变量所需的内存空间大小
2)此类型的值可表示的最大、最小值范围
3)此类型所包含的成员(如方法、属性、事件等)
程序的静态:程序非执行时(编辑期、编译期)
程序的动态:程序执行时(运行期)
Type myType = typeof(Form); //获取Form的对象
PropertyInfo[] pInfos = myType.GetProperties();
foreach (var p in pInfos)
{
Console.WriteLine(p.Name); //打印出Form的所有属性
}
Type myType = typeof(Form);
MethodInfo[] mInfos = myType.GetMethods();
foreach (var m in mInfos)
{
Console.WriteLine(m.Name); //打印出Form的所有方法
}
4)此类型由何基类(父类)派生而来
Type myType = typeof(Form);
Console.WriteLine(myType.BaseType.FullName); //打印出Form的父类的全称
5)程序运行的时候,此类型的变量在分配内存的什么位置
(1)Stack简介(栈):
空间较小,1~2兆,方法调用时使用 。
(2)Stack overflow(栈溢出):
函数调用太多;程序编写错误,分配内存太多。栈溢出的实例如下,
–>函数调用太多导致栈溢出
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StackOverflow
{
class Program
{
static void Main(string[] args)
{
BadGuy bg = new BadGuy();
bg.BadMethod();
}
}
class BadGuy
{
public void BadMethod()
{
int x = 100;
this.BadMethod(); //只递不归
}
}
}
–>分配内存太多
unsafe
{
int* p = stackalloc int[9999999];
}
C#语言中,不推荐使用指针,指针被认为是不安全语言,所以在程序运行前,需要做如下操作。
![](https://i-blog.csdnimg.cn/blog_migrate/7f4cacd91c8584ba69c2dad70931e062.png#pic_center)
(3) Heap简介(堆):
空间较大,几个G,存储对象。 堆的实例如下,
namespace HeapSample
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
List<Window> winList;
private void Button1_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 Button2_Click(object sender, RoutedEventArgs e)
{
winList.Clear();
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/7a80fa69f0e0865bf47c9bebdf677e06.png#pic_center)
(4) 使用Performance Monitor查看进程的堆内存使用量
(5) 关于内存泄漏:忘记内存回收
C++语言需要手动回收内存,而C#语言有垃圾收集器,会在合适的时候回收内存。
6)此类型所允许的操作(运算)
double result = 3.0 / 4.0;
结果:0.75
double result = 3 / 4;
结果:0
C#语言的类型系统
- C#的五大数据类型
1)类(Classes):如Windows,Form,Console,String
以Form为例,判断Form是不是类:
(1)光标放在Form中间,点击f1键。
(2)Type myType = typeof(Form); Console.WriteLine(myType.FullName);
找出Form的全称,再利用MSDN文档,点击Index进行搜索。
(3)Type myType = typeof(Form); Console.WriteLine(myType.IsClass);
直接判断是不是类。
(4)光标放在Form中间,点击f12键,查看Form的定义。
2)结构体(Structures):如Int32,Int64,Single,Double
3)枚举(Enumerations):如HorizontalAlignment,Visibility
Form f = new Form();
f.WondowState = FormWindowState.Maximized; //窗口的大小只有最大化(Maximized)、最小化(Minimized)、正常(Normal)三种可供用户选择
f.ShowDialog();
4)接口(Interfaces)
5)委托(Delegates)
注意:class:声明和定义类;struct:声明和定义结构体;enum:声明和定义枚举。
- C#类型的派生谱系
变量、对象与内存
变量 = 以变量名所对应的内存地址为起点,以其数据类型所要求的存储空间为长度的一块内存区域
- 什么是变量
1)表面上来看(从C#代码的上下文行文上看),变量的用途是存储数据
2)实际上,变量表示了存储位置,并且每个变量都有一个类型,以决定什么样的值能够存入变量
3)变量一共有7种:静态变量,实例变量(成员变量、字段),数组元素,值参数,引用参数,输出参数,局部变量。
4)狭义的变量指局部变量,因为其他种类的变量都有自己的约定名称
简单地讲,局部变量就是方法体(函数体)里声明的变量
5)变量的声明
有效地修饰符组成(opt) 类型 变量名 初始化器(opt)(opt表示可选的,可有可无)
public static int Amount = 0; //public static:有效地修饰符组合,int:类型,Amount:变量名,= 0:初始化器
另外,对7种变量做简单的实例介绍:
静态成员变量是隶属于类的,而不是类的实例;
public static int Amount; //静态成员变量
属性是为了保护字段,不让其随便被赋值;
public int Age;
public string Name;
数组元素:
int[] array = new int[100];
array[0] = 100;
值参数:
public double Add(double a, double b) //a、b是值参数变量
{
return a + b;
}
引用参数、输出参数变量:
public double Add(ref double a, out double b) //a是引用参数变量,b是输出参数变量
{
return a + b;
}
-
值类型的变量
1)以byte(无符号1字节)/sbtye(有符号1字节)/short(有符号2字节)/ushort(无符号2字节)为例
有符号位:0表示正数,1表示负数
100:01100100
-100:10011011+00000001= 10011100(对100的二进制数按位取反,再加1)
注:高八位存储在地址的高位上,低八位存储在地址的低位上
2)值类型没有实例,所谓的“实例”与变量合而为一 -
引用类型的变量与实例
引用类型变量与实例的关系:引用类型变量里存储的数据是对象的内存地址(引用类型变量被分配的内存空间是4个字节) -
局部变量是在stack(栈)上分配内存,实例和实例的成员变量是在heap(堆)上分配内存。
-
变量的默认值
成员变量在声明之后,会获得默认值0;C#的本地变量必须要有明显的赋值,没有默认值。 -
常量(值不可改变的变量)
const int x = 100; //const表示常量,初始化器不能省略
-
装箱与拆箱(Boxing & Unboxing)
装箱和拆箱会使性能有所损失。
装箱:将栈上值类型的值封装成obj类型的实例,存储在堆上;
拆箱:将堆上obj实例里的值按照要求拆成目标类型,放在栈上