C#类型都派生自System.Object

祖先的优良传统:Object的公共方法

Equals: 对象的同一性而非相等性

GetHashCode:返回对象的值的哈希码

ToString:默认返回类型的完整名称 this.GetType().FullName

GetType:返回从Type派生的一个对象的实例,即对象的元数据信息,此方法为非虚方法,为防止类来重写该方法,隐瞒真实的类型信息,从而破坏类型的安全性

GetHashCode有什么用?

判断对象是否相等的快速检查。Equals方法和GetHashCode方法的重写应该同时存在。如果Equals方法返回的结果是true,那么GetHashCode方法返回的结果应该相同。如果GetHashCode方法返回的结果相同,那么Equals方法返回的结果不一定是true。

public class Student
{
public string FirstName { get; private set; }
public string LastName { get; private set; } public Student(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
} public override bool Equals(object obj)
{
Console.WriteLine("Called Equals");
if (obj == null || this.GetType() != obj.GetType())
return false;
return this.FirstName == ((Student)obj).FirstName
&& this.LastName == ((Student)obj).LastName;
} public override int GetHashCode()
{
Console.WriteLine("Called GetHashCode");
return this.FirstName.GetHashCode();
}
} static void Main(string[] args)
{ Student student1 = new Student("Jun", "Lei");
Student student2 = new Student("Kaifu", "Li");
Student student3 = new Student("Jun", "Zhu"); //第一次调用
var dic = new Dictionary<Student, object>();
dic[student1] = new object();
Console.WriteLine("==================");
Console.WriteLine(dic.ContainsKey(student2));
Console.WriteLine("==================");
Console.WriteLine(dic.ContainsKey(student3));
//第二次调用
Student student4 = new Student("Jun", "Lei");
var dic1 = new Dictionary<Student, object>();
dic1[student4] = new object();
Console.WriteLine("==================");
Console.WriteLine(dic1.ContainsKey(new Student("Jun", "Lei"))); } 

说明:在上面的Student类中我们重写了Equals和GetHashCode这两个基类的方法,在针对Dictionary这种散列值的key值判断的时候系统默认先调用GetHashCode判断,然后再掉用Equals方法判断,微软约定如果两个对象的哈希码不一样,则两个对象肯定不相等。所以在判断对象相等时系统默认先调用此方法做最简单的判断。举个例子:要比较两个人是不是兄弟,第一眼肯定是看两个人的性别是否相同(GetHashCode),如果性别都不一样,肯定不是兄弟,然后再判断长相,血型,DNA等的相似性(Equals)。

上述代码第一次调用时,输出结果如下:

在Student中我们重写了GetHashCode方法,让它获取FirstName的哈希值,这也就是意味着如果两个Student的FirstName相同的话这两个对象判断相等的时候系统默认返回的哈希值将是一样的,我们可以看到student1和student2 对象中的每一个字段都不相同,所以根绝GethashCode直接判断不相等,所以系统直接返回false,没有调用Equals方法判断。而Student3对象和Student1对象的FirstName是一样的,所以感觉哈希值已经判断不出来了,所以又调用了一次Equals方法进行深入判断,由于LastName不一样,所以返回结果为false。由上述代码我们可以得出结论,系统判断对象相等性的时候先调用GetHashCode判断,如果对象的哈希值一样,再根据Equals的实现判断,否则直接返回false。

如果我们把GetHashCode的实现注释掉,直接用系统的方法的话,返回结果如下:

因为Student1和Student3是两个不同的对象,所以哈希码肯定不一样,所以就不会调用Equals方法再继续进行判断了

基元类型

基元类型:编译器直接支持的数据类型称之为基元类型,它直接映射到Framework类库(FCL)中存在的类型,比如 int  —> System.Int32

int a = 0;   //最方便的语法
System.Int32 a = 0 ; //方便的语法
int a = new int() ; //不方便的语法
System.Int32 a = new System.Int32(); //最不方便的语法  

问题1:以上四行代码生成的IL代码完全一样吗 ?(完全一样,可以根据生成的IL代码判断)

问题2:在32位操作系统上运行时,int代表32位整数,在64位操作系统上运行时,int代表64位整数这种说法正确吗?(完全错误,不管在什么操作系统上都是代表32位整数)

下面是C#中的基元类型和FCL中类型的对应关系

引用类型:

a.内存分配到托管堆上

b.托管堆上分配的每个对象都会包含:对象本身的值,类型对象指针,同步索引块

