前言

上一篇读书笔记,很多小伙伴说这本书很不错,所以趁着国庆假期,继续我的读书之旅,来跟随书中作者一起温习并掌握第二章的内容吧。

一.理解泛型

1.为什么要使用泛型?-----通过使用泛型,可以极大地提高代码的重用度,同时还可以获得强类型的支持,提升了应用程序的性能,避免了隐式的装箱、拆箱,以及运行时的类型转换错误。

2.为什么要有泛型? -----以简单的数组排序为例,第一次我们可能会要求对int型数组进行排序,然后我们很快的写出了答案,

第二次,又要求我们对byte[]数组进行排序,这时候我们可能会思考下,是不是要优化我们的设计思想,但是还不至于修改,我们还是快速的将int[]数组的排序代码进行了复制,将方法签名改为byte[].

第三次,又要求我们对char[]数组进行排序,这个时候我们就不得不停下来思考了,以上两种需求,除了方法签名不一样以为,其他的都一模一样。所以我们引进了泛型的概念,将int[]、byte[]、char[]使用T[]来表示,T代表type,指代任何类型。所以我们又得到了泛型类的概念。

public class SortHelper<T> {
public void BubbleSort(T[] array){
// 方法实现体
}
}

这样,当我们需要对int[]进行排序时,我们可以这样声明:

SortHelper<int> sorter = new SortHelper<int>();
int[] array = { 8, 1, 4, 7, 3 };
sorter.BubbleSort(array);

当我们需要对char[]进行排序时,我们就能这样声明:

SortHelper<char> sorter = new SortHelper<char>();
char [] array = { 8, 1, 4, 7, 3 };
sorter.BubbleSort(array);

再也不用重复的对代码进行复制,然后修改方法签名了。

结论:通过使用泛型,极大的减少了重复代码,使程序更加清爽。泛型类可以让我们在需要时传入任何类型,在.net中,我们称作类型参数。

3.类型参数约束

我们定义了一个Book类,对它实现排序,该怎么实现呢?假设该类包含两个字段,一个int类型的单价price,一个string类型的title标题。

Book[] bookArray = new Book[2];
Book book1 = new Book(30, "HTML5解析");
Book book2 = new Book(21, "JavaScript实战");
bookArray[0] = book1;
bookArray[1] = book2;
SortHelper<Book> sorter = new SortHelper<Book>();
sorter.BubbleSort(bookArray);
foreach (Book b in bookArray) {
Console.WriteLine("Price:{0}", b.Price);
Console.WriteLine("Title:{0}\n", b.Title);
}

那么到底该怎么进行比较大小呢? 是以价格为准呢,还是以书名的字母顺序呢?都不好说,所以这个时候就需要定义一个比较规则了,那么在.net中,实现比较的基本方法是实现IComparable接口。此接口有泛型和非泛型两个。

public class Book :IComparable {
// CODE:上面的实现略
public int CompareTo(object obj) {
Book book2 = (Book)obj;
returnthis.Price.CompareTo(book2.Price);
}
}

这里我们以price为准来进行排序,可以看到CompareTo()方法参数接受了一个object类型的参数,我们却违背了Liskov替换原则。原则要求方法内部不应该对方法所接受的参数进行向下的强制转换。我们都知道,在C#中,object是一切类型的基类。book类继承自Object类,所以我们在将object转换为book进行价格比较时,就称作向下的强制转换.

泛型类,所接受的T类型参数必须能够进行比较--即实现IComparable接口,所以我们可以这样定义:

public class SortHelper<T> where T:IComparable {
// CODE:实现略
}

4.泛型方法

既然有了泛型类,我们就引入了泛型方法的概念,泛型方法的引入主要是为了解决,我们在声明泛型类时,避免因为调用某一个方法不得不将类型参数T传给某个类,使得那些不需要调用该方法的情况下,创建一个类实例也需要传递类型参数的情况。

如下:SpeedSort()就是一个泛型方法

public class SortHelper
{
public void SpeedSort<T>(T[] Array) where T:IComparable
{ }
}

二.泛型和集合类型

1.避免隐式的装箱拆箱

典型的非泛型集合ArrayList,它包容了任何类型, 所以它接受的参数为所有类型的基类Object, 当我们需要获取到一个int[],需要循环遍历ArrayList,并将它一一添加到我们所声明的数组集合中去,由于object是一个引用类型,而int是一个值类型,这样在得到这么一个包含int类型的ArrayList数组时,我们就需要不断的进行装箱、拆箱的操作,这对.net来说是相对耗时的。

通过使用泛型,由于集合中的元素类型在编译时就已确定,避免了装箱和拆箱的操作,很显著的提高集合类型的性能。 在.NET中,与ArrayList作用等同的泛型类型是 List.

2.编译时的类型安全

由于使用泛型,集合中的元素在编译时就已确定,所以当我们想将一个int类型的数值转换为string时,编译器会直接告诉我们编译错误,这种在编译时就检查出的错误,叫做编译时错误,与之相对的,就是我们的运行时错误,即当使用ArrayList时,因为它所接受的参数是object基类,编译器视为将一个int类型的数值转换为string时是正常的,只有运行时才检查出错误。

三.小结

本章学习了为什么需要泛型(避免重复代码)以及如何使用类型参数约束和泛型方法,并且比较了泛型集合List和非泛型集合ArrayList的对比,熟悉并了解了泛型集合的优势和应用。

很开心,又跟随作者学习了第二章泛型的概念,上一篇读书笔记中,很多小伙伴给我留言了,说了很多鼓励的话,很感谢,能和大家一起进步学习,其中有一位小伙伴提到的方法我觉得很棒,就是大量阅读开源源码,确实,我在园子里看到很多对底层原理理解很透彻的大佬们,每每讲解一个知识点时,总是会教我们去跟踪源码,即理解它的底层实现逻辑是啥,这样更能加深我们对知识点的理解和巩固。

我也是在学习中,希望自己在今后的学习和工作中,能掌握这种技巧,帮助自己更好的理解并熟悉它的原理。

【记】《.net之美》之读书笔记(二) C#中的泛型的更多相关文章

  1. 《你必须知道的.NET》读书笔记二:小OO有大原则

    此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.单一职责原则 (1)核心思想:一个类最好只做一件事,只有一个引起它变化的原因 (2)常用模式:Fa ...

  2. spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Pr ...

  3. ES6读书笔记(二)

    前言 前段时间整理了ES6的读书笔记:<ES6读书笔记(一)>,现在为第二篇,本篇内容包括: 一.数组扩展 二.对象扩展 三.函数扩展 四.Set和Map数据结构 五.Reflect 本文 ...

  4. spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...

  5. Mastering Web Application Development with AngularJS 读书笔记(二)

    第一章笔记 (二) 一.scopes的层级和事件系统(the eventing system) 在层级中管理的scopes可以被用做事件总线.AngularJS 允许我们去传播已经命名的事件用一种有效 ...

  6. Servlet和JSP读书笔记(二)

    一. GenericServlet 1. 前面写的 Servlet和JSP学习笔记(一) 中的实例都是通过实现Servlet接口编写的,这样存在的问题就是:你必须实现Servlet中的所有方法,而不管 ...

  7. how tomcat works 读书笔记(二)----------一个简单的servlet容器

    app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...

  8. java读书笔记二

    这是我的一些读书笔记: 我研究了一下面向对象: 面向对象符合人类看待事物的一般规律,对象的方法的实现细节是包装的,只有对象方法的实现者了解细节 我觉得面向过程是由过程.步骤.函数组成,过程是核心,面向 ...

  9. 《JavaScript 高级程序设计》读书笔记二 使用JavaScript

    一   <script>元素 a.四个属性: async:立即异步加载外部脚本: defer:延迟到文档完全被解析再加载外部脚本: src:外部脚本路径: type:脚本语言的内容类型: ...

随机推荐

  1. 用LR录制终于可以在我的电脑上顺利弹出IE了

    之前在我的电脑上各种折腾,由于是win764bit+IE11,安装了LR11连最基本的录制都没能搞定.google之后各种的尝试,也没能解决问题.狠下心来把IE11换成了IE8,终于可以勉强使用了,没 ...

  2. 20190928-02使用Redis客户端Jedis连接Redis,以及用Java代码操作Redis 000 030

    启动redis package com.yujie.jedis; import java.util.HashMap; import java.util.Map; import java.util.Se ...

  3. 转载:把你的精力专注在java,jvm原理,spring原理,mysql锁,事务,多线程,大并发,分布式架构,微服务,以及相关的项目管理等等,这样你的核心竞争力才会越来越高

    https://developer.51cto.com/art/202001/608984.htm 把你的精力专注在java,jvm原理,spring原理,mysql锁,事务,多线程,大并发,分布式架 ...

  4. IDEA中配置Tomcat中的Artifact

    IDEA中配置Tomcat中的Artifact 我在配置Tomcat时,要设置deployment中的Artifact时,却总是无法显示出当前项目的war包,针对这个问题,如下图展示, 当我点击Art ...

  5. Redis哨兵模式(sentinel)部署

    1 主机环境 我这里使用的操作系统是centos 6.5,安装在vmware上,共三台. 主机名 IP 操作系统 用户名 安装目录 node1 192.168.1.101 centos 6.5 wxy ...

  6. JVM运行时数据区--Java虚拟机栈

    虚拟机栈的背景 由于跨平台性的设计,java的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 根据栈设计的优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样 ...

  7. Linux实战(10):ssh密码被拒绝

    网上的操作都试过了,可还是不行,最终通过重装ssh服务解决. 参考资料:https://blog.csdn.net/VicdorLin/article/details/90727826 https:/ ...

  8. Shell编程(4)

    shell函数 shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数.给这段代码起个名字称为函数名,后续可以直接调用该段代码. 格式 func() { #指定函数名 co ...

  9. vue自适应布局的n中方法

    在index.html中 head标签中 <script> //通过window.screen.width获取屏幕的宽度 var offWidth = window.screen.widt ...

  10. hystrix文档翻译之配置

    Hystrix使用Archaius作为配置的默认实现,下面介绍的是HystrixPropertiesStrategy的默认实现,你也可以通过插件方式重新实现. 每一个配置有四个级别: 全局默认 当下面 ...