Java泛型

1——泛型在集合中的使用

一、为什么会有泛型

先看下面的代码
Demo1:

class GenericDemo {
	public static void main(String[] args) {

		ArrayList al = new ArrayList();

		al.add("abc01");
		al.add("abc0991");
		al.add("abc014");

		al.add(4);
		
		Iterator it = al.iterator();
		while(it.hasNext()) {
			String s = (String)it.next();
			System.out.println(s+":"+s.length());
		}
	}
}

编译后出现这个提示:


运行后出现异常:


    异常的原因是类型转换错误,Integer不能转换为String。
    假如现在有一个程序,编译时期是没问题的,结果交到用户手上,一运行就出错,这是非常不安全的,所以编译的时候编译器给了一个提示,表示使用了不安全的操作。为了解决这种问题,Java在JDK1.5推出了泛型机制,在JDK1.5之前,程序员在使用集合的时候,只能主观的向集合中添加相同的元素,有了泛型之后,就可以强制添加相同的类型,如果类型不一致,在编译时期就会出错,这就大大提高了程序的安全性。接下来看看泛型到底怎么用。
Demo2:泛型的简单使用

class GenericDemo {
	public static void main(String[] args) {

		ArrayList<String> al = new ArrayList<String>();

		al.add("abc01");
		al.add("abc0991");
		al.add("abc014");

//		al.add(4);
		
		Iterator<String> it = al.iterator();
		while(it.hasNext()){
			String s = it.next();
			System.out.println(s+":"+s.length());
		}
	}
}

    泛型格式:通过<>来定义要操作的引用数据类型。想要指定集合存储的类型,在new集合的时候就得把泛型写上,然后在迭代器那里,因为集合指定了类型,那么该集合的迭代器也得指定为该类型,写了泛型之后,迭代器里面就不需要强制转换了。
    如果将上面代码的注释去掉,想加入一个非String类型的对象,那么编译时就会有错误



Demo3:泛型再比较器上的使用

class GenericDemo2 {
	public static void main(String[] args) {
		TreeSet<String> ts = new TreeSet<String>(new LenComparator());

		ts.add("abcd");
		ts.add("cc");
		ts.add("cba");
		ts.add("aaa");
		ts.add("z");
		ts.add("hahaha");

		Iterator<String> it = ts.iterator();

		while(it.hasNext()) {
			String s = it.next();
			System.out.println(s);
		}
	}
}
//加上泛型之后,比较器内部也不用强制转换,直接接受String类型就行了
class LenComparator implements Comparator<String> {
	public int compare(String o1,String o2) {
		int num = new Integer(o1.length()).compareTo(new Integer(o2.length()));
		if(num==0)
			return o1.compareTo(o2);
		return num;
	}
}

    需要注意的是:在HashSet中,比较两个元素需要用到equals方法,这个不能使用泛型。因为equals属于object里面的方法,object不可以使用泛型。


2——泛型类、泛型方法

一、泛型类

什么时候定义泛型类?当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。现在定义泛型来完成扩展。

Demo1:定义一个工具类,可以操作不同的类

class Worker {
}
class Student {
}
//泛型前做法。
class Tool {
	private Object obj;
	public void setObject(Object obj) {
		this.obj = obj;
	}
	public Object getObject() {
		return obj;
	}
}

//泛型类。
class Utils<QQ> {
	private QQ q;
	public void setObject(QQ q) {
		this.q = q;
	}
	public QQ getObject() {
		return q;
	}
}

class  GenericDemo3 {
	public static void main(String[] args) {
		Utils<Worker> u = new Utils<Worker>();	//new一个工具类
		
		u.setObject(new Worker());
//		u.setObject(new Student());	//编译错误
		Worker w = u.getObject();
		/*
		Tool t = new Tool();
		t.setObject(new Worker());	
		t.setObject(new Student());	//编译不会出错,但是运行时出错
		Worker w = (Worker)t.getObject();
		*/
	}
}
二、泛型方法

Demo2:

class Demo<T> {
	public void show(T t) {
		System.out.println("show:"+t);
	}
	public <Q> void print(Q q) {
		System.out.println("print:"+q);
	}
	public  static <W> void method(W w) {
		System.out.println("method:"+ w);
	}
}
class GenericDemo4 {
	public static void main(String[] args) {
		Demo <String> d = new Demo<String>();
		d.show("haha");
		//d.show(4);
		
		d.print(5);
		d.print("hehe");

		Demo.method("hahahahha");
		Demo.method(1);
	}
}

1.泛型方法的泛型加在返回值前面,加到其他地方会出错
2.如果方法上没有加泛型,那么方法的类型与类的泛型一致,所以上面代码的show方法只能输出String,输出Integer就会报错
3.当类和方法都加了泛型且不一致时,以方法上的泛型为准,所以print方法可以输出多种类型
4.静态方法想要使用泛型必须在自己在方法上指定,不能使用类的泛型,因为类的泛型是在new的时候指定的,而静态方法在new之前就存在了

