黑马程序员--范型

-------<a href="http://www.itheima.com" target="blank">android培训</a></li><li><a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流!----------

1.范型的定义

泛型是JDK1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以在类、方法和类中创建,分别称为泛型类、泛型方法、泛型接口。 
没有泛型的情况的下,通过对类型Object的引用来实现类型不明确的参数,其缺点是需要要强制类型转换,这就要求开发者对实际参数类型在可以预知的情况下进行。强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。

不使用范型的代码实例如下:
public class Test {


	public static void main(String[] args) {
		ArrayList al = new ArrayList();
		
		al.add("aaa1");
		al.add("aaa2");
		al.add("aaa3");
		al.add(4);
		
		Iterator it = al.iterator();
		while(it.hasNext()){
			String s = (String)it.next();
			System.out.println(s+""+s.length());
		}
	}
}
在没有范型的情况下需要在传递对象时明确对象的类型并在相应的方法中强制类型转换,而不符合该类型的数据在编译时不能给出错误提示,需要运行时才会出现异常,存在安全隐患。
2.范型的使用
使用泛型的好处:
1.将运行时期出现的问题ClassCastException,转移到了编译时期,方便于程序员解决问题,运行时的问题减少,更为安全。
2.避免了强转的麻烦操作。
范型的格式:
通过<>定义操作的引用数据类型。<>用于接收类型,当使用集合时,将集合中要存储的数据类型作为参数传递到<>中。
在使用java提供的数据对象时,什么时候使用范型呢?我们通常在集合框架经常使用范型。
下面我们来使用范型完成上面实例的操作
public class Test {
	public static void main(String[] args) {
		ArrayList<String> al = new ArrayList<String>();
		
		al.add("aaa1");
		al.add("aaa2");
		al.add("aaa3");
		al.add(4);
		
		Iterator<String> it = al.iterator();
		while(it.hasNext()){
			String s = it.next();
			System.out.println(s+""+s.length());
		}
	}
}

当我们编译代码时,通过ArrayList<String>编译时检测添加到数组中的类型,会提示类型转换异常,这样我们就能明确添加的内容中有不匹配的条目,而且在通过迭代器获取到的内容也不需要进行强制类型转换。
public class GenericDemo2 {
	public static void main(String[] args) {
		TreeSet<String> ts = new TreeSet<String>(new LenComparator());
		
		ts.add("abdc01");
		ts.add("abdc02");
		ts.add("abdc03");
		ts.add("abdc04");
		
		Iterator<String> it = ts.iterator();
		while(it.hasNext()){
			String s = (String) it.next();
			System.out.println(s+"::"+s.length());
		}
	}


}
class LenComparator implements Comparator<String>{
	public int compare(String t1,String t2){
		//倒序需要s1和s2交换即可
		int num = new Integer(t1.length()).compareTo(new Integer(t1.length()));
		if(num == 0)
			return (t2.compareTo(t1));
		return num;
	}
}

3.范型类的使用
在使用TreeSet进行排序时同样可以使用相同的方法,避免强制类型转换的不安全方法。
如何在自己定义的类中使用范型操作呢?一个很简单的程序演示自定义类中的范型使用操作。
class Stud{
}
class Worker{
}
class Tool{
	private Worker w;
	public Worker getWorker() {
		return w;
	}
	public void setWorker(Worker w) {
		this.w = w;
	}
}
class Tool1{
	private Stud s;
	public Stud getStud() {
		return s;
	}
	public void setStud(Stud s) {
		this.s = s;
	}
}
public class GenericDemo3 {
	public static void main(String[] args) {
		Tool t = new Tool();
		t.setWorker(new Worker());
		Worker w = t.getWorker();
		
		Tool1 t1 = new Tool1();
		t1.setStud(new Stud());
		Stud s = t1.getStud();
	}
}

可以看到我们用于操作学生和操作工人的工具类几乎是一样的,只有参数类型不同,怎样才能使用同一个方法操作不同类型的类呢?范型就可以解决这一问。
我们将Tool和Tool1使用范型封装成一个类Util就可以实现
class Stud{
}
class Worker{
}
class Util<T>{
	private T t;
	public void setObject(T t) {
		this.t = t;
	}
	public T getObject() {
		return t;
	}
}
public class GenericDemo3 {
	public static void main(String[] args) {
		Util<Worker> u = new Util<Worker>();
		u.setObject(new Worker());
		Worker w = u.getObject();
		
		Util<Stud> u1 = new Util<Stud>();
		u1.setObject(new Stud());
		Stud s = u1.getObject();
	}
}

