首页 > 代码库 > 泛型拾遗一下
泛型拾遗一下
一、为什么想到再学习一下泛型?
最近需要写几个这样的报表,怕领导看到我做一个隐藏哈,你们懂的~哈哈~
然后基本的类型返回都是一样的格式就是生成一个json喽,有个什么父亲节点这种,具体那个什么节点类型的我就不说了,当然这个插件还没有改造完成,等等有时间的时候我准备在完善一下这个插件。这个当时把大神东西拷下来的时候是有点问题,我稍微修复了一下,准备等等忙完这段时间再好好扩展一下。接下来就说我们要关注的重点泛型,因为报表的类型都基本一样,所以返回的类型也基本相同,无谓就是多创建了几个实体类然后在前端展示一下喽,当然我作为这么懒的程序员怎么可以老是粘贴代码尼~这是不应该的,我脑袋灵光一闪瞬间想到了泛型,用泛型方法传入不同的类型参数,这个地方我提一下我那个跟节点是没有父节点的,所以我返回了一个List<object>,当然想到归想到但是我怎么也想不起来怎么C#泛型方法怎么声明了,顿时一脸的悲剧,当然查一下资料一切都不是问题喽,但是我后来又想了一下这地方其实不需要泛型也是可以的,我后面还做了个泛型约束,真是画蛇添足,能这么做都是因为对其概念没有真正理解了,无奈。我最近学习核心卷也正好看到泛型,既然如此那我就把java泛型和C#泛型对比的来学习下,当然我没有挑动这2者矛盾的意思~废话不多说开始搞起来~
二、泛型有哪些好处?
使用ArrayList的时候可以插入任意的数据,不管什么类型放入ArrayList中都会被装箱成object类型,当我们要比较一组ArrayList中的大小的时候,其中放入了一个string类型这样就会照成System.InvalidOperationException异常,泛型的数据是统一的,类型是安全的,一组数据是int就都是int类型,另外泛型比起ArrayList减少了装箱和拆箱操作,节省了时间,省时间的就是性能好~哇哈哈~这么好当然使用泛型喽~对对忘记重要的一点也就是我上面场景用的,代码复用性增强,这样的图文并茂,相信大家一定会明白泛型的好处~
三、C#泛型用法
泛型类的声明:再类名后面放一组<>括号,要是有多个类型就用,隔开,这个是类型参数,其实我们也可以这样理解,就是说泛型类不是类而是类的模板,在使用泛型类的时候我们必须创建类型的实例。如下样子:
MyCompare<int> a =new MyCompare<int>();
MyCompare<string> b= new MyCompare<string>();
C#里面提供了5种泛型:类,结构,接口,委托和方法,这就使我们程序使用起来更加灵活方便。
上面这个泛型模板里面存在的方法就是错误的,错误的原因在于没有约束,传入的对象就被看作object,我们怎么样来避免这种错误,当然C#是提供了这种机制的,那就是约束,只有符合约束的类型才能构造类型。
约束使用where来进行声明,where TypeParam:constraint,constraint,..这是一个简单声明泛型约束的模板,我来解释一下具体于含义TypeParam这个表示类型的参数,constraint这个表示约束列表,也就声明类型参数可以是那种类型,下面我简单写了一个例子
当然约束类型也分多种,
where T:class 限制类型参数T必须是引用类型;
where T:struct 限制类型参数必须是值类型;
where T:new() 限制参数必须带有一个无参数的构造函数
where T:接口 限制参数必须是实现了该接口的类型或者接口
说完泛型约束接下来说一下泛型的方法,泛型方法的定义如下所示,具体的我不做过多介绍,和上面泛型类基本差不多
public static bool MyWay<T, S>(T t1, S s2)
{
return t1.Equals(s2);
}
接下来说下泛型方法的调用,第一种就属于比较常规的调用,第二种就是泛型方法的一个特点就是类型推断,就是编译器再调用泛型方法的时候推断要使用的类型简化我们的写法。
1).static void Main(string[] args)
{
Console.WriteLine(MyClass.MyWay<int, int>(4, 4));
Console.ReadKey();
}
2).static void Main(string[] args)
{
Console.WriteLine(MyClass.MyWay(4, 4));
Console.ReadKey();
}
说到这里我还想说一个很有意思的东西,下面这个是错误的,再有泛型约束的时候也不能进行运算符操作,是不是瞬间懵逼了,没错我也是懵逼了好一会,这确实也是C#泛型的一个严重限制,说到这个需要明白一下C#是如何处理基元类型的,说到基元类型又是一脸懵逼,这里做一下解释,编译器直接支持的数据类型就是基元类型,基元类型就是直接映射到FCL中存在的类型,比如 int直接映射到System.Int32类型,明白了什么是基元类型,那我们就来说一下这个struct约束泛型的方法为什么不能比较值,假设下面的方法是成立的,接下来我调用下面的方法MyWay<byte,byte>(100,200),这个方法最后在进行类型转化的时候就会出现错误,我相信说到这里大家就应该比较明确了,那我在最后总结一下,因为在编译的时候不能确实泛型的类型,定义为了struct就可能是所有的值类型,所以不能处理类型任何类型的数据类型算法~~
public static byte MyWay<T, S>(T t1, S s2) where T:struct where S:struct
{
return t1+s2;
}
C#泛型先简单的介绍到这里,下一篇我在详细写一下泛型委托和更高级的逆变和协变,这个我还没很了解了。。期待与你共成长哈哈~~
四、Java泛型用法
好处就不多说了,当然和C#基本一致的,接下来我们开始搞一搞java的用法。
还是泛型类声明 public class TestGenercDemo<T> {} 二者基本一样
多个泛型的声明也是在<>中加入,分割开 如 public class TestGenercDemo<T,U> {}
这里注意一点(这个可能是比较针对于我,因为要学习java,所以我要了解其中的各种规范方便以后更好融入团队中,形成比较好的代码风格),在java库中,变量E表示集合元素的类型,K和V表示键值对,T表示任意类型;
另外使用就没必要说了这个就是一个new的问题喽,再来属性封装读取值,基本就是这样;
接下来说泛型方法
public class TestGenercDemo { public static <T> T[] getMiddle(T[] t) { T[] middle=Arrays.copyOf(t,(int)t.length/2); return middle; } public static <T> T get(T t) { return t; } public static void main(String[] args) { // TODO Auto-generated method stub String[] a={"w","c","a","b"}; String[] b=getMiddle(a); String c=get("c"); int d=get(2); System.out.println(b.length); System.out.println(c); System.out.println(d); } }
以上可以观察出基本也和C#的方法一样,可以自动推断类型,就是声明的方式有所不一样<>和方法名中间是返回类型
接下来说一下泛型变量的约束:
这个之前我们还是来说一下错误案例:
这个错误想必以及难不到大家了,这个也是因为编译之前不知道泛型T的类型,编译器只能默认是object类型,所以只能调用object类下面的方法
写这些可能是在大神面班门弄斧了,,但是我坚信我有一天会成为大神哈哈
类型限定在类,接口和方法中都可以使用,需要注意一下几点
1).不管是类或者接口都需要使用extends
2).可以使用&符号给出多个限定
public static <T extends Number&Comparable<Integer>> boolean compareValue(T t1,T t2) { return t1.equals(t2); }
3).如果限定既有接口也有类,那么类必须只有一个,并且放在首位置
三、结束语
上面的可能说的相对比较基础,接下来将会有下一篇泛型拾遗2,因为我坚信基础好,框架神木的都不是问题,扎实基础
以上如果存在什么错误欢迎大神帮忙指出一下,小弟在此感谢!!另外小弟刚刚搞一个Java群438836709欢迎各种喜欢学习的人进来交流~一起畅谈人生~一起开心的学习~Go!!
泛型拾遗一下