`
modabobo
  • 浏览: 502212 次
文章分类
社区版块
存档分类
最新评论

黑马程序员—Java基础加强学习笔记之泛型

 
阅读更多

-----------android培训java培训java学习型技术博客、期待与您交流!-----------

泛型

一、1,概述:JDK1.5版本后出现的新特性,用于解决安全问题,是一个安全机制

扩展:(JDK升级目的:高效,简化书写,安全)

JDK1.5版本以前的集合,没有使用泛型,只要是对象,不管什么类型的对象,都可以存储进同一个集合中,JDK1.5版本出现了泛型,这样集合就可以限定某一类型的元素,更安全,并且从集合中获取对象时候,编译器也可以知道这个对象的类型。

好处1:将运行时期出现的问题如:ClassCastException,转移到了编译时期,方便程序员解决问题;

2:不需要再对其进行强制转换,更方便了

2,格式:

通过<E>来定义要操作的引用数据类型,其中E称为类型变量或类型参数

:ArrayListString> a1=new ArrayListString>()

a1.add(“你好”);

a1.add(“abc”);

Sting s=a1.get(0);

3,术语

整个ArrayList<E>称为泛型类型
ArrayList<E>中的E称为类型变量或者类型参数
整个ArrayList<Interger>称为参数化的类型
ArrayList<Interger>中的Interger称为类型参数的实际参数ArrayList称为原始类型

<>发音:typeof

4,参数化类型不考虑类型参数的继承关系(或多态):

举例:

Vector<String> v = new Vector<Object>();//错误,不写Object没错

Vector<Object> v = new Vector<String>();//也错,不要理解说继承父类,或多态

5,在使用Java提供的对象时,什么时候写泛型呢?

在集合框架中很常见,只要见到<>就要定义泛型.

<>就是用来接受类型的

当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可

6,泛型与反射

泛型是提供给Javac编译器使用的,可以限定集合中的元素类型,编译完后会去掉类型信息,使得程序运行效率不受影响,对应参数化的泛型类型,getClas()返回值和原来类型完全一样.由于编译生成的字节码会去掉泛型的类型信息,所以只要跳过编译器,就可以往某个泛型集合中加入其他类型元素,例如,通过反射得到集合,再调用add()方法

7,泛型限定:<? extends父类>

<? super父类>

a,限定通配符的上边界:

<? extends Person>:表示可以接受Person类型和其子类如Student

正确:Vector<? extends Number> x = new Vector<Interger>(),因为NumberInterger的父类

错误: Vector<? extends Interger > x = new Vector< Number >()因为Number才是Interger的父类

加强扩展:定义泛型时可以使用&来指定多个边界

在泛型中还可同时使用多个类型参数,在定义它们时候用逗号隔开

b,限定通配符的下边界:

<? super Student >:表示可以接受Student类型和其父类如Person

正确:Vector<? super Interger > x = new Vector< Number >();

错误: Vector<? extends Interger > x = new Vector< Byte >();因为IntergerByte是同级关系

注意:限定通配符总是包括自己

8,扩展:通过泛型比较器限定

class Comp implements Comparator<Person> {}//定义一个(泛型:父类)的比较器,共子类调用

9,编译器不允许创建类型变量的数组.即在创建数组实例时,数组的元素不能使用参数化的类型,例如下面:

Vector<Integer> vectorList[] = new Vector<Integer>[10];

10,泛型异常

对类型变量表示异常,即泛型异常

//定义一个泛型异常

举例:

//定义一个泛型异常
	private static <T extends Exception> void method() throws T {
		try {
			
		} catch (Exception e) {
			throw(T)e;
		}
	}

二、泛型实例及方法

1,泛型实例:

package com.heima.biji.genericity;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public abstract class genericity_jiaqiang {
	public static void main(String[] args) {
		//定义一个双列的集合HashMap
		HashMap<String,Integer> maps = new HashMap<String,Integer>();
		maps.put("张三", 22);
		maps.put("李四", 20);
		maps.put("王五", 22);
		
		Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
		//forEach迭代Map.Entry集合
		for (Map.Entry<String, Integer> entry : entrySet) {
			System.out.println(entry.getKey()+":"+entry.getValue());
		}
		
		swap(new String[]{"abc","def","ooo"},1,2);//将1和2位置上元素互换
		//swap(new int[]{1,2,3,4,5},0,4);//报错,因为编译器不会对new in[3]中的int自动拆箱和装箱,因为new int[3]已经是对象了
		Object obj = "aaaa";
		String x = conver(obj);
	}
	//定义一互换方法
	private static <T> void swap(T[] a, int i, int j) {
		T tmp = a[i];
		a[i] = a[j];
		a[j] = tmp;
		
	}	
}

代码分析:

只有引用类型才能做为泛型方法的实际参数,对应add方法,使用基本类型的数据进行测试没有问题,这是因为自动装箱和拆箱.

Swap(new int[3],语句会报错,因为编译器不会对new in[3]中的int自动拆箱和装箱,因为new int[3]已经是对象了

2,泛型类

如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用的泛型类型要保持同一个实际类型时,这时候要采用泛型类型的方式进行定义,也就是类级别的泛型-----泛型类.

举例:

package com.heima.biji.genericity;
class Worker {
	
}
class Student {
	
}
//早期泛型方法
/*
class Tool {
	private Object obj;
	public void setObject(Object obj) {
		this.obj = obj;
	}
	public Object getObject() {
		return obj;
	}
}
*/

/**
 * 泛型类
 * 什么时候定义泛型类?
 * 当类中要操作的引用数据类型不确定的时候
 * 早期定义Object来完成扩展
 * 现在定义泛型类来完成扩展
 * 总结:泛型类定义的泛型,在整个类中有效
 * 	   如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就固定了
 */
class Utils<UU> {
	private UU u;
	public void setObject(UU u) {
		this.u = u;
	}
	public UU getObject() {
		return u;
	}
}
public class Demo_genericityclass {

	public static void main(String[] args) {
		/*Tool t = new Tool();
		t.setObject(new Worker());
		Worker w = (Worker)t.getObject();
		*/
		Utils<Worker> u = new Utils<Worker>();
		u.setObject(new Worker());
		Worker w =u.getObject();
	}

}


3,泛型方法

将泛型定义在方法上,这样传入什么类型数据就操作什么类型
为了让不同方法可以操作不同类型,而且类型还不确定,就可以将泛型定义在方法上

举例:

package com.heima.biji.genericity;

class Demo_Method {
	//泛型方法,将泛型定义在方法上
	public <T> void show(T t) {
		System.out.println("show:"+t);
	}
	public <T> void print(T t) {
		System.out.println("print:"+t);
	}	
}
public class Demo_genericity_method {
/**
 * 泛型方法:将泛型定义在方法上,这样传入什么类型数据就操作什么类型
 * 为了让不同方法可以操作不同类型,而且类型还不确定,就可以将泛型定义在方法上
 * @param args
 */
	public static void main(String[] args) {
		Demo_Method dm = new Demo_Method();
		dm.show("hahaha");
		dm.show(new Integer(4));
		dm.print("hehe");
	}

}

4、泛型接口

定义在接口上

举例:

package com.heima.biji.genericity;
//泛型定义在接口上
interface Inter<T> {
	void show(T t);
}
class InterImpl<T> implements Inter<T> {

	@Override
	public void show(T t) {
		System.out.println("show:"+t);
	}
}
public class Demo_genericity_Interface {
	public static void main(String[] args) {
		InterImpl<Integer> i = new InterImpl<Integer>();
		i.show(4);
	}
}

5,通配符举例

package com.heima.biji.genericity;
import java.util.*;
import java.util.ArrayList;
import java.util.Iterator;

public class tongpeifu {
	public static void main(String[] args) {
		ArrayList<String> al = new ArrayList<String>();
		al.add("abc");
		al.add("abcd");
		al.add("abcde");
		ArrayList<Integer> al1 = new ArrayList<Integer>();
		al1.add(1);
		al1.add(2);
		al1.add(3);
		
		printColl(al);
		printColl(al1);	
	}
	//使用通配符?,可以接受任何类型元素
	public static void printColl(ArrayList<?> al) {//ArrayList<String> al=new ArrayList<String>
		Iterator<?> it = al.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}

}

结果:

abc
abcd
abcde
1
2
3

6,泛型推断

编译器判断泛型方法的实际类型参数的过程称为类型推断,类型推断是相对于直觉推断的,其实现方法是一种非常复杂的过程。

根据调用泛型方法时实际传递的参数类型或返回值的类型来推断。

a:当某个类型变量只在整个参数列表中的所有参数和返回值中一处被应用了,那么根据调用方法时该处的实际应用类型来确定,

b:当某个类型变量在整个参数列表中的所有参数和返回值中多处被应用了,如果调用方法时这多处的实际应用类型都对应同一种类型来确定
c:当某个类型变量在整个参数列表中的所有参数和返回值中多处被应用了,如果调用方法时这多处的实际应用类型都对应不同的类型,并且没有使用返回值,这时候取多个参数的最大交集类型

d:当某个类型的变量在整个参数列表中的所有参数和返回值中多处应用到,如果调用方法时这多处实际应用类型对应到了不同的类型,并且使用返回值,这时有限考虑返回值的类型

e:参数类型的类型推断具有传递性

-----------android培训java培训java学习型技术博客、期待与您交流!-----------

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics