泛型

0.泛型知识体系

Java泛型知识体系如下图所示:


1.泛型概论


1)泛型概念

JDK1.5出现的技术,是一种安全机制;再直白一点,泛型就是通过<>定义形式参数,专门用于接收具体的引用类型。另外,{}、[]、()、<>已经全部都有用处。

只要类型不确定就用泛型,使用时明确类型。


2)技术由来

集合中可存储任意类型对象,但是如果取出时调用具体对象特有方法时需要进行向下转型,如果存储对象类型不一致,转型过程中就出抛出ClassCastException异常,给程序带来不安全性。JDK1.5之后就出现了解决方案,即泛型技术。

如下列代码:

public class GenericTest
{
	public static void main(String[] args)
	{
		List ls = new ArrayList();
		ls.add("Tad");
		ls.add("Great");
		ls.add(23);
		Iterator it = ls.iterator();
		while(it.hasNext()){
			String str = (String)it.next();//执行到第3次时,出现问题
			System.out.println(str.length());
		}
	}
}

解决方案就是泛型,在定义容器时完成类型确定,如果类型不匹配就会发生编译错误。


3)泛型关键词

(1)ArrayList:原始类型。

(2)ArrayList<E>:泛型类型;<E>:类型参数。

(3)ArrayList<String>:参数类型;String:实际类型参数。


4)泛型优点

(1)将运行时期的ClassCastException转移到编译时期进行检查并以编译失败体现,利于程序员解决问题,提高安全性。

(2)简化书写,避免类型强制转换,提高效率。


2.通配符与类型限定

1)通配符

构造参数化类型时,如果类型参数不确定,就写类型通配符?。

当操作的不同容器中的类型都不确定的时候,而且使用的都是元素从Object类中继承的方法,这时泛型就用通配符?表示。

public class GenericAdv
{
	public static void main(String[] args)
	{
		ArrayList<String> al1= new ArrayList<String>();
		al1.add("tad1");
		al1.add("tad2");
		al1.add("tad3");
		printColl(al1);
		
		ArrayList<Integer> al2 = new ArrayList<Integer>();
		al2.add(23);
		al2.add(23);
		al2.add(23);
		printColl(al2);
	}
	public static void printColl(ArrayList<?> al){
		Iterator<?> it = al.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
	}
}

public static void printColl(Collection<?> al){}

通配符应用的具体体现。


2)通配符限定

明确具体类型代表一个类型,明确?代表类型,能不能限定只操作某个范围类型?
? extends E 接收E类型或者E的子类型,上限,可以使用E的所有方法:添加元素时用到,如Collection<? extends Person>。
? super E 接收E类型或E的父类型,从容器中取出元素,取出来的都能接收。

?相当于 ? extends Object,所以只能使用Object的方法。


3)类型参数上限与带有接口上限

public class Apple<T extends Number>{
}

一个父类上限,多个接口上限。
public class Apple<T extends Apple && java.io.Serializable>{

}

3.定义及使用泛型

1)定义及使用泛型接口

两种使用方法
(1)实现接口时,明确具体的类。

(2)实现接口时,也不明确具体的类。

//定义泛型接口
interface Shower<G>{//声明是泛型类型,类型参数为G
	public abstract void show(G g);
}

//实现泛型接口时明确具体类型
class ShowerImplA implements Shower<Integer>{
	public void show(Integer g){
		System.out.println(g);
	}
}

//实现接口时不明确具体类型,泛型类+泛型接口
class ShowerImplB<C> implements Shower<C>{
	public void show(C g)
	{
		System.out.println(g);
	}
	
} 

public class GenericInterface
{
	public static void main(String[] args)
	{		
		ShowerImplA sib = new ShowerImplA();
		sib.show(23);
		//sib.show("Tad is a great person in the world!");
		
		ShowerImplB<String> sia = new ShowerImplB<String>();
		sia.show("abc");
	}
}


2)泛型类

(0)早期做法(自定义泛型类)

package tad.blog.generic;

class Teacher{
	
}
class Student{
	
}
class ObjectTools{
	private Object obj;

	public Object getObj()
	{
		return obj;
	}

	public void setObj(Object obj)
	{
		this.obj = obj;
	}
	
}
public class LongAgo
{
	public static void main(String[] args)
	{
		ObjectTools ot = new ObjectTools();
		ot.setObj(new Teacher());
		Student stu = (Student)ot.getObj();	
	}
}

(1)泛型类声明及使用

class Generic<T>//声明是泛型,并且类型参数为T
{
	public void info(){
		System.out.println("Hello world");
	}
}
public class GenericTest 
{
	public static void main(String[] args) 
	{
		Generic<String> g = new Generic<String>();//泛型类实例时指明具体类型
		g.info();
	}
}


(2)泛型类型派生类

当使用了泛型类之后,就可以为父类派生子类,但需要注意的是当使用父类时不能再包含类型形参。

3)泛型方法

public class GenericMethod
{
	public static void main(String[] args)
	{
		Tools<String> tool = new Tools<String>();
		tool.println("Tad is a great person in the world.");
		//tool.println(new Integer(23));//不能打印其它类,如果想要做到,就必须重新new对象。
		Tools<Integer> tool2 = new Tools<Integer>();
		tool2.println(new Integer(23));
		//tool2.println("Tad is a great person in the world.");//同样不可以
		
	}
}
class Tools<E>{
	public void println(E e){
		System.out.println(e.toString());
	}
}

如果想要不重新new对象就改变可以使方法打印各种各样的数据,就需要用到方法的泛型。

方法的操作类型不确定,但不一定和调用该方法的对象指定的类型一致。
泛型定义在类上与泛型定义在方法上,作用域是不一样的。定义的位置不同。

方法泛型参数的定义位置是返回值前方修饰符后方。

public class GenericMethod
{
	public static void main(String[] args)
	{
		Tools<String> tools = new Tools<String>();
		tools.rawPrintln("Tad is a great person in the world!");
		//tools.rawPrintln(new Integer(23));//编译错误
		tools.println("Tad is a great person in the world");//要求传入新的类型参数。
		tools.println(new Integer(23));//也是ok的
	}
}
class Tools<E>{
	public void rawPrintln(E e){
		System.out.println(e.toString());
	}
	public <T> void println(T t){
		System.out.println(t.toString());
	}
}

泛型定义小插曲

(1)泛型类型不能访问类上定义的泛型,如果需要泛型只能定义在方法上。因为类上泛型用到时是在类进行实例化时,而静态方法的调用是不用实例化。


4)类库中的泛型

只要在使用类或或者接口时,该类或接口在API文档描述中带着<>就需要使用,写代码时直接加上,而不是写完再加上, 文档中会说明。
保证两边一致。
ArrayList<Object> al = new ArrayList<String>();

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


5.泛型擦除和转换

泛型是编译器上的技术,编译时对用指定类型对代码检查,检查不通过,编译失败,检查通过完成之后生成class文件中没有泛型,此就是泛型擦除。

运行时可根据具体元素对象获取其具体类型,并用该类型对元素进行转换。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值