这样我们要操作Worker对象时就给Util类传递Woker参数,要操作Stud对象时就传递Stud参数,使得方法更加使用,也更加简便。
4.范型方法的使用
在学习范型之前我们需要在定义函数时指定操作类型,现在只需要,对类定义范型,在定义函数时,引用类定义的范型,就可以实现不同类型参数的传递,但是我们能不能直接对函数定义范型呢?当然,结果是肯定的。
class Demo<T>{
	public <T> void show(T t){
		System.out.println(t+"::show()");
	}
	public <Q> void print(Q t){
		System.out.println(t+"::print()");
	}
	public static <W> void method(W w){//注意范型别放错位置
		System.out.println(w+"::method");
	}
}
public class GenericDemo4 {
	public static void main(String[] args) {
		Demo<String> d = new Demo<String>();
		d.show("haha");
		d.show(4);
		d.print("hehe");
		d.print(4);
		Demo.method("hhh");
	}
}


  范型类定义的范型,在整个类中有效,如果被方法使用。那么范型类的对象明确要操作的具体类型后,需要操作的类型就已经固定,而为了操作不同的类型,那么可以将范型定义在方法上。需要注意的是将范型定义在方法上有一些特殊之处,静态方法不可以访问类上定义的范型。
 5.范型接口的使用
  既然类可以定义范型,接口应该也可以,下面是接口使用范型定义的实例:
/范型定义的接口
interface Inter<T>{
	void show(T t);
}
class InterImpl<T> implements Inter<T>{
	public void show(T t){
		System.out.println("show:"+t);
	}
}
public class GenericDemo5 {
	public static void main(String[] args) {
		InterImpl<String> i = new InterImpl<String>();
		i.show("haha");
	}
}

6.范型的高级应用
我们来看下面一段代码:
public class Test {
	public static void main(String[] args) {
		ArrayList<String> al = new ArrayList<String>();
		al.add("aaa1");
		al.add("aaa2");
		al.add("aaa3");
		
		ArrayList<Integer> al1 = new ArrayList<Integer>();
		al1.add(3);
		al1.add(5);
		al1.add(8);
		al1.add(4);
		
		printColl(al);
		printColl(al1);
	}
	public static void printColl(ArrayList<String> al){
		Iterator<String> it = al.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}

当我们使用printColl(al1)方法时会产生类型不匹配错误,我们需要使用同一个方法输出第二个ArrayList时我们可以将printColl(ArrayList<String> al)方法中的参数修改一下改为printColl(ArrayList<?>通配符?用于接收所有不明确的类型。但这是我们不能对获取到的对象使用特定的方法(如String的求长度方法),这时我们需要对这些不明确类型加以限定,通过限定以后我们可以使用限定范围内的类的特有方法。
class Person{
	private String name;
	Person(String name){
		this.name = name;
	}
	public String getName(){
		return name;
	}
}
class Student extends Person{
	Student(String name){
		supper(name);
	}
}
public class Test {
	public static void main(String[] args) {
		ArrayList<Person> al1 = new ArrayList<Person>();
		al1.add(new Person("abc1"));
		al1.add(new Person("abc2"));
		al1.add(new Person("abc3"));
		printColl(al1);
		
		ArrayList<Student> al2 = new ArrayList<Student>();
		al2.add(new Student("abc1"));
		al2.add(new Student("abc2"));
		al2.add(new Student("abc3"));
		printColl(al2);
	}
	public static void printColl(ArrayList<Person> al){
		Iterator<Person> it = al.iterator();
		while(it.hasNext()){
			System.out.println(it.next().getName());
		}
	}
}
当我们对Person的子类Student使用printColl(al2)方法时,发现输出异常,其实这个过程的调用相当于ArrayList<Person> al1 = new ArrayList<Student>(),这是由于"="前定义了一个Person类型的数组,可以存放继承Person类的各种子类,而"="后实例化的数组只能存储Person的其中一个子类Student,当我们用一个其他的子类对象存储到实例话的Person类型Student中,发现类型异常。这种情况我们需要如何解决呢?java给我们提供了更为实用的限定范围的范型方法<? extends Person>这时我们就可以对子类Student访问。使用这方式以后就可以使用父类中有的特定方法。限定有两种方式:
 ? ectends E :可以接收E类型或者E的子类型,向上限定
 ? supper E :可以接收E类型或者E的父类 ,向下限定
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值