泛型的由来和基本使用
1,因为集合可以存储的对象类型是任意的,在取出进行向下转型时,容易发生ClassCastException。
所以JDK1.5以后就有了解决这个问题的技术:泛型。
2,泛型的原理:其实就是在操作的元素类型不确定时,通过传递参数的形式来明确类型。
3,泛型的体现就是 <参数类型变量>用于接收具体的实际元素类型。
4,泛型技术在集合框架中应用非常广泛,只要记住:在使用类或者接口时,如果接口上有明确<>泛型。
在使用时,就传递所需的数据类型即可。不传递会出现警告类型不安全提示。
5,了解:泛型技术是用在编译器部分的技术,一旦类型检查正确,
生成的class文件中就没有泛型标记了:这是的泛型的擦除。
6,泛型的好处:
6.1 将运行时期的ClassCastException异常转移到编译时期通过编译失败体现。
6.2 避免了强制转换的麻烦。
7,其实泛型的使用就是往定义了泛型的类或者接口的<>中传递类型参数。
public static void main(String[] args) {
/*
* 为了让集合使用更安全,
* 问题:什么类型的元素都可以存储。导致取出时,如果出现强转就会引发运行时 ClassCastException。
* 能不能在创建集合时,就明确容器中的元素的类型,如同数组一样。
* 目的是为了更安全。
* JDK1.5以后,出现了解决方案,使用容器时,必须明确容器中元素的类型。
* 这种机制:称之为 :泛型。
* 体现 <数据类型>,不是很难理解,<>也是括号,往括号里面写东西其实就是在传递参数。
* 泛型:
* 1,安全机制。
* 2,将运行时期的ClassCastException,转移到了编译时期变成了编译失败。
* 3,泛型技术,是给编译器使用的技术。
* 4,避免了强转的麻烦。
*/
//int[] arr = new int[];
//创建集合时,直接在集合上明确要存储的元素的类型。
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("zzzz");
// list.add(6);//只要不是指定的类型对象,编译器检查会 报错。这样将运行时的问题转移到编译时期。
for (Iterator<String> it = list.iterator(); it.hasNext();) {
// Object object = (Object) it.next();
// System.out.println(object.toString());
//想要打印字符串的长度。
String str = it.next();
System.out.println(str.length());
}
}
泛型的擦除
泛型类的使用
import java.util.LinkedList;
public class GenericDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
// Tool t = new Tool();
// t.setObject(6);
// String s = (String)t.getObject();
// System.out.println(s);
Tool<String> t = new Tool<String>();
// t.setObject(6);//只要类型错误,编译失败。避免了运行时的类型转换异常。
String s = t.getObject();//省去了强转的麻烦。
System.out.println(s);
Queue<String> queue = new Queue<String>();
queue.myAdd("abcd1");
queue.myAdd("abcd2");
queue.myAdd("abcd3");
while(!queue.isNull()){
String string = queue.myGet();
System.out.println(string);
}
}
}
//jdk1.5有了新技术,泛型,改成如下这样。
//类中操作的对象确定不?不确定,用Object,需要转型,运行容易出异常。不爽。
//在定义时,就将不确定的对象的类型,定义成参数。由使用该类的调用者来传递对象类型。
class Tool<Q>{//将泛型定义在类上,泛型类。
private Q object;
public Q getObject() {
return object;
}
public void setObject(Q object) {
this.object = object;
}
}
class Queue<E>{
//封装了一个链表数据结构。
private LinkedList<E> link;
/*
* 队列初始化时,对链表对象初始化。
*/
Queue(){
link = new LinkedList<E>();
}
/**
* 队列的添加元素功能。
*/
public void myAdd(E obj){
//内部使用的就是链表的方法。
link.addFirst(obj);
}
/**
* 队列的获取方法。
*/
public E myGet(){
return link.removeLast();
}
/**
* 判断队列中元素是否空,没有元素就为true。
*/
public boolean isNull(){
return link.isEmpty();
}
}
/*
//定义一个工具对对象进行操作,比如设置和获取。可以对任意对象进行操作。对共性类型Object操作。
//定义Object就哦了。但用的时候,因为提升为了Object,想要使用特有内容,需要向下转型。容易引发ClassCastException:
class Tool{
private Object object;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
*/
泛型方法的使用
public class GenericDemo3 {
/**
* @param args
*/
public static void main(String[] args) {
Util<String> util = new Util<String>();
util.show("hehe");
// util.print(5);
Util<Integer> util2 = new Util<Integer>();
Util.print(5);
util2.show("hehe");
}
}
class Util<W>{
//当方法要操作的类型不确定和类上的泛型不一定一样。这时可以将泛型定义在方法上。
public <Q> void show(Q q){//泛型方法
System.out.println("show:"+q);
}
public static<E> void print(E e){//记住:如果方法是静态,还需要使用泛型,那么泛型必须定义在方法上。
System.out.println("print:"+e);
}
public void method(W w){
}
}
泛型接口
public class GenericDemo4 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
new InterImpl<String>().show("hehe");
}
}
//泛型接口。
interface Inter<E>{
void show(E e);
}
/*
class InterImpl implements Inter<String>{
public void show(String e){}
}
*/
class InterImpl<T> implements Inter<T>{
@Override
public void show(T e) {
}
}
泛型通配符(?)
public class GenericDemo5 {
public static void main(String[] args) {
Set<Student> list = new HashSet<Student>();
list.add(new Student("lisi1",21));
list.add(new Student("lisi2",22));
list.add(new Student("lisi3",23));
printList(list);
List<String> list2 = new ArrayList<String>();
list2.add("lisi11");
list2.add("lisi22");
list2.add("lisi33");
printList(list2);
}
/*
* 打印集合中的元素。
*
* 当使用泛型类或者接口时,传递的具体的类型不确定,可以通过通配符(?)表示。
*
*/
private static void printList(Collection<?> list2) {
for (Iterator<?> it = list2.iterator(); it.hasNext();) {
System.out.println(it.next().toString());
}
}
}
public class GenericDemo7 {
public static void main(String[] args) {
/*
* 通配符? 在api中的体现。
*
* Collection接口: boolean containsAll(Collection<?> c)
*/
Collection<String> c1 = new ArrayList<String>();
c1.add("haha");
c1.add("hehe");
Collection<Integer> c2 = new ArrayList<Integer>();
c2.add(4);
c2.add(5);
boolean b = c1.containsAll(c2);//了解 containAll源码内判断是否包含的依据。依据是equals方法。
//public boolean equals(Object obj) "abc".equals(5);
System.out.println("b="+b);
}
}
/*
* class Collection<E>
* {
* public boolean containsAll(Collection<?> c){
* }
* }
*/
泛型限定
public class GenericDemo6 {
public static void main(String[] args) {
Set<Student> list = new HashSet<Student>();
list.add(new Student("lisi1",21));
list.add(new Student("lisi2",22));
list.add(new Student("lisi3",23));
printList(list);
List<Worker> list2 = new ArrayList<Worker>();
list2.add(new Worker("lisi11",21));
list2.add(new Worker("lisi22",22));
list2.add(new Worker("lisi33",23));
printList(list2);
}
/*
* 打印集合中的元素。
* 当使用泛型类或者接口时,传递的具体的类型不确定,可以通过通配符(?)表示。
* 如果想要对被打印的集合中的元素类型进行限制,只在指定的一些类型,进行打印。
* 使用泛型的限定。
*
* 只需要打印学生和工人的集合。找到学生和工人的共性类型Person。
* ? extends Person : 接收Person类型或者Person的子类型。
*
* 总结:
* ? super E:接收E类型或者E的父类型。下限。
* ? extends E:接收E类型或者E的子类型。上限。
*/
private static void printList(Collection<? extends Person> list2) {
for (Iterator<? extends Person> it = list2.iterator(); it.hasNext();) {
Person p = it.next();
System.out.println(p.getName());
}
}
}
public class GenericDemo8 {
public static void main(String[] args) {
/*
* 泛型的限定在api中的使用。上限的体现。
* TreeSet(Collection<? extends E> c)
*
*
*/
//创建一个Collection.
Collection<Student> c = new ArrayList<Student>();
c.add(new Student("wangcai1",26));
c.add(new Student("wangcai2",29));
//TreeSet集合在创建时,就将c中的存储到Treeset集合。
TreeSet<Person> ts = new TreeSet<Person>(c);
ts.add(new Person("lisi",20));
for (Iterator<Person> it = ts.iterator(); it.hasNext();) {
Person person = it.next();
System.out.println(person);
}
}
}
/*
* class TreeSet<E>{
* TreeSet(Collection<? extends E> c){}
*/
public class GenericDemo9 {
/**
* @param args
*/
public static void main(String[] args) {
/*
* 泛型的限定在api中的使用。下限的体现。
* TreeSet(Comparator<? super E> comparator)
*
*
*/
//创建一个集合存储的是学生对象。想要按照姓名排序。
TreeSet<Student> ts = new TreeSet<Student>(new ComparatorByName());
ts.add(new Student("abc",26));
ts.add(new Student("aaa",29));
ts.add(new Student("lisi",20));
for (Iterator<Student> it = ts.iterator(); it.hasNext();) {
Student student = it.next();
System.out.println(student);
}
//让工人按照姓名排序。
TreeSet<Worker> ts2 = new TreeSet<Worker>(new ComparatorByName());
ts2.add(new Worker("abc",26));
ts2.add(new Worker("aaa",29));
ts2.add(new Worker("lisi",20));
for (Iterator<Worker> it = ts2.iterator(); it.hasNext();) {
Worker worker = it.next();
System.out.println(worker);
}
}
}
class ComparatorByName implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==0? o1.getAge() - o2.getAge() : temp;
}
}
/*
* 以下两个比较器,都是通过姓名排序,就是类型不同,一个是student,一个是worker
* 既然使用的都是Person的内容,为什么不定义一个Person的比较器。
*/
/*
//定义一个比较器。
class ComparatorByName implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==0? o1.getAge() - o2.getAge() : temp;
}
}
//定义一个工人的姓名比较器。
class ComparatorByWorkerName implements Comparator<Worker>{
@Override
public int compare(Worker o1, Worker o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==0? o1.getAge() - o2.getAge() : temp;
}
}
*/
/*
* class TreeSet<E>{
* TreeSet(Comparator<? super E> c){}
*/
泛型的细节
// ArrayList<Dog> al = new ArrayList<Animal>();//使用泛型,要保证左右类型一致。
// ArrayList<String> al = new ArrayList<Object>();
List<Integer> list = new ArrayList<Integer>();
// show(list);
}
public static void show(List<String> list){
}