C# OOP之五 深入理解值类型和引用类型
内存分配
我们在前面的章节已经了解了值类型和引用类型,下面我们重点讲下值类型和引用类型在内存中的分配情况。
值类型实例通常分配在栈(Stack)上,并且不包含任何指向实例数据的地址,因为变量包含了其实例数据。值类型主要包括简单类型、结构体类型和枚举类型。
例如如下代码:int iCount=50; //声明和初始化变量iCount
int iSum=iCount; //将iCount中的数据赋值给iSum
iCount++; //增加iCount对iSum无关
在内存中给值类型分配的图形标识:
视频:https://edu.csdn.net/course/detail/27107
|
引用类型实例通常分配在堆(Heap)上,变量保存了实例数据的地址引用,主要包括以下类型:class、interface、delegate、object、string以及其他的自定义引用类型。
如下代码:
-
Class Car
-
{
-
Public string Model;
-
Public int Money;
-
}
-
-
Static void Main()
-
{
-
Car Ford=new Car();
-
Car BYD=new Car();
-
}
注意:Ford、BYD中分别存放各自new Car()的内存地址,即通常说的引用。
|
为什么要使用结构,针对小型相关变量组,例如,矩形的坐标或系统颜色的定义及操作,因为值类型直接分配内存效率比引用类型要高,所以结构还是有自己的用武之地。通常结构用来充当不同系统之间的数据传递的载体或者用在要求效率极高的软件中,比如游戏设计中就会采用大量的结构。
结构是从C语言遗留下来的一种类型,在C#中结构使用struct关键字定义。可以包含构造方法、常量、字段、方法、属性、索引器等成员。
结构类型语法:
访问修饰符 struct 结构名
{
定义结构成员
定义结构方法
….
}
针对每家的消费开销做的一个小案例如下:
-
using System;
-
class Program
-
{
-
public struct Spending
-
{
-
public string Spending_No;//开销号
-
public string Spending_Name;//开销名
-
public string Spending_Date;//开销日期
-
public double Spending_Cost;//开销金额
-
public string Spending_Memo;//开销备注
-
};
-
static void Main(string[]args)
-
{
-
//注意:区分结构型的变量可以直接赋值使用
-
//类变量必须将类的地址赋给对象
-
Spending mySp;
-
Console.WriteLine("请输入你的开销号:");
-
mySp.Spending_No=Console.ReadLine();
-
Console.WriteLine("请输入你的开销名:");
-
mySp.Spending_Name=Console.ReadLine();
-
Console.WriteLine("请输入你的开销日期:");
-
mySp.Spending_Date=Console.ReadLine();
-
Console.WriteLine("请输入你的开销金额:");
-
mySp.Spending_Cost=Convert.ToDouble(Console.ReadLine());
-
Console.WriteLine("请输入你的备注:");
-
mySp.Spending_Memo=Console.ReadLine();
-
Console.WriteLine("***********************************");
-
Console.WriteLine("您的开销编号:{0}",mySp.Spending_No);
-
Console.WriteLine("您的开销名:{0}",mySp.Spending_Name);
-
Console.WriteLine("您的开销日期:{0}",mySp.Spending_Date);
-
Console.WriteLine("您的开销费用:{0}",mySp.Spending_Cost);
-
Console.WriteLine("您的开销备注:{0}",mySp.Spending_Memo);
-
}
-
}
【struct同class的区别:
1.不支持继承
2.为值类型;class引用类型;
3.没有缺省的构造器;
4.使用:通常用来封装小型相关变量组,例如,矩形的坐标或库存商品的特征;类封装比较多的相关变量;
5.思考:同样的变量数的结构和类,谁的存取效率更高;为啥是结构!!!
6.结构不能声明默认构造函数(没有参数的构造函数)或析构函数
7.在结构中给实例字段赋值是错误的;
8.结构可以声明构造函数,但它们必须带参数。到第6章再讲,注意提醒我!!!
9.一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自 System.ValueType,后者继承自 System.Object。到继承再讲;
10.结构可以实现接口。注意到接口再讲;
】
|
枚举用在什么地方?打开每个文件的属性,我们会看到“只读、隐藏、存档”;操作一个文件时,你可以采用只读、可写、追加等模式;设置系统级别时,你可能会选择紧急、普通和不紧急来定义。这些各式各样的信息中,一个共同的特点是信息的状态分类相对稳定,在.Net中可以选择以类的静态字段来表达这种简单的分类结构,但是更明智的选择显然是:枚举。
枚举定义:
访问修饰符 enum 枚举名 {值1,值2… }
n 枚举是一组描述性的名称
n 枚举定义一组有限的值,不能包含方法
n 对可能的值进行约束
n 枚举允许描述性名称表示整数值
案例:
….
枚举的典型应用(WinForm):
-
DialogResult choice;
-
choice = MessageBox.Show("确定要退出吗?", "退出系统",
-
MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
-
if(choice == DialogResult.OK) //DialogResult是个枚举,指示对话框的返回值
-
Application.Exit();
做一个枚举扑克牌的花色,enum Suit{Clubs,Diamonds,Hearts,Spades};
在此处Suit枚举的基础类型默认为int型,枚举的指定类型只能是除char外的8种整数类型:byte、sbyte、ushort、int、uint、long和ulong,声明为其他类型将导致编译错误。
第一个元素默认为0,然后各成员依次加1;如果有成员显式设置相应值(比如8),则后续成员仍然在此值基础上加1;
|
一中小企业,老板给员工分配了一项任务,计算公司(25人)的平均销售额。
定义25个销售变量合适不?然后销售总额除以25可以吗?
为什么需要数组,我们去旅馆(宾馆)住宿,有不同的房间类型(单人间、双人间、三人间、豪华套房等),不同的房间类型又分不同的房号(比如从301—318;401—409等),这样客户根据不同的经济条件就可以选择相应的房间类型,然后旅馆为其分配相应的房间号。
数组:数组是一个变量,存储相同数据类型的一组数据
如何使用数组四步骤:
1、声明数组
int[ ] a;
2、分配空间
a = new int[5];
3、赋值
a [0] = 8;
4、处理数据
a [0] = a[0] * 10;
1、声明数组: 告诉计算机数据类型是什么
语法:
数据类型 数组名[ ] ;
数据类型[ ] 数组名;
int[ ] Sales; //销售业绩
int Sales[ ]; //销售业绩
String[ ] empName; //员工姓名
2、分配空间: 告诉计算机分配几个格子
语法:
声明数组并分配空间
数据类型[ ] 数组名 = new 数据类型[大小] ;
Sales = newint[30]; //数组为引用类型,所以,需要new
Sales = newint[6];
empName = newString[30];
3、赋值:向分配的格子里放数据
score[0] = 89;
score[1] = 79;
score[2] = 76;
……
思考:考虑如何一次多个赋值,希望大家给出解决方法
4、对数据进行处理:计算25位员工的平均销售额
-
for(int i = 0; i< 25; i ++){
-
Sales[i] = Console.ReadLine();
-
}
-
int sum = 0;
-
double avg;
-
for(int index = 0;index < Sales.length; index++){
-
sum = sum + Sales [index];
-
}
-
avg = sum /Sales.length;
回顾问题:一中小企业,老板给员工分配了一项任务,计算公司(25人)的平均销售额,使用动态录入并赋值的方式计算平均销售额
Foreach循环:
Foreach(基本数据类型 变量名/对象名 in <array>)
{
循环遍历数组中的各元素
}
定义二维数组:
数据类型[,]数组名=new 数据类型[行数,列数]
针对多维数组一般都采用使用循环来初始化数据
案例:求1个3行3列距阵对角线的和,数字距阵如下:
1 2 3
4 5 6
7 8 9
-
ClassTwoArray
-
{
-
static void Main(string[]args)
-
{
-
int[,]a={{1,2,3},{4,5,6},{7,8,9}}
-
int sum=0;
-
for(int i=0;i<3;i++)
-
{
-
if(i==j||i+j==2)
-
sum+=a[i,j];
-
}
-
}
-
Console.WriteLine(“和为:{0}”,sum);
-
}
思考:注意体会循环中判断
接下来,我们来看一下,Main()中的参数string[]args,我们已经学过方法参数和数组了,那么Main()中的东东是什么呢?就是一个string类型的数组而已。
那么这个数组有啥用呢?
我们称之为Main()的命令行参数,使用方法是在运行时,输入数据,传递给args数组,代码如下:
class CommandLine
{
staticvoid Main(string[] args)
{
System.Console.WriteLine("参数总数{0}", args.Length);
for (int i = 0; i< args.Length; i++)
{
System.Console.WriteLine("args[{0}]= [{1}]", i, args[i]);
}
}
}
编译:csc CommadLine.cs
运行如下几种命令行参数,试验效果如何?
命令行输入 |
传递给 Main 的字符串数组 |
CommadLine.exe 老板 Boss CEO |
"老板" "Boss" "CEO" |
CommadLine.exe老板 Boss |
"老板" " Boss" |
CommadLine.exe "老板 Boss " CEO |
"老板 Boss " "CEO" |
|
1.如果数组声明为 int[] arr = new int[16],则数组中的元素个数为______.
A.15 B.16 C.17 D.18
2.看一些代码,输出的结果为( )
-
using System;
-
class nameee
-
{
-
public static void Main()
-
{
-
int Number1=0;
-
int Number2=0;
-
int[] Array1=new int[]{12,33,24,65,26,47,38,29,90,41,99,81};
-
foreach (int Ctr inArray1)
-
{
-
if (Ctr%2 == 1)
-
Number1++;
-
else
-
{
-
Number2++;
-
Console.WriteLine (Car);
-
}
-
}
-
}
-
}
A. 12,24,26,38,90 B.33,65,47,29,41,99,81
C.Ctr D. 12, 24, 26,29,33,38, 41, 47, 65,81, 90, 99
3.如果数组声明为string [] arr = new string[5],则数组的基类型是______.
A.string B.int C.long D.byte
4.在数组中,它的下标即数组的第一个位置是从______开始。
A.0 B.-1 C.1 D.2
|
在本章中,我们主要学习了:
u 值类型和引用类型的内存分配
u 值类型的两种新类型:结构与枚举的定义与使用
u 数组的使用
|
英文 全文 中文
Struct 结构
Datatype 数据类型
Namespace 命名空间
Detail 详细、详情
Product 产品
Cost 花费
Advance 高级
Enum 枚举
Array 数组
Source 源
Target 目标
Code 代码
Check 检查
Loop 循环
Foreach 循环
Param 参数
Total 总共的
Content 内容
Row 行
Length 长度
Rank 排; 横列; 行列
Sort 排序
Clear 清空
Index 索引
Framework 框架
Collection 集合
Queue 队列
Stack 堆栈
|
1. 利用结构来设计一个矩形,来实现求其面积,注意(设计矩形结构的Height、Widtd,可以适当参考MSDN)
课程项目扩充:
2.猜数游戏:从键盘中任意输入某员工销售额,判断销售数组中是否包含此销售额
3.求销售数组中的最大值。
文章来源: aaaedu.blog.csdn.net,作者:tea_year,版权归原作者所有,如需转载,请联系作者。
原文链接:aaaedu.blog.csdn.net/article/details/51254011
- 点赞
- 收藏
- 关注作者
评论(0)