c.对象传递的是内存的引用地址

d.没有被使用的情况下,会被垃圾回收

eg:类都是引用类型,string

值类型:

a.内存分配到它声明的地方

b.分配的内存只包含本身的值

c.传递的是值本身

d.不会被垃圾回收

e.所有值类型都是隐式封闭的 sealed(防止一个值类型用作其他类型的基类型)

f.所有值类型都是 System.ValueType 的后代

eg: int , decimal , double, struct

关于引用类型的类型对象指针和同步索引块,下面的博客将的很详细,不过我还是没有完全理解,所有在此不做详细解释。

类型对象指针和同步索引块:http://www.cnblogs.com/yuyijq/archive/2009/03/13/1410071.html

Code1:

string str = "ab";
string str1 = str;
str = "abc";
str1 = ?  

上面代码你一眼看过去肯定以为str1会输出 abc ,因为是引用类型啊,我们改了引用的值之后它也会跟这边,因为引用的是同一片内存地址呀。如果真这样认为那我只能说太年轻了。

输出依然是 ab,具体原因如下:

String的不可变性:string 对象是只读的,一旦创建了该对象,就不能修改该对象的值。看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因,如果经常改变string的值则应该使用StringBuilder而不使用string

StringBulider: 通过分配一个缓存(工作区)来解决这些问题,在工作区中对字符串应用StringBuilder类的相关方法。包括添加,删除,移除,插入和替换字符等等。执行完之后,将调用ToString方法把工作区中的内容转换为一个字符串,方便赋给一个字符串变量。这样StringBuilder会提升一些性能。

Code2:

string  str1 = "string" ;
string str2 = "string" ;
Console .WriteLine(string .ReferenceEquals(str1, str2));  

我们虽然初始化了两个字符串对象,看起来是分配了两个内存地址,但其实不是的,CLR对此作了优化,具体解释如下:

当CLR初始化的时,会创建一个内部的散列表,Key为字符串,Value为指向托管堆中字符串对象的引用。当构造str1时,先会去散列表中查询是否存在”string”字符串,如果不存在那么会在托管堆中构造一个新的String对象,然后将”string”字符串和指向该对象的引用添加到散列表中,当构造str2时,由于散列表中存在 Key为”string”的引用,于是将Value值赋值给str2,那么str1和str2引用的是同一个String对象

注意:string 是不可变的引用的类型,CLR在运行时进行了优化,相同的string实际上在内存中只存在一份

Code3:

 public struct Point
{
public int x = 0;
public int y = 0;
}  

上面的代码是编译不通过的,原因是:

值类型不支持无参数构造函数,当一个值类型没有提供任何有参构造函数的时候,是不能够对字段在定义中进行初始化。

为什么微软不支持值类型的无参构造函数?

防止开发人员不去显式调用构造函数,对于值类型的变量来说,如果不去显式调用构造函数的话,编译器不会在生成的IL代码中添加调用构造函数的代码的。

