.NET零基础入门06:面向对象入门
一:前言
在本系列课程的第一部分,我们说明为了要选择C#作为你成为程序员的第一门语言:
• 首先,C#是一门非常优秀的面向对象编程的语言;
凡是对编码感兴趣的同学一定听说过“面向对象编程”这个概念,C#就是为此诞生的,它天然是面向对象的。所以,既然“面向对象编程”是当前IT界的主流,我们选择C#就没有偏离主流方向。
本节,我们就要讲讲什么是面向对象,以及面向对象开发中最重要,最应该掌握的概念。
二:什么是面向对象
“面向对象”是当前软件开发的一个主流思想,它有三个主要特征:封装、继承、多态。很多软件开发的教程使用了阿猫阿狗的例子来讲面向对象,其实说明了“面向对象”在某种意义上是很好理解的概念。我们已经在之前的例子中讲过了“类”这个概念,现在我们就来讲讲抽象类,接口。当然,我们不打算用阿猫阿狗的例子(阿猫阿狗都是动物,动物都有吃喝拉撒的习惯……,但是阿猫有阿猫的喵喵叫,阿狗有阿狗的汪汪叫……),我们在这里举一个实际的例子,只不过,需要大家活动思维,主动将概念联系到阿猫阿狗中去。
这个实际的例子是.Net Framework基础类库(以后简称:FCL)中的三个类Stream、FileStream 、MemoryStream ,如下:
public abstract class Stream
{
public abstract void Write(byte[] buffer, int offset, int count);
}public class FileStream : Stream
{
public override void Write(byte[] array, int offset, int count)
{
}
}public class MemoryStream : Stream
{
public override void Write(byte[] buffer, int offset, int count)
{
}
}
这三个是负责byte读写的类,我只拿出了其中一个方法Write。
(TIP:什么是byte?,程序中的数据会以byte的形式存在,我们只要知道,读写内容,如字符串、整数,到内存中,到文件中,实际读写的就是byte就行了)
1:什么是封装?
一句话概括:像上面这样,将代码分类到不同的类中,实际就是封装。
2:什么是继承?
像上面这样,有父类Stream,有两个子类,就叫做继承。如果要讲继承,我们就需要讲解下访问限制符了。
2.1什么是类型的访问限制符?
在C#中,可以为类型,如Stream类,或者类型的成员,如Write方法,添加访问限制符。在C#的世界中,我们将类型和类型的成员所在的可见范围分为如下几类(注意,只讲解最常用的):
a)在整个应用程序内可见
使用public修饰。
b)在当前项目内可见
使用internal修饰。
c)在当前类型内部可见
使用private修饰。该修饰符主要修饰类型的成员。
d)仅在子类中可见
使用protected修饰。该修饰符主要修饰类型的成员。
需要强调的是,类型的默认访问限制符是internal,如果我们不加任何修饰符,.NET编译器就会默认此类型为internal。类型的成员的访问限制符是private。
好了,现在不妨停下来,自己创建一些类型和类型成员,感悟下对访问限制符的理解吧。
2.2什么是抽象类?
如何创建一个类的对象?使用new,如下:
Stream stream = new Stream();
但是这段代码你一定执行不了,因为Stream是抽象类,它被abstract修饰着。既然抽象类new不了?那它有什么意义呢?
a)首先,它可以定义一些抽象的方法abstract method,抽象方法表达了这样一个意思:嗨,子类,你必须实现我这个方法;
b)其次,抽象类可以有一些常规的非abstract的方法,也就是说,我们可以把一些子类中相同的逻辑,放到这个抽象方法中,这样就不需要相同的代码在不同的子类中都去写一遍了。
2.3什么是接口?
如果一个抽象类,只有抽象方法,而没有常规方法,那么我们可以考虑将它抽象为接口(interface)。一个简单的接口的例子如下:
interface IDispose
{
void Dispose();
}
那么,什么时候用接口,什么时候用抽象类呢?这个问题问的很好,但是,别着急,作为初学者,我们是很难把握这个标准的,对于现在的我们来说,我们只要直接.NET的世界中,存在类、抽象类、接口就可以了,尝试一口气全部弄明白,往往属于揠苗助长。
3:什么是多态?
一句话概括之:让子类有自己的行为,就是多态。好吧,其实,多态可不是一句话能概括的,我们来具体看看多态的具体含义及实现手段。
三:多态的具体含义及实现手段
备注:以下内容摘自我所撰写的书《高质量代码编写:改善C#的157个建议》。注意,要完全掌握多态的含义及实现手段,必须通过自己编写代码细细品味才行,请按照本文下面的例子来体会。
override和new使我们的类型体系因为继承而呈现出多态性。多态是一门语言是否是“面向对象语言”的三个重要特性之一。多态要求子类具有与基类方法同名的方法,而override和new的作用就是:
如果子类中的方法前面带有new关键字,则该方法被定义为独立于基类的方法。
如果子类中的方法前面带有override关键字,则子类的对象将调用该方法,而不是调用基类方法。
这两个定义看上去有些抽象,要深刻理解它们之间的区别,我们不妨来看一个继承体系:
public class Shape
{
public virtual void MethodVirtual()
{
Console.WriteLine("base MethodVirtual call");
}public void Method()
{
Console.WriteLine("base Method call");
}
}class Circle : Shape
{
public override void MethodVirtual()
{
Console.WriteLine("circle override MethodVirtual");
}
}class Rectangle : Shape
{
}class Triangle : Shape
{
public new void MethodVirtual()
{
Console.WriteLine("triangle new MethodVirtual");
}public new void Method()
{
Console.WriteLine("triangle new Method");
}}
class Diamond : Shape
{
public void MethodVirtual()
{
Console.WriteLine("Diamond default MethodVirtual");
}public void Method()
{
Console.WriteLine("Diamond default Method");
}
}
查看上面的继承体系,类型Shape是所有子类的基类。
Circle类override了父类的MethodVirtual,所以即使子类转型为了Shape,调用的还是子类的方法:
Shape s = new Circle()
s.MethodVirtual();
s.Method();
输出:
circle override MethodVirtual
base Method call
当然,Circle的第二种用法很好理解。使用子类本身的类型,调用的则全部是子类的方法,如下所示:
Circle circle = new Circle();
circle.MethodVirtual();
circle.Method();
输出也是:
circle override MethodVirtual
base Method call
类型Rectangle没有对基类做任何处理,所以无论子类是否转型为Shape,调用的都是基类Shape的方法。
类型Triangle将基类Shape的virtual方法和非virtual方法都new了一遍。所以第一种用法为:
Shape s = new Triangle()
s.MethodVirtual();
s.Method();
因为子类已经new了父类的方法,故子类方法和基类方法完全没有关系了,只要s被转型为Sharp,则针对s调用的都是父类方法。
第二种用法很好理解,调用的都是子类的方法,如下所示:
Triangle triangel = new Triangle();
triangel.MethodVirtual();
triangel.Method();
输出:
triangle new MethodVirtual
triangle new Method
类型Diamond,包含了两个和基类一模一样的方法,并且没有额外的修饰符。这在编辑器中会提出警示。但是如果选择忽略这些警示,程序一样还是可以运行。它的第一种用法为:
Shape s = new Diamond()
s.MethodVirtual();
s.Method();
编译器会默认new的效果,所以输出和显式new修饰的一样。
输出:
base MethodVirtual call
base Method call
在Diamond的第二种用法中,全部调用的是子类的方法,如下所示:
Diamond diamond = new Diamond();
diamond.MethodVirtual();
diamond.Method();
输出:
Diamond default MethodVirtual
Diamond default Method
我们总结一下以上所有的用法,并给出一个综合示例,读者可以仔细体会每种用法所带来的输出变化:
static void Main(string[] args)
{
TestShape();
TestDerive();
TestDerive2();
}private static void TestShape()
{
Console.WriteLine("TestShape\tStart");
List<Shape> shapes = new List<Shape>();
shapes.Add(new Circle());
shapes.Add(new Rectangle());
shapes.Add(new Triangle());
shapes.Add(new Diamond());
foreach (Shape s in shapes)
{
s.MethodVirtual();
s.Method();
}Console.WriteLine("TestShape\tEnd\n");
}private static void TestDerive()
{
Console.WriteLine("TestDerive\tStart");
Circle circle = new Circle();
Rectangle rectangle = new Rectangle();
Triangle triangel = new Triangle();
Diamond diamond = new Diamond();
circle.MethodVirtual();
circle.Method();
rectangle.MethodVirtual();
rectangle.Method();
triangel.MethodVirtual();
triangel.Method();
diamond.MethodVirtual();
diamond.Method();
Console.WriteLine("TestShape\tEnd\n");
}private static void TestDerive2()
{
Console.WriteLine("TestDerive2\tStart");
Circle circle = new Circle();
PrintShape(circle);
Rectangle rectangle = new Rectangle();
PrintShape(rectangle);
Triangle triangel = new Triangle();
PrintShape(triangel);
Diamond diamond = new Diamond();
PrintShape(diamond);
Console.WriteLine("TestDerive2\tEnd\n");}
static void PrintShape(Shape sharpe)
{
sharpe.MethodVirtual();
sharpe.Method();
}
输出:
TestShape Start
circle override MethodVirtual
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
TestShape End
TestDerive Start
circle override MethodVirtual
base Method call
base MethodVirtual call
base Method call
triangle new MethodVirtual
triangle new Method
Diamond default MethodVirtual
Diamond default Method
TestShape End
TestDerive2 Start
circle override MethodVirtual
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
base MethodVirtual call
base Method call
TestDerive2 End
四:某个同学的比较差的记录
视频部分非公开,请联系最课程(www.zuikc.com)。
微信扫一扫,关注最课程(www.zuikc.com),获取更多我的文章,获取软件开发每日一练
.NET零基础入门06:面向对象入门的更多相关文章
- 零基础学习C语言入门必备知识
今天跟大家一起从零学C语言: 1. C语言简介 1.1 C语言发展史 C语言是一种广泛使用的面向过程的计算机程序设计语言,既适合于系统程序设计,又适合于应用程序设计.C语言的发展历程大致如图1-1所示 ...
- 零基础学习STM32之入门学习路线
可以说就目前的市场需求来看,stm32在单片机领域已经拥有了绝对的地位,51什么的已经过时了也只能拿来打基础了,最后依然会转到stm32来,也正是因为这样stm32的学习者越来越多,其中不难发现绝大部 ...
- 零基础学python之入门和列表数据(附详细的代码解释和执行结果截图)
Python学习笔记 1 快速入门 下载安装好Python之后,在开始找到 双击打开一个窗口,这是一个shell界面编辑窗口,点击左上角的file——new file新建一个窗口,这里可以输入完整的代 ...
- Scala实战高手****第7课:零基础实战Scala面向对象编程及Spark源码解析
/** * 如果有这些语法的支持,我们说这门语言是支持面向对象的语言 * 其实真正面向对象的精髓是不是封装.继承.多态呢? * --->肯定不是,封装.继承.多态,只不过是支撑面向对象的 * 一 ...
- 【JAVA基础】06 面向对象
1. 面向对象思想概述 面向过程思想概述 第一步 第二步 面向对象思想概述 找对象(第一步,第二步) 举例 买煎饼果子 洗衣服 面向对象思想特点 是一种更符合我们思想习惯的思想 可以将复杂的事情简单化 ...
- javascript入门视频第一天 小案例制作 零基础开始学习javascript
JavaScript 是我们网页设计师必备的技能之一.我们主要用javascript来写的是网页特效.我们从零基础开始学习javascript入门. 但是,好的同学刚开始不知道怎么学习,接触js,因此 ...
- 序言 - PHP零基础快速入门
我为什么要写<PHP零基础快速入门>? 原因: PHP 真心简单,适合零基础的人快速入门掌握,身边的人学习一两周上手开发的比比皆是: 市面上的文章或书籍对初学者并不友好,多半枯燥乏味,我相 ...
- 081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字
081 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 06 new关键字 本文知识点:new关键字 说明:因为时间紧张,本人写博客过程中只是 ...
- 056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用
056 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 03 一维数组的应用 本文知识点:数组的实际应用 程序开发中如何应用数组? 程序代码及其运行结果: 不同数据类 ...
- 055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念
055 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 02 数组的概念 本文知识点:数组的概念 数组的声明创建.初始化 在学习数组的声明创建.初始化前,我们可以和之 ...
随机推荐
- TypeScript的HTML5游戏
wildfirecode 自动化的基于TypeScript的HTML5游戏开发 自动化的开发流程 在HTML5游戏开发或者说在Web客户端开发中,对项目代码进行修改之后,一般来说,需要手动刷新浏览器来 ...
- jquery下载,实时更新jquery1.2到最新3.3.1所有版本下载
描述:jquery下载,实时更新jquery1.2到最新3.3.1所有版本下载 https://www.jb51.net/zt/jquerydown.htm (注意:jquery-2.0以上版本不再支 ...
- python常用库安装网址
python常用库安装网址如下: http://pypi.python.org/pypi
- DML和DQL 总结
一:MySql的存储引擎 问题的引入: 由于不同用户对数据的容量,访问速度,数据安全性有着不同的要求. 为了满足不同用户的需求,mysql数据库采用多种存储引擎来进行数据的存储! 1.1:查询mysq ...
- maven配置文件中modules的作用
modules 从字面意思来说,module就是模块,而pom.xml中的modules也正是这个意思,用来管理同个项目中的各个模块:如果maven用的比较简单,或者说项目的模块在pom.xml没进行 ...
- webshpere 节点&环境分析
场景名称:LotusConnections: 场景下有一个节点:feb02Node1 节点下有一个应用服务器 LotusConnections server.
- Xamarin-Android_BaseAdapter 简单的复用
Xamarin-Android_BaseAdapter 简单的复用 缘由: 本人是一枚 小菜 初学Xamarin-Android 正在学习ListView 控件 发现这个控件的自定义布局 用的那叫一 ...
- [TC11326]ImpossibleGame
[TC11326]ImpossibleGame 题目大意: 一类字符串仅由'A','B','C','D'四种字母组成.对于这样的一个字符串\(S\),可以用以下两种方式之一修改这个字符串: 交换\(S ...
- hdu 4612 边双联通 ***
题意:有N 个点,M条边,加一条边,求割边最少.(有重边) 链接:点我 先求双连通分量,缩点形成一个生成树,然后求这个的直径,割边-直径即是答案 #pragma comment(linker, &qu ...
- 【转载】gdi+ 内存泄漏
[转载]http://issf.blog.163.com/blog/static/1941290822009111894413472/ 最近用GDI+实现了几个自定义控件,但是发现存在内存泄露问题 B ...