牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现
不多说,直接上干货!
先来看个泛型概念提出的背景的例子。
GenericDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.ArrayList;
import java.util.Iterator; public class GenericDemo { /**
* @param args
*/
public static void main(String[] args) {
ArrayList al = new ArrayList(); al.add("abc");//public boolean add(Object obj)
al.add("hahah");
al.add();//al.add(new Integer(4)); Iterator it = al.iterator();
while(it.hasNext()){
String str = (String)it.next();//1处
System.out.println(str);
}
}
}
输出
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at zhouls.bigdata.DataFeatureSelection.GenericDemo.main(GenericDemo.java:)
abc
hahah
以上是运行时期出现问题了。
定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型。在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于//1中的错误。因为编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。
在如上的编码过程中,我们发现主要存在两个问题:
1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。
2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。
那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“java.lang.ClassCastException”异常呢?答案就是使用泛型。
再次修改,GenericDemo.java
这就是,将运行时期的问题ClassCastException转到了编译时期。
再次修改,GenericDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.ArrayList;
import java.util.Iterator; public class GenericDemo {
/**
* @param args
*/
public static void main(String[] args) { ArrayList<String> al = new ArrayList<String>(); al.add("abc");//public boolean add(Object obj)
al.add("hahah");
// al.add(4);//al.add(new Integer(4));//1处 Iterator<String> it = al.iterator();
while(it.hasNext()){
String str = it.next();//2处
System.out.println(str);
}
}
}
采用泛型写法后,在//1处想加入一个Integer类型的对象时会出现编译错误,通过List<String>,直接限定了list集合中只能含有String类型的元素,从而在//2处无须进行强制类型转换,因为此时,集合能够记住元素的类型信息,编译器已经能够确认它是String类型了。
结合上面的泛型定义,我们知道在List<String>中,String是类型实参,也就是说,相应的List接口中肯定含有类型形参。且get()方法的返回结果也直接是此形参类型(也就是对应的传入的类型实参)。
什么是泛型?
泛型:jdk1.5出现的安全机制。
我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int型数据,另一个是处理String类型数据,或者其它自定义类型数据,但是我们没有办法,只能分别写多个方法处理每种数据类型,因为方法的参数类型不同。有没有一种办法,在方法中传入通用的数据类型,这样不就可以合并代码了吗?泛型的出现就是专门解决这个问题的。
使用泛型的好处:
好处:
1、将运行时期的问题ClassCastException转到了编译时期。
2、避免了强制转换的麻烦。
<>什么时候用?
当操作的引用数据类型不确定的时候。就使用<>。将要操作的引用数据类型传入即可.
其实<>就是一个用于接收具体引用数据类型的参数范围。
里面是引用类型,要么放类名,要么放接口名,要么放数组名。
在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型 。泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。
运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。
为什么擦除呢?因为为了兼容运行的类加载器。
泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者在强制转换了。
泛型在集合中的应用
我这里仅仅以集合中的TreeSet为例,
更多集合,请见
牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection、集合框架中的Map集合
GenericDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.Iterator;
import java.util.TreeSet; import zhouls.bigdata.DataFeatureSelection.Person;
import zhouls.bigdata.DataFeatureSelection.ComparatorByName; public class GenericDemo { /**
* @param args
*/
public static void main(String[] args) { TreeSet<Person> ts = new TreeSet<Person>(new ComparatorByName());
ts.add(new Person("lisi8",));
ts.add(new Person("lisi3",));
ts.add(new Person("lisi",));
ts.add(new Person("lis0",)); Iterator<Person> it = ts.iterator(); while(it.hasNext()){
Person p = it.next();
System.out.println(p.getName()+":"+p.getAge());
}
} }
因为TreeSet是需要是二叉树,需要进行比较排序。
Person.java
package zhouls.bigdata.DataFeatureSelection; public class Person implements Comparable<Person> { private String name;
private int age; public Person() {
super();
} public Person(String name, int age) {
super();
this.name = name;
this.age = age;
} public int compareTo(Person p){
// Person p = (Person)obj;
int temp = this.age - p.age;
return temp==?this.name.compareTo(p.name):temp;
} @Override
public int hashCode() {
final int prime = ;
int result = ;
result = prime * result + age;
result = prime * result + ((name == null) ? : name.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
} public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} @Override
public String toString() { return "Person:"+getName()+":"+getAge();
}
}
ComparatorByName.java
package zhouls.bigdata.DataFeatureSelection; import java.util.Comparator; import zhouls.bigdata.DataFeatureSelection.Person; public class ComparatorByName implements Comparator<Person> {
public int compare(Person o1, Person o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==0? o1.getAge()-o2.getAge(): temp;
}
}
什么是泛型类?什么时候用泛型类?泛型类?
在jdk1.5后,使用泛型来接收类中要操作的引用数据类型。
泛型类。什么时候用?当类中的操作的引用数据类型不确定的时候,就使用泛型来表示。
Tool.java
package zhouls.bigdata.DataFeatureSelection; /*
public class Tool { private Object object; public Object getObject() {
return object;
} public void setObject(Object object) {
this.object = object;
} } */
//在jdk1.5后,使用泛型来接收类中要操作的引用数据类型。
//泛型类。什么时候用?当类中的操作的引用数据类型不确定的时候,就使用泛型来表示。
public class Tool<QQ>{
private QQ q; public QQ getObject(){
return q;
} public void setObject(QQ object){
this.q = object;
} /**
* 将泛型定义在方法上。
* @param str
*/
public <W> void show(W str){
System.out.println("show : "+str.toString());
}
public void print(QQ str){
System.out.println("print : "+str);
} /**
* 当方法静态时,不能访问类上定义的泛型。如果静态方法使用泛型,只能将泛型定义在方法上。
* @param obj
*/
public static <Y> void method(Y obj){
System.out.println("method:"+obj);
}
}
GenericDefineDemo.java
package zhouls.bigdata.DataFeatureSelection; import zhouls.bigdata.DataFeatureSelection.Student;
import zhouls.bigdata.DataFeatureSelection.Worker; public class GenericDefineDemo{
/**
* @param args
*/
public static void main(String[] args){
Tool<String> tool = new Tool<String>();
tool.show(new Integer());//show : 4
tool.show("abc");//show : abc
tool.print("hahah");//print : hahah
// tool.print(new Integer(8));//不能
Tool.method("haha");//method:haha
Tool.method(new Integer());//method:9
} }
Student.java
package zhouls.bigdata.DataFeatureSelection; public class Student extends Person{ public Student(){
super(); } public Student(String name, int age){
super(name, age); } @Override
public String toString(){
return "Student:"+getName()+":"+getAge();
}
}
Worker.java
package zhouls.bigdata.DataFeatureSelection; public class Worker extends Person{ public Worker(){
super();
} public Worker(String name, int age){
super(name, age);
} @Override
public String toString(){
return "Worker:"+getName()+":"+getAge();
}
}
Person.java
package zhouls.bigdata.DataFeatureSelection; public class Person implements Comparable<Person> {
private String name;
private int age; public Person() {
super(); } public Person(String name, int age) {
super();
this.name = name;
this.age = age;
} public int compareTo(Person p){
// Person p = (Person)obj;
int temp = this.age - p.age;
return temp==?this.name.compareTo(p.name):temp;
} @Override
public int hashCode() {
final int prime = ;
int result = ;
result = prime * result + age;
result = prime * result + ((name == null) ? : name.hashCode());
return result;
} @Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
} public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} @Override
public String toString() { return "Person:"+getName()+":"+getAge();
}
}
泛型接口
GenericDefineDemo.java
package zhouls.bigdata.DataFeatureSelection; public class GenericDefineDemo {
/**
* @param args
*/
public static void main(String[] args) {
InterImpl in = new InterImpl();
in.show("abc"); InterImpl2<Integer> in2 = new InterImpl2<Integer>();
in2.show();
}
} //泛型接口,将泛型定义在接口上。
interface Inter<T>{
public void show(T t);
} class InterImpl2<Q> implements Inter<Q>{
public void show(Q q){
System.out.println("show :"+q);
}
} class InterImpl implements Inter<String>{
public void show(String str){
System.out.println("show :"+str);
}
}
泛型限定上限
GenericAdvanceDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator; public class GenericAdvanceDemo {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("abc");
al.add("hehe"); ArrayList<Integer> al2 = new ArrayList<Integer>();
al2.add();
al2.add();
printCollection(al);
printCollection(al2);
} /**
* 迭代并打印集合中元素。
* @param al
*/
public static void printCollection(Collection<?> al) {
Iterator<?> it = al.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
}
泛型限定下限
GenericAdvanceDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator; import zhouls.bigdata.DataFeatureSelection.Person;
import zhouls.bigdata.DataFeatureSelection.Student;
import zhouls.bigdata.DataFeatureSelection.Worker; public class GenericAdvanceDemo {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList<Person> al = new ArrayList<Person>();
al.add(new Person("abc",));
al.add(new Person("abc4",)); ArrayList<Student> al2 = new ArrayList<Student>();
al2.add(new Student("stu1",));
al2.add(new Student("stu2",));
ArrayList<String> al3 = new ArrayList<String>(); al3.add("stu3331");
al3.add("stu33332"); printCollection(al2);
printCollection(al);
} /**
* 迭代并打印集合中元素。
*
* 可以对类型进行限定:
* ? extends E:接收E类型或者E的子类型对象。上限!
*
* ? super E :接收E类型或者E的父类型。下限!
* @param al
*/
/*public static void printCollection(Collection<? extends Person> al) {//Collection<Dog> al = new ArrayList<Dog>()
Iterator<? extends Person> it = al.iterator(); while(it.hasNext()){
// T str = it.next();
// System.out.println(str);
// System.out.println(it.next().toString());
Person p = it.next(); System.out.println(p.getName()+":"+p.getAge());
} }*/ public static void printCollection(Collection<? super Student> al){
Iterator<? super Student> it = al.iterator();
while(it.hasNext()){ System.out.println(it.next());
}
}
}
什么时候使用上限?
GenericAdvanceDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.ArrayList;
import zhouls.bigdata.DataFeatureSelection.Person;
import zhouls.bigdata.DataFeatureSelection.Student;
import zhouls.bigdata.DataFeatureSelection.Worker; public class GenericAdvanceDemo{
/**
* @param args
*/
public static void main(String[] args) {
ArrayList<Person> al1 = new ArrayList<Person>();
al1.add(new Person("abc",));
al1.add(new Person("abc4",)); ArrayList<Student> al2 = new ArrayList<Student>();
al2.add(new Student("stu1",));
al2.add(new Student("stu2",)); ArrayList<Worker> al3 = new ArrayList<Worker>();
al3.add(new Worker("stu1",));
al3.add(new Worker("stu2",)); ArrayList<String> al4 = new ArrayList<String>();
al4.add("abcdeef");
// al1.addAll(al4);//错误,类型不匹配。 al1.addAll(al2);
al1.addAll(al3);
System.out.println(al1.size());
}
} /*
* 一般在存储元素的时候都是用上限,因为这样取出都是按照上限类型来运算的。不会出现类型安全隐患。
*/
class MyCollection<E>{
public void add(E e){ }
public void addAll(MyCollection<? extends E> e){
}
}
什么时候使用下限?
GenericAdvanceDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet; import zhouls.bigdata.DataFeatureSelection.Person;
import zhouls.bigdata.DataFeatureSelection.Student;
import zhouls.bigdata.DataFeatureSelection.Worker; public class GenericAdvanceDemo {
/**
* @param args
*/
public static void main(String[] args) {
TreeSet<Person> al1 = new TreeSet<Person>(new CompByName());
al1.add(new Person("abc4",));
al1.add(new Person("abc1",));
al1.add(new Person("abc2",)); TreeSet<Student> al2 = new TreeSet<Student>(new CompByName());
al2.add(new Student("stu1",));
al2.add(new Student("stu7",));
al2.add(new Student("stu2",)); TreeSet<Worker> al3 = new TreeSet<Worker>();
al3.add(new Worker("stu1",));
al3.add(new Worker("stu2",)); TreeSet<String> al4 = new TreeSet<String>();
al4.add("abcdeef");
// al1.addAll(al4);//错误,类型不匹配。
// al1.addAll(al2);
// al1.addAll(al3);
// System.out.println(al1.size());
Iterator<Student> it = al2.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
} /*
* class TreeSet<Worker>
* {
* Tree(Comparator<? super Worker> comp);
* }
* 什么时候用下限呢?通常对集合中的元素进行取出操作时,可以是用下限。
*/ class CompByName implements Comparator<Person>{
public int compare(Person o1, Person o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==? o1.getAge()-o2.getAge():temp;
}
} class CompByStuName implements Comparator<Student>{
public int compare(Student o1, Student o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==? o1.getAge()-o2.getAge():temp;
}
} class CompByWorkerName implements Comparator<Worker>{
public int compare(Worker o1, Worker o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==? o1.getAge()-o2.getAge():temp;
}
}
泛型限定通配符的体现
GenericAdvanceDemo.java
package zhouls.bigdata.DataFeatureSelection; import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet; import zhouls.bigdata.DataFeatureSelection.Person;
import zhouls.bigdata.DataFeatureSelection.Student;
import zhouls.bigdata.DataFeatureSelection.Worker; public class GenericAdvanceDemo {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList<Person> al1 = new ArrayList<Person>();
al1.add(new Person("abc",));
al1.add(new Person("abc4",)); ArrayList<Person> al2 = new ArrayList<Person>();
al2.add(new Person("abc22222",));
al2.add(new Person("abc42222222",)); ArrayList<String> al4 = new ArrayList<String>();
al4.add("abcdeef");
al4.add("abc");
al1.containsAll(al4);
// "abc".equals(new Person("ahahah",20));
}
public static void printCollection(Collection<?> al){
Iterator<?> it = al.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
} class MyCollection2<E>{
public boolean containsAll(Collection<?> coll){
return true;
}
}
泛型的通配符:
? 未知类型。
泛型的限定:
? extends E: 接收E类型或者E的子类型对象。上限
一般存储对象的时候用。比如 添加元素 addAll.
? super E: 接收E类型或者E的父类型对象。 下限。
一般取出对象的时候用。比如比较器。
同时,大家可以关注我的个人博客:
http://www.cnblogs.com/zlslch/ 和 http://www.cnblogs.com/lchzls/
详情请见:http://www.cnblogs.com/zlslch/p/7473861.html
人生苦短,我愿分享。本公众号将秉持活到老学到老学习无休止的交流分享开源精神,汇聚于互联网和个人学习工作的精华干货知识,一切来于互联网,反馈回互联网。
目前研究领域:大数据、机器学习、深度学习、人工智能、数据挖掘、数据分析。 语言涉及:Java、Scala、Python、Shell、Linux等 。同时还涉及平常所使用的手机、电脑和互联网上的使用技巧、问题和实用软件。 只要你一直关注和呆在群里,每天必须有收获
以及对应本平台的QQ群:161156071(大数据躺过的坑)
牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现的更多相关文章
- 牛客网Java刷题知识点之为什么HashMap和HashSet区别
不多说,直接上干货! HashMap 和 HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的 ...
- 牛客网Java刷题知识点之为什么HashMap不支持线程的同步,不是线程安全的?如何实现HashMap的同步?
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- 牛客网Java刷题知识点之Map的两种取值方式keySet和entrySet、HashMap 、Hashtable、TreeMap、LinkedHashMap、ConcurrentHashMap 、WeakHashMap
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- 牛客网Java刷题知识点之ArrayList 、LinkedList 、Vector 的底层实现和区别
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- 牛客网Java刷题知识点之垃圾回收算法过程、哪些内存需要回收、被标记需要清除对象的自我救赎、对象将根据存活的时间被分为:年轻代、年老代(Old Generation)、永久代、垃圾回收器的分类
不多说,直接上干货! 首先,大家要搞清楚,java里的内存是怎么分配的.详细见 牛客网Java刷题知识点之内存的划分(寄存器.本地方法区.方法区.栈内存和堆内存) 哪些内存需要回收 其实,一般是对堆内 ...
- 牛客网Java刷题知识点之HashMap的实现原理、HashMap的存储结构、HashMap在JDK1.6、JDK1.7、JDK1.8之间的差异以及带来的性能影响
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
- 牛客网Java刷题知识点之UDP协议是否支持HTTP和HTTPS协议?为什么?TCP协议支持吗?
不多说,直接上干货! 福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 ...
- 牛客网Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤
福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 Java全栈大联盟 ...
- 牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合
不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...
随机推荐
- Altium Designer 3D模型的下载与添加
先 先晒几个图:是不是很逼真啊.. ---------------------------------------教程---------------------------------------- ...
- Sass和Compass设计师指南 Ben Frain 中文高清PDF扫描版
Sass和Compass设计师指南是<响应式Web设计:HTML5和CSS3实战>作者Ben Frain的又一力作.作者通过丰富.完整的案例,循序渐进地展示了Sass和Compass的使用 ...
- 用MODI OCR 21种语言
作者:马健邮箱:stronghorse_mj@hotmail.com发布:2007.12.08更新:2012.07.09按照<MODI中的OCR模块>一文相关内容进行修订2012.07.0 ...
- redis配置文件常用配置介绍
博客内容首发地址 参数说明 redis.conf 配置项说明如下: Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 当Redis以守护进 ...
- 记一次安装kolla遇到DockerException: Error while fetching server API version: Timeout value connect was Timeout的问题
1)环境信息: docker版本:17.09,当docker的版本是12.06时,也会报这个错误 [root@localhost ~]# docker --version Docker version ...
- html颜色设定 - 网址不见了看这里
- 如何打开Assets.car文件
1.操作步骤 使用GitHub上的工具,下载也好,checkout也好都可以: 运行可知需要传入一个文件路径和解压后的文件输出路径: 选择Edit Scheme 大概看下源码可以知道,第一个是需要解压 ...
- Apache Spark
1. 用Apache Spark进行大数据处理——第一部分:入门介绍 2.
- 编译安装log4cxx
1.介绍 Log4cxx是开放源代码项目Apache Logging Service的子项目之一,是Java社区著名的log4j的c++移植版,用于为C++程序提供日志功能,以便开发者对目标程序进行调 ...
- P4196 [CQOI2006]凸多边形 半平面交
\(\color{#0066ff}{题目描述}\) 逆时针给出n个凸多边形的顶点坐标,求它们交的面积.例如n=2时,两个凸多边形如下图: 则相交部分的面积为5.233. \(\color{#0066f ...