0°

谈谈泛型

内容预览:
  • “  四、使用类型通配符 List不是List的父类型,List不是List的父类...~
  • 既然static方法不认识泛型,那我们看一下static变量是否认识泛型: 这证...~
  • “  七、泛型约束 可以对泛型参数作约束,本来觉得应该有规律,后来...~

始发于微信公众号: 程序员小乐

分享编程技能、互联网技术、生活感悟、打造干货分享平台,将总结的技术、心得、经验分享给大家,这里不只限于技术!还有职场心得、生活感悟、以及面经点击上方 “杨守乐” ,选择“置顶公众号”,第一时间送达!



文章目录

  • 泛型初探

  • getClass()相同

  • 尽量使用精确的类型定义泛型

  • 使用类型通配符

  • 泛型方法

  • 静态资源不认识泛型

  • 泛型约束

谈谈泛型

 一、泛型初探


在泛型(Generic type或Generics)出现之前,是这么写代码的:

public static void main(String[] args)
{
   List list = new ArrayList();
   list.add("123");
   list.add("456");
   System.out.println((String)list.get(0));
}

当然这是完全允许的,因为List里面的内容是Object类型的,自然任何对象类型都可以放入、都可以取出,但是这么写会有两个问题:

1、当一个对象放入集合时,集合不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型变成了Object

2、运行时需要人为地强制转换类型到具体目标,实际的程序绝不会这么简单,一个不小心就会出现java.lang.ClassCastException,即类型转换异常

所以,泛型出现之后,上面的代码就改成了大家都熟知的写法:

public static void main(String[] args)
{
   List<String> list = new ArrayList<String>();
   list.add("123");
   list.add("456");
   System.out.println(list.get(0));
}

这就是泛型。泛型是对Java语言类型系统的一种扩展,有点类似于C++的模板,可以把类型参数看作是使用参数化类型时指定的类型的一个占位符。引入泛型,是对Java语言一个较大的功能增强,带来了很多的好处:

1、类型安全。类型错误现在在编译期间就被捕获到了,而不是在运行时当作java.lang.ClassCastException展示出来,将类型检查从运行时挪到编译时有助于开发者更容易找到错误,并提高程序的可靠性

2、消除了代码中许多的强制类型转换,增强了代码的可读性

3、为较大的优化带来了可能

 二、getClass()相同


看一段代码:

public static void main(String[] args)
{
   List<String> stringList = new ArrayList<String>();
   List<Integer> integerList = new ArrayList<Integer>();
   System.out.println(stringList.getClass() == integerList.getClass());
}

运行结果为:

true

这意味着,泛型是什么并不会对一个对象实例是什么类型的造成影响,所以,通过改变泛型的方式试图定义不同的重载方法也是不可以的:

 三、尽量使用精确的类型定义泛型


尽量使用精确的类型定义泛型,除非必要,否则不要写一个接口或者父类上去:

public static void main(String[] args)
{
   List<Number> list = new ArrayList<Number>();
   list.add(4);
   list.add(2.2);
   for (Number number : list)
       System.out.println(number);
}

就像这样,list中的是一个Number类型,往里面添加的是Integer与Double,这样导致get出来的元素也都是Number类型的,失去了子类扩展的功能。如果要让子类变为Interger和Double也可以,(Integer)list.get(0)和(Double)list.get(1)强转就可以了,但是这样不就失去了泛型的意义了吗?所以,尽量用精确的类型去定义泛型。

 四、使用类型通配符


List不是List的父类型,List不是List的父类型,试图用以下方式赋值是不允许的:

1 public static void main(String[] args)
2 {
3     List<Number> numberList = new ArrayList<Number>();
4     List<Integer> integerList = new ArrayList<Integer>();
5     numberList = integerList;
6 }

第5行将报错”Type mismatch: cannot convert from Listto List“。有人可能觉得这样很不方便:我在一个方法里面只需要循环检索一个List,也不能利用多态放一个父类型进去,也不能重载,那怎么办呢?针对这个问题,Java给开发者提供了通配符”?”,看一下:

public static void main(String[] args)
{
   List<String>  stringList = new ArrayList<String>();
   List<Integer> integerList = new ArrayList<Integer>();
   printList(stringList);
   printList(integerList);
}
private static void printList(List<?> l)
{
   for (Object o : l)
       System.out.println(o);
}

是类型通配符,表示是任何泛型的父类型,这样List、List这些都可以传递进入printList方法中,注意这里的参数不能写成List,这样就报错了,E未定义。当然也可以不加,不过这样会有警告:如果传递一个List给List,相当于传递一个只承诺将它当作List(原始类型)的方法,这将会破坏使用泛型的类型安全。

再注意一点,使用类型通配符,只能从中检索元素,不能添加元素。

 五、泛型方法



public static void main(String[] args)
{
   System.out.println(ifThenElse(false, "111", "222"));
}
private static <T> T ifThenElse(boolean b, T first, T second)
{
   return b ? first : second;
}

返回结果为:

222

这说明,方法也可以被泛型化,不管定义在其中的类是不是泛型化的。这意味着不用显式告诉编译器,想要T什么值:编译器只知道这些T都必须相同。

 六、静态资源不认识泛型


接上一个话题,如果把去掉,那么:

报错,T未定义。但是如果我们再把static去掉:

这并不会有任何问题。两相对比下,可以看出static方法并不认识泛型,所以我们要加上一个,告诉static方法,后面的T是一个泛型。既然static方法不认识泛型,那我们看一下static变量是否认识泛型:

这证明了,static变量也不认识泛型,其实不仅仅是static方法、static变量,static块也不认识泛型,可以自己试一下。总结起来就是一句话:静态资源不认识泛型。

 七、泛型约束


可以对泛型参数作约束,本来觉得应该有规律,后来发现没有,那就把自己研究的结论发一下,假设有一组类继承关系C继承自B,B继承自A:

1、定义class的时候只能使用extends关键字且不能用通配符”?”

public class TestMain<T extends B>
{
   public static void main(String[] args)
   
{
       new TestMain<C>();
   }
}


正确。TestMain类的泛型只能传B的子类,也就是C。”new TestMain()”、”public class TestMain”、”public class TestMain“都是错误的写法

2、作为方法的参数,泛型可以使用”? extends B”或者”? super B”,前者表示实际类型只可以是B的子类,后者表示实际类型只可以是B的父类,以下两种写法都是正确的:

public static void main(String[] args)
{
   print(new ArrayList<C>());
}
public static void print(List<? extends B> list)
{
}
public static void main(String[] args)
{
   print(new ArrayList<A>());
   print(new ArrayList<Object>());
}
public static void print(List<? super B> list)
{
}

3、作为局部变量的参数,泛型可以使用”? extends B”或者”? super B”,不过前者好像没什么意义,后者表示只可以传以B为父类的对象,所以以下的写法是正确的:

public static void main(String[] args)
{
   List<? super B> list = new ArrayList<B>();
   list.add(new C());
}

不要写”list.add(new A())”,JDK将会认为这是类型不匹配的。

如果您觉得不错,请别忘了转发、分享、点赞让更多的人去学习, 您的举手之劳,就是对小乐最好的支持,非常感谢!

如何您想进技术群和大牛们交流,关注公众号在后台回复 “加群”,或者 “学习” 即可

来自:五月的仓颉

链接:

http://www.cnblogs.com/xrq730/p/4869134.html

著作权归作者所有。本文已获得授权。欢迎大家来投稿。

每日英文


The road ahead is still a long way, you may cry, but must go on, must not stop .Those who can’t lose will never win either.

前面的路还很远,你可能会哭,但是一定要走下去,一定不能停。输不起的人,往往就是赢不了


乐乐有话说


人有两条路要走,一条是必须走的,一条是想走的,但是你只有把必须走的路走得漂亮,才可以走想走的路。无论今天的你正走在哪条路上,从现在开始,勇往直前,做一个精彩的自己,给未来的你看一看!


谈谈泛型


推荐阅读



看完本文有收获?请转发分享给更多人
关注「杨守乐」,提升技能

以上就是:谈谈泛型 的全部内容。

本站部分内容来源于互联网和用户投稿,如有侵权请联系我们删除,谢谢。
Email:[email protected]


0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论