C# 类型基础(上)的更多相关文章

  1. 《C#从现象到本质》读书笔记(二)第2章 C#类型基础(上)

    <C#从现象到本质>读书笔记第二篇 第2章 C#类型基础(上) 类型指的是集合{类,结构,接口,枚举,委托}中的任意一个成员.任何拥有某类型的值(value)称为某类型的一个实例(inst ...

  2. C#学习笔记——面向对象、面向组件以及类型基础

    C#学习笔记——面向对象.面向组件以及类型基础 目录 一 面向对象与面向组件 二 基元类型与 new 操作 三 值类型与引用类型 四 类型转换 五 相等性与同一性 六 对象哈希码 一 面向对象与面向组 ...

  3. 在Livemedia的基础上开发自己的流媒体客户端

    一.背景 二.Livemedia框架介绍 1.总体框架 2.客户端框架 2.1 客户端openRTSP流程 2.2增加一种新的媒体 2.2.1增加媒体的format 2.2.2 新媒体需要考虑的问题 ...

  4. 使用mysqlbinlog工具的基础上及时恢复数据的位置或点

    使用mysqlbinlog工具的基础上及时恢复的位置或点 MySQL备份一般采取完全备份的形式加日志备份.让我们运行一个完整备份,每天.每小时运行二进制日志备份. 这样在MySQL Server故障后 ...

  5. [CLR via C#]4. 类型基础及类型、对象、栈和堆运行时的相互联系

    原文:[CLR via C#]4. 类型基础及类型.对象.栈和堆运行时的相互联系 CLR要求所有类型最终都要从System.Object派生.也就是所,下面的两个定义是完全相同的, //隐式派生自Sy ...

  6. UNIX基础上

    时光飞逝,转眼已经毕业快2年了,觉得自己学的东西多却不精.对此深深的思考一下,觉得有必要连载unix环境编程文章,以此激励自己学习.在此立贴为证,2天一篇博客从零开始阐述unix的环境编程. 参考书籍 ...

  7. 如何基于Winform开发框架或混合框架基础上进行项目的快速开发

    在开发项目的时候,我们为了提高速度和质量,往往不是白手起家,需要基于一定的基础上进行项目的快速开发,这样可以利用整个框架的生态基础模块,以及成熟统一的开发方式,可以极大提高我们开发的效率.本篇随笔就是 ...

  8. 《C#从现象到本质》读书笔记(三)第3章C#类型基础(下)

    <C#从现象到本质>读书笔记第3章C#类型基础(下) 常量以关键字const修饰.C#支持静态字段(类型字段)和实例字段. 无参属性的get方法不支持参数,而有参属性的get方法支持传入一 ...

  9. [No0000B9]C# 类型基础 值类型和引用类型 及其 对象复制 浅度复制vs深度复制 深入研究2

    接上[No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1 对象复制 有的时候,创建一个对象可能会非常耗时,比如对象需要从远程数据库中获取数据来填充,又或者创建对象需要读取硬 ...

  10. [No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1

    引言 本文之初的目的是讲述设计模式中的 Prototype(原型)模式,但是如果想较清楚地弄明白这个模式,需要了解对象克隆(Object Clone),Clone其实也就是对象复制.复制又分为了浅度复 ...

随机推荐

  1. 数据结构-二叉树(应用篇)-之二叉搜索树 C和C++的实现

    一.概念 二叉搜索树(Binary Sort Tree/Binary Search Tree...),是二叉树的一种特殊扩展.也是一种动态查找表. 在二叉搜索树中,左子树上所有节点的均小于根节点,右子 ...

  2. 了解adb的基本原理

    ADB就是Android调试桥的意思,很形象.但不知道是windows本身的原因还是windows乱七八糟软件太多,用USB调试手机时,经常连不上ADB,或者就出现offline,导致费时费力,焦头烂 ...

  3. 【jQuery】(7)---jQueryAjax同步异步区别

    jQueryAjax同步异步 今天在项目开发过程中,要实现这么一个功能 <!-- 当我点击就业的时候,触发onclick时间,check()方法里通过ajax请求返回数据, 如果该用户已经毕业可 ...

  4. 使用神经网络来拟合函数y = x^3 +b

    我们使用一个三层的小网络来,模拟函数y = x^3+b函数 import tensorflow as tf import numpy as np import matplotlib.pyplot as ...

  5. Java异常抛出及try,catch应用实例

    class lanpingException extends Exception { lanpingException(String msg) { super(msg); } } class maoy ...

  6. THUSC2016 游记

    浑浑噩噩地就出发了,只记得可以翘课,不知道自己要干什么去. Day 0    5点起床,到潮汕机场坐飞机.第一次坐飞机非常不爽起飞和降落时的加速度……终于还是转转地铁.动车在下午4点左右抵达目的地,西 ...

  7. return机制

    C/C++中,函数内部的一切变量(函数内部局部变量,形参 )都是在其被调用时才被分配内存单元.子函数运行结束时,所有局部变量的内存单元会被系统释放.形参和函数内部的局部变量的生命期和作用域都是在函数内 ...

  8. POI实现大数据EXCLE导入导出,解决内存溢出问题

    使用POI能够导出大数据保证内存不溢出的一个重要原因是SXSSFWorkbook生成的EXCEL为2007版本,修改EXCEL2007文件后缀为ZIP打开可以看到,每一个Sheet都是一个xml文件, ...

  9. eclipse中git提交冲突问题

    1.工程->Team->同步:  2.从远程pull至本地,就会出现如下内容:  3.使用Merge Tool,执行第二项 使用HEAD合并后的效果: 4.再手动修改 4.修改后的文件需要 ...

  10. 10个html5增加的重要新特性和内容

    文章开篇之前我们先了解一下什么是html5,百度上是这样定义html5的:万维网的核心语言.标准通用标记语言下的一个应用超文本标记语言(HTML)的第五次重大修改. 其实说白了html5也就是人为定义 ...