3——通配符及泛型的限定

一、通配符

Demo1:<?>

class  GenericDemo6 {
	public static void main(String[] args) {
		
		ArrayList<String> al = new ArrayList<String>();

		al.add("abc1");
		al.add("abc2");
		al.add("abc3");

		ArrayList<Integer> al1 = new ArrayList<Integer>();
		al1.add(4);
		al1.add(7);
		al1.add(1);

		printColl(al);
		printColl(al1);
		
		printColl2(al);
		printColl2(al1);
	}
	//使用通配符
	public static void printColl(ArrayList<?> al) {
		Iterator<?> it = al.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
//			System.out.println(it.next().length());	//不能使用
		}
	}
	//使用泛型方法
	public static <T> void printColl2(ArrayList<T> al) {
		Iterator<T> it = al.iterator();
		while(it.hasNext()) {
			T t = it.next();	//可以使用T
			System.out.println(t);
		}
	}
}

    通配符与泛型方法差不多,都可以接受不同的类型,不过泛型方法有可以具体使用的类型T,虽然不明确是什么类型,但是可以使用,而通配符就不可以了。使用泛型虽然有了拓展性,但是也有不可避免的弊端,那就是不能使用某些具体类中的特有方法,比如上面的length(),String类型有,而integer类型没有,所以不能使用。跟多态不能使用子类特有方法一个道理。

二、泛型的限定

<? extends E>: 可以接收E类型或者E的子类型。上限。
<? super E>: 可以接收E类型或者E的父类型。下限

Demo2:<? extends E>

class Person {
	private String name;
	Person(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
}

class Student extends Person {
	Student(String name) {
		super(name);
	}
}
class  GenericDemo6 {
	public static void main(String[] args) {
		ArrayList<Person> al = new ArrayList<Person>();
		al.add(new Person("abc1"));
		al.add(new Person("abc2"));
		al.add(new Person("abc3"));
		printColl(al);

		ArrayList<Student> al1 = new ArrayList<Student>();
		al1.add(new Student("abc--1"));
		al1.add(new Student("abc--2"));
		al1.add(new Student("abc--3"));
		printColl(al1);  
	}
	//打印方法使用了泛型限定
	public static void printColl(ArrayList<? extends Person> al) {
		Iterator<? extends Person> it = al.iterator();
		while(it.hasNext()) {
			System.out.println(it.next().getName());
		}
	}
}
/*
输出:
abc1
abc2
abc3
abc--1
abc--2
abc--3
 */

    上面打印方法的泛型只写<?>是没有问题的,但是这样任何类型都可以传进来,容易产生问题。只写<Person>会出错,只能写<? extends Person>,这样Person和它的子类都可以传进来。这把最顶端的类型给限定了,叫上限。
    还有种叫下限<? super E>,在集合的比较器中就有

TreeSet(Comparator<? superE> comparator)
构造一个新的空 TreeSet,它根据指定比较器进行排序。


Demo3:<? super E>

class GenericDemo7 {
	public static void main(String[] args) {
		
		TreeSet<Student> ts = new TreeSet<Student>(new Comp());

		ts.add(new Student("abc03"));
		ts.add(new Student("abc02"));
		ts.add(new Student("abc06"));
		ts.add(new Student("abc01"));
		
		//遍历输出
		Iterator<Student> it = ts.iterator();
		while(it.hasNext()) {
			System.out.println(it.next().getName());
		}

		TreeSet<Worker> ts1 = new TreeSet<Worker>(new Comp());

		ts1.add(new Worker("wabc--03"));
		ts1.add(new Worker("wabc--02"));
		ts1.add(new Worker("wabc--06"));
		ts1.add(new Worker("wabc--01"));
		
		//遍历输出
		Iterator<Worker> it1 = ts1.iterator();
		while(it1.hasNext()) {
			System.out.println(it1.next().getName());
		}
	}
}

/*笨方法
class StuComp implements Comparator<Student>
{
	public int compare(Student s1,Student s2)
	{
		return s1.getName().compareTo(s2.getName());
	}
}

class WorkerComp implements Comparator<Worker>
{
	public int compare(Worker s1,Worker s2)
	{
		return s1.getName().compareTo(s2.getName());
	}
}
*/

//简便方法
class Comp implements Comparator<Person> {
	public int compare(Person p1,Person p2) {
		return p2.getName().compareTo(p1.getName());
	}
}


class Person {
	private String name;
	Person(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public String toString() {
		return "person :"+name;
	}
}

class Student extends Person {
	Student(String name) {
		super(name);
	}
}

class Worker extends Person {
	Worker(String name) {
		super(name);
	}
}
/*
输出:
abc06
abc03
abc02
abc01
wabc--06
wabc--03
wabc--02
wabc--01
*/

    在Comparator的泛型中,可以不写Student而写Person,因为Student继承了Person,比较时用的是父类的方法,所以Person可以接受子类对象并进行比较。
    注意:<? super E>不像<? extends E>一样全部照抄,而必须写上确定的父类。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值