只能从声明变量的命名空间中访问静态变量_C#-面向对象:基础中的基础-类和对象...

477e344ae6082978914e0d4c50cec3f0.png

我们说过,学习完变量赋值分支循环,理论上我们就可以干任何事情了。从函数开始,我们就从代码实现 步入了代码管理 的领域。几千上万行的时候,我们可以用几十个函数实现对代码的组织重用,但随着代码量的进一步增加,代码行数以万计数以十万级,函数都数以千计数以万计的时候,我们怎么办呢?

光是记忆这些函数,人脑都相当吃力了!(其实还有命名,^_^)

注意,牢记这一点,人脑的局限或者特点,是我们不得不求助于

面向对象

的重要原因。

想一想,我们如何管理成千上万的函数?一个简单的办法,就是分

类:

比如,和控制台相关的函数一类,和计算相关的函数一类……这样,我们想调用一个控制台方法的时候,就可以先找到控制台(类),然后在控制台中寻找方法。事实上,我们也确实是这样做的:

Console

Console就是一个类,点(.)就相当于“的”,WrtieLine()就是方法名。所以整行代码的意思就是:调用Console类的WrtieLine()方法。

演示:F12转到WrtieLine()

我们也可以自己声明(创建)一个类,这需要使用

class关键字

在控制台项目右键->Add->New Class,或直接使用Shift+Alt+C,就会弹出添加类(文件)的窗口,输入类名,比如Student(命名规则/规范),点击Add,就会在项目中添加一个Student.cs文件,文件中已经有如下代码:

using 

演示:

先说

.cs文件

我们也把它称之为类文件,cs是csharp的缩写。通常,一个 .cs 文件里面放一个class,文件名和类名相同。但是,.cs文件名也可以和类名不一致,一个.cs文件里也可以有多个class,为了教学演示方便,我们前期就会这样做。本质上,.cs的文件名不影响类名,文件名和class冲突,以class后面定义的类名为准。

另外,类还可以被放置在类中,形成类中类

class 

或者使用partial关键字生成部分类

partial 

(同名的)部分类会在编译的时候被合成为一个类,所以我们完全可以把部分类当成一个类使用。

但这些都是非常规的做法,我们一般不要使用。尽量一个类一个类文件。

对类文件而言,.cs后缀很关键,不能修改,它指示编译器使用C#语法进行编译。如果代码以http://VB.NET书写,就以.vb为后缀。

.cs文件的内容实际上分为三部分:using、namespace、class。这涉及到

类的名称

实际上,关键字class后面跟的不是类的全名,而是一个部分名 。类的全名是:名称空间+点(.)+部分名,类的名称空间由namespace定义,所以这个类的全名是Yuanzhan.Student。为什么搞得这么复杂呢?

首先,类名是不能重复的。所以,当类越来越多,重名的几率就会越来越大,“命名”就会变得越来越困难。怎么办?一个办法就是加前缀。;但是,“就比如“学生”,这简直太太普遍了源栈的学生”(YuanZhan.Student),就好多了;如果还担心源栈有重名,就再加一个“大飞哥的源栈的学生”(Dafeige.Yuanzhan.Student)就是了。部分名之前的前缀就叫做

名称空间

注意名称空间一般都是按层级组织的,比如:

  • Dafeige.Yuanzhan.Student
  • Dafeige.Yuanzhan.Teacher
  • Dafeige.17bang.User
  • Dafeige.17bang.Problem
  • ……

但这就是为了便于(开发人员)理解和记忆。C#编译器不关心名称空间的“层级”,换言之,Dafeige和Dafeige.17bang是两个完全不同的名称空间。

然而,每次都使用全名,会非常的麻烦!所以,C#提供了这样一个机制:当源代码中出现了部分名时(也就是找不到这个类名的时候),编译器会依次将部分名:

  1. 和当前代码所在的namespace组合,
  2. 和using中的namespace组合(using后面也只能跟名称空间)

生成全名,以确定这个类。

所以,我们来看下面的代码:

af1c66c1e23d4be9783bbf2e5b52fefc.png
  1. Student实际上是Yuanzh.Student(和当前所在的名称空间组合)
  2. Console实际上是System.Console(和using中的System组合)

f74666979fb5e39c9d76a02f2ba9934e.png

有时候还会出现部分类名可以和当前类文件中using的多个名称空间组合的情形,比如有两个User类:

//命名不能以数字开头,所以加一个下划线

在使用的时候就会报错:

e4c6c1bca17832226a0baa24bb6e48ab.png

编译器无法知道你究竟是要_17bang.User还是要feige.User,这时候你只能使用全名:

new 

有时候全名会很长,这时候可以使用名称空间别名:

using 

现在回头看看我们一直在使用的Program.cs,它也是一个类文件,其中的class就声明了的Program类,Program中又声明了Main()方法。注意Main()方法前面的

static(静态)

它表示这个方法:

  • 属于这个类
  • 可以直接由类名进行调用

我们可以把之前和学生相关的方法都搬到Student类中去:

class 

这样,greet()就变成Student的方法了,我们可以在Main()中通过Student调用:

static 

你可能会问:为什么以前就可以不用Student.呢?哈哈,因为以前你的greet方法是属于Program类的呀!同一个类中的方法之间的互相调用是不需要加类名的。

