在这篇文章中,我将带大家深入了解C#编程语言的核心概念,包括类的实例化、访问修饰符的应用,以及C#中不同数据类型的默认值。我会通过逐步分析和具体实例,详细解释如何在C#中正确创建和操作对象,并探讨如何通过访问修饰符控制类成员的访问权限。此外,我还打算深入探讨C#的内存管理机制,特别是堆和栈在对象生命周期中的作用,以帮助读者全面理解这些基本但关键的概念。
一图展示什么是类的实例化
接下来我将从上至下向各位说明这张图
在这张图中,首先看到的,就是实例化”Computer"类的语句
Computer com = new Computer();
在这个语句当中,Computer
为类名,com为实例化Computer
类的对象名,new为实例化Computer
类的关键字,()是编译器用以调用Computer
类的构造函数的符号
让我们分析实例来理解以上四句话
在这张图片中我们定义了一个类,类名为
Computer
紧接着我们声明了一个变量
com
,但没有初始化。
而后,我们使用
new Computer();
语句创建了一个 Computer 类的新实例,但是没有将这个实例赋值给任何变量。这意味我创建了一个 Computer 对象,但是没有引用
它
最后,将两者合并起来看
现在我们知道了,等号左边声明了一个变量com
,等号右边创建了一个 Computer 类的新实例
,这个语句就是将Computer 类的新实例
赋值给变量com
。也就意味着变量com
引用了实例Computer
,那么,等号左侧就是变量com对实例的引用,等号右侧就是Computer 类的新实例
接下来我们有请AI小助手为解释为什么上图中
Computer com = new Computer();
使用堆栈的相关知识解释这个语句
在C#中,
Computer com = new Computer();
这个语句涉及到计算机内存的两个关键部分:堆(Heap)和栈(Stack)。这两部分在内存管理中扮演着不同的角色,尤其是在对象的创建和引用方面。
Computer com
)时,这个变量(如果它是一个引用类型)存储的是对堆上对象的引用。这个引用存储在栈上。Computer com = new Computer();
的内存操作new Computer()
会在堆上为 Computer
类的一个新实例分配内存。Computer
实例的地址(或引用)被存储在变量 com
中。com
本身存储在栈上,因为它是一个局部变量。com
包含了指向堆上 Computer
对象的引用。通过这种方式,栈和堆协同工作,使得您能够在程序中创建和使用对象。栈提供了快速的变量访问,而堆允许动态地分配更大的内存空间来存储对象实例。
如此,我们知道了
变量
对堆上对象
的引用
所有的对象实例
首先我们来回顾一下访问修饰符的概念
说说在C#编程中常用的访问修饰符及他们的作用
在C#中,访问修饰符(或访问限定符)用于定义类、方法、属性和其他成员的可访问性。这是确保数据封装和对象的安全性的关键部分。以下是C#中常用的访问修饰符及其作用:
public:
private:
protected:
internal:
protected internal:
private protected:
每个修饰符都提供了不同级别的封装,允许开发者在保护数据和功能的同时提供必要的接口。正确使用这些修饰符是面向对象编程中的一个重要方面,有助于创建结构良好、易于维护和扩展的代码。
默认情况下,如果没有指定访问修饰符,类的成员(字段、属性、方法等)在C#中是私有的(private)。这意味着它们只能在其所属的类内部被访问。
接着我们通过实例来了解
访问修饰符
这一概念
通过下图我们看到对象
com
是找不到它的属性age、name、alive的,尽管我们在Computer实例中已经声明了这些变量
这是因为对象引用对于非静态的字段,方法或属性“Program.com”是必须的
对象引用对于非静态的字段,方法或属性“Program.com”是必须的
这句话是什么意思?
这句话“对象引用对于非静态的字段,方法或属性‘Program.com’是必须的”,指的是在C#编程中访问非静态成员(如字段、方法或属性)时,必须通过一个类的实例(即对象)来进行。
让我们分解这句话以更好地理解:
非静态字段、方法或属性:这些是属于类的实例的成员。换句话说,它们不属于类本身,而是属于类的具体对象。因此,每个对象有其自己的一套这些成员。
对象引用是必须的:要访问这些非静态成员,您需要一个指向类实例的引用。这意味着您必须先创建类的一个对象,然后通过这个对象来访问这些成员。
“Program.com”:这似乎是指在类 Program
中有一个名为 com
的成员引用。如果 com
是非静态的,那么您需要 Program
类的一个实例来访问 com
。
例如,假设您有以下类定义:
class Program
{
Computer com; // 非静态成员
static void Main(string[] args)
{
// 创建Program类的实例来访问com
Program programInstance = new Program();
programInstance.com = new Computer();
// 一些操作...
}
}
class Computer
{
// 一些字段和方法...
}
在这个例子中,要访问 Program
类中的 com
成员,您需要先创建 Program
类的一个实例(在这个例子中是 programInstance
),然后通过这个实例来访问 com
。 直接通过类名(如 Program.com
)来访问 com
是不可能的,因为它不是一个静态成员。
就是说在上图中缺少一个访问`com·的实例,可是我又不想创建一个新实例怎么办?
如下图,将Computer类的实例化语句放到Main方法中,这样com
就不再是Program类的成员,但Main方法作为入口函数,是程序开始执行的地方,这样就能保证com
对象的正常使用。可以看到,此时com
已经变成可访问状态
但当我试图通过
.
运算符来找到它的属性name
的时候,我们并没有看到name属性
这是因为name变量前面隐藏了一个访问修饰符
private
,结合上方的知识点,我们只要在前方加上public
,变量name
就变成类外部可以访问的变量了,如下图
此时,运行程序发现,结果是:我的名字是
,后面没了,这是为什么呢?
此时运行程序得出的结果是”我的名字是“,后面没了,为什么?
在您提供的代码中,
Computer
类的name
字段是public
(公开的),因此可以在Program
类中访问它。但是,在创建Computer
类的新实例com
之后,您并没有为name
字段赋予任何值。由于name
是一个string
类型的字段,而在C#中,未初始化的字符串默认值是null
。
所以,当执行 Console.WriteLine("我的名字是" + com.name);
这一行时,您实际上是在连接字符串 “我的名字是” 和 null
。在C#中,将 null
与字符串连接时,null
会被视为空字符串,因此结果就是 “我的名字是” 后面没有任何内容。
为了看到名字输出,您需要在输出之前为 com.name
赋予一个非空的字符串值。例如:
class Program
{
static void Main(string[] args)
{
Computer com = new Computer();
com.name = "Tom"; // 给name字段赋值
Console.WriteLine("我的名字是" + com.name);
}
}
class Computer
{
int age;
public string name; // 字段已声明为public
bool alive;
}
在这个修改后的版本中,com.name
被赋值为 “Tom”,所以输出将会是 “我的名字是Tom”。
由此,我们初步了解了
默认值
这一概念
看来windows也不认为我是个靓仔,桑心
在C#中,还有哪些类型是有默认值的?默认值是什么?
在C#中,所有的数据类型都有默认值。这些默认值取决于数据类型是否是值类型(如基本数据类型和结构体)还是引用类型(如类和接口)。以下是一些常见数据类型及其默认值:
int
, short
, long
, byte
等):默认值为 0
。float
, double
):默认值为 0.0
。decimal
:默认值为 0.0M
。bool
):默认值为 false
。char
):默认值为 \0
(空字符)。0
。null
。string
):默认值也是 null
。null
。dynamic
):默认值为 null
。null
。int?
, bool?
等):默认值为 null
。这些是值类型的特殊版本,允许值类型表示 null
。int defaultInt; // 默认为 0
bool defaultBool; // 默认为 false
string defaultString; // 默认为 null
MyClass defaultClass; // 默认为 null
在C#中,当声明一个变量但未显式初始化时,它会自动被初始化为其类型的默认值。这是C#的一项语言特性,旨在防止使用未初始化的变量。
常言道,出门在外,身份是自己给的,现在我宣布:我也是个靓仔了,谁赞成?谁反对?
今天的学习就到此结束了,感谢大家的喜爱,喜欢本文的话,给博主点个赞吧!记得收藏加关注哦!道友们的支持就是我更新的源动力!
回到顶部