你还一定注意到了我们在greet()方法前面加了一个public关键字。它被称之为:

访问修饰符

它决定了greet()方法能不能在类的外部被调用(访问),包括:

  • public:公开的,可以在外部任何地方使用
  • internal:内部的,可以在当前项目中使用
  • private(默认):私有的,只能在自己类的内部使用

我们可以在类中再装入两个方法,使用不同的访问修饰符:

internal 

演示:

新建一个项目OutSample,引用YuanZhan项目,在OutSample的Main()中调用Student.greet()等……

访问修饰符除了可以修饰方法(以及后文讲到的其他类成员),也可以修饰类本身。但类不能使用private,且默认修饰符是internal。

通常来说,

  • public的成员命名,我们使用命名法;
  • private的成员命名,我们使用(小)驼峰命名,甚至在前面加上下划线(_);
  • internal的成员命名,可以匈牙利可以驼峰,本教材我们统一使用驼峰命名法

访问修饰符对于面向对象至关重要,因为依靠它,才能真正的实现:

封装

把方法分门别类的组织起来,装到不同的类里面,这只做到了,还没有做到。只有使用了这些访问修饰符,才能保证让类能够封闭一些逻辑(代码实现),开放一些接口(调用方法)。

为什么需要封闭呢?开放不好么?现在不都提倡“开源”么……

咳咳!这个不是这样理解的。鉴于同学们目前的开发经验,我只能要求大家记牢两点:

  1. 总是尽可能地给最低的访问权限
  2. 不要把访问修饰符当成“安全策略”使用通过反射,即使private的类成员都可以被获取

类里面除了可以存放方法,还应该可以存储数据。因为对数据的封装是一个非常普遍的要求(参照之前的元组)。在类中存放数据的成员叫做:

字段

注意不要将字段和变量混淆,在类中声明的是字段,在方法中声明的是变量:

class 

他们还有以下区别:

  1. (静态)字段可以在类中任何地方声明,在任何地方使用;变量在方法中声明,作用域为自声明开始到声明位置对应的第一个花括号(})结束
  2. 如果字段和变量同名,在同一个方法中,变量优先
  3. 字段被属于类,通过类调用;变量不属于任何成员,直接使用
  4. 变量未赋值不能使用;字段可以使用,值为默认值
static 

你说等等,还有字段前要加static,变量前不能加static……

停!错!!!变量前面确实不能加static,但字段也是可以不使用static:

internal 

不仅字段,方法也可以没有static哟!他们被称之为

实例

你注意到没有,我们本来是要讲面向对象的,但我们一直都在讲类啊!对象在哪里?

对象是类的实例,所以,实例化一个类就能得到这个类对象。

我擦!什么鬼?

稍安勿躁,^_^,我们有了类的概念,比如学生类,学生类里可以放一些和学生相关的方法或字段。但有些东西是类的静态成员无法体现的,比如学生的姓名:

Student

学生这个类的姓名都叫“阿泰”?这说不通。我们只能说某一个学生的姓名叫“阿泰”,另一个学生的姓名叫“陈元”,这样才对。当然,阿泰和陈元都有共同的特点,他们都在飞哥的源栈学习(learn()),都有学习成绩(score),等等,所以他们学生。

在面向对象的世界里,阿泰和陈元都是对象,而且是Student类的对象,因为他们都具有(能调用)Student类所定义的,但是有各自独立的方法(行为)和字段(状态)。

那如何获得呢?new一个就可以了:

new 

这样我们就得到了一个Student类型的对象。使用这个对象,就可以调用Student类中所有实例 方法和字段:

//可以调用实例成员

因为对象通过类创建,我们也可以认为:类是创建对象的模板

但是注意运行上述代码,我们会发现代码行2的结果是0而不是23。这是因为new是一个运算符,意味着“构建”,每new一次都会生成一个新的对象。所以代码行1和代码2实际上各自生成了两个不相关的对象,新生成的对象上的age字段没有被赋值,所以只有其默认值0。

所以我们通常会在通过new得到一个对象之后,将其赋值给一个同类型的变量:

Student 

只有通过wx变量指向这个对象,就可以反复的使用了:

wx

延伸阅读

当面试官面试你时,提问谈谈你对面向对象编程的理解时该怎样回答?

作业

  1. 观察“一起帮”的:
    1. 注册/登录功能,定义一个User类,包含字段:Name(用户名)、Password(密码)和 邀请人(InvitedBy),和方法:Register()、Login()
    2. 求助版块,定义一个类Problem,包含字段:标题(Title)、正文(Body)、悬赏(Reward)、发布时间(PublishDateTime)和作者(Author),和方法Publish()
    3. 帮帮币版块,定义一个类HelpMoney,表示一行帮帮币交易数据,包含你认为应该包含的字段和方法
  2. 为这些类的字段和方法设置合适的访问修饰符。

每日单词

c070474a1c225013a6550c6d3a7104e8.png

感谢童鞋们的阅读!^_^

我就是:黑律师/包工头/创业狗/老码农……现在还是教书匠的大飞哥。

再次重申这个系列的目标是:

1)通俗易懂。2)实战为主。3)面向就业。

系列内容的完善需要你的反馈!

欢迎点赞和评论,以及加入我们的QQ交流群:326801052。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值