15,泛型
15.1泛型
泛型的符号:<泛型标识符,泛型标识符……>
泛型的作用:泛型就是用于接收具体引用数据类型的参数范围。
泛型什么时候用?
当操作的引用数据类型不确定的时候,就可以使用泛型。
使用泛型的好处:
1,将运行时期的问题转到的编译时期。
2,避免了强转的麻烦。
泛型是JDK1.5的新特性,目的是增加安全性。
15.2泛型的擦除和补偿
java源文件中定义的泛型在运行时会被擦除,生成的字节码文件是不带泛型的,称为泛型的擦除。
当在运行.class字节码文件时,会进行泛型的补偿,目的是避免使用者强转的动作。
泛型在集合、类、方法和接口中都有广泛的应用。
15.3泛型类
当类中操作的引用数据类型不确定时,就可以使用泛型类
类上定义泛型的格式:
权限饰符 class类名<泛型标识符1,泛型标识符2…….>{
…….CODE;
}
如:集合框架中的ArrayList<E>类,定义了泛型,用来明确集合中要存放什么类型的元素,集合对象创建时需要传入具体的引用数据类型,一旦集合的泛型接收了具体的引用数据类型,那么这个集合中只能存储这一类型的元素,当传入其它类型的元素,编译器就会报错。
ArrayList<String>al=new ArrayList<String>();
//添加元素
al.add("abc1");
al.add("abc2");
al.add("abc2");
al.add("abc1");
al.add("abc4");
al.add("abc5");
for(Iterator<String> it=al.iterator();it.hasNext();){
String s=it.next();//如果不加泛型就需要强转:String s=(String)it.next();
System.out.println(s);
}
如上,集合泛型为String类型,那么集合中的元素,就必须是这一类型,否则编译会报错,提高了安全性。
在元素的取出过程中,因为next()取出的元素类型默认是Object类型,如果加了泛型就不需要再进行强转的动作,否则必须要强转,避免了强转的麻烦。
如:以下自定义类中使用的泛型。
public class GenericDemo{
public static void main(String[]args){
Person<String,Integer> person=new Person<String,Integer>("lisi",23);//创建对象时指定具体泛型类型。
Student<String,Integer> student=new student<String,Integer>("zhangsan",23,100);
person.show();
student.show();
}
}
class Person<N,A>{//Person类上定义了泛型
private Aa;
private Nn;
Person(){
}
Person(N n,A a){//构造参数使用了类上的泛型
this.n=n;
this.a=a;
}
public void show(){
System.out.println("姓名:"+this.n+" 年龄:"+this.a);
}
}
class Student<N,A>extends Person<N,A>{//当子类继承父类时,没有传入具体泛型类型时,子类也要定义泛型
private A a;
private N n;
private int s;
Student(N n, A a, int s) {
this.n=n;
this.a=a;
this.s = s;
}
public void show(){
System.out.println("姓名:"+this.n+"年龄:"+this.a+"分数:"+this.s);
}
}
/*
姓名:lisi 年龄:23
姓名:zhangsan年龄:23分数:100
*/
15.4泛型方法
如果一个类定义了泛型,那么类中的方法可以使用类上的泛型作为参数。当然,如果方法中的参数类型不确定,则可以在方法上重新定义泛型。
注意:泛型在方法上的位置,只能定义在返回值的前面,修饰符的后面
格式:
权限修饰符 成员修饰符 <泛型标识符1,泛型标识符2……>返回值类型 方法名称(泛型标识符1 变量,泛型标识符2 变量,.....,其它参数){
方法体;
}
如:
class Generic<T>{//定义了泛型的类
private T t;
Generic(T t){
this.t=t;
}
public void show_1(T t){//此方法的参数直接使用了类上的泛型,类上传入什么类型,这个方法的参数就是什么类型。
}
public <A> void show_2(A a){//此方法的参数,没有使用类上的泛型,而是使用了其他的泛型,则需要在方法上定义泛型。
}
public static <B> void show_3(B b){//注意,对于静态方法的参数是不能直接访问类上的泛型的,如果要使用泛型则需要在方法上重新定义泛型。
}
}
注意:对于静态方法是不能直接访问类上的泛型的,因为类上的泛型是依赖对象的,而静态方法不需要对象去调用,所以,静态方法不能直接使用类上定义的泛型。如果静态方法要使用泛型,则需要在静态方法上定义泛型。
15.5泛型接口
格式:
interface接口名<泛型标识符1,泛型标识符2……>{
}
如:
interface Inter<T>{
void show(T t);
}
注意:如果一个类实现了带有泛型的接口时,如果没有明确具体泛型类型,则这个类也必须要定义泛型。
如:
interface Inter<T>{
void show(T t);
}
class Generic <T> implements Inter<T>{//没有明确接口上泛型的具体类型,类也要定义泛型
@Override
public void show(T t) {
}
}
如果在实现一个泛型接口时,明确具体的泛型类型,就把具体的类型传给接口上的泛型。这样类上就需要再定义泛型。
如:
interface Inter<T>{
void show(T t);
}
class Genericimplements Inter<String>{//明确接口上泛型的具体类型,直接传入具体类型到接口上的泛型。
@Override
publicvoid show(String t) {
}
}
15.6泛型通配符
泛型通配符:?,表示未知的泛型类型。
用字母作为泛型标识符和泛型通配符?有什么区别呢?
用字母作为泛型的标识符,可以对其进行操作。
如:泛型方中,作为方法的返回值 ,作为一个类型,声明一个变量,传给类中的构造函数等等。
public <T> T show(T t){
//方法体;
}
而泛型通配符,代表未知的任意类型,是不能够直接操作的,通配符多用于对泛型的限定。
泛型的限定分为:上限和下限
上限:<? extends具体引用类型A> ,表示可以接收A类型及其A的子类类型。
下限:<? super具体引用类型B>,表示可以收的B类型及B的父类类型。
上限和下限同样可以用于对字母泛型标识符的限定。
如:上限
public class GenericDemo{
public static void main(String[]args){
new Generic().show("abc"); //传入字符串类型,可以打印
new Generic().show(123);//传入其它类型,就报错。
}
}
class Generic{
public <T extends String> void show(T t){//show(T t)方法的参数类型T必须是,String及其子类,不能传入其它类型参数。
System.out.println(t);
}
}
如:下限
public class GenericDemo<T>{
public static void main(String[]args){
Person<String> p=new Person<String>("LISI",23);
new Generic().show(p);
}
}
class Generic{
public void show(Person<?super String> g){//此方法,用来接收Person类型 参数,对Person的泛型进行了下限。
System.out.println(g.getT()+":"+g.getAge());
}
}
class Person<T>{
private T t;
private int age;
public Person(T t,int age) {
super();
this.t = t;
this.age = age;
}
public T getT() {
return t;
}
public int getAge() {
return age;
}
}
15.7泛型在集合中的应用
泛型在集合中都有所应用,集合中使用泛型可以避免强转。集合定义泛型,在创建集合对象时,可以明确具体的泛型类型,元素在取出时,就不需再进行强转。
如:ArrayList集合
public class GenericDemo<T>{
public static void main(String[]args){
ArrayList al=newArrayList();//创建集合对象
al.add("abc1");//add(Objectobj);方法中接收的参数都会被提升为Object类型。
al.add("abc2");
al.add("abc3");
al.add("abc4");
Iterator it=al.iterator();
while(it.hasNext()){
String s=(String)it.next();//添加的元素被提升为Object类型,取出时也是Object类型,要强转。
System.out.println(s);
}
}
}
因为没有加泛型,所以在元素取出时必须要强转。
把泛型加入集合:
:
import java.util.ArrayList;
import java.util.Iterator;
public class GenericDemo<T>{
public static void main(String[]args){
ArrayList<String> al=new ArrayList<String>();//创建集合对象,并明确泛型类型
al.add("abc1");//add(Objectobj);方法中接收的参数都会被提升为Object类型。
al.add("abc2");
al.add("abc3");
al.add("abc4");
Iterator <String>it=al.iterator();//元素的取出明确泛型
while(it.hasNext()){
String s=it.next();//添加的元素被是String,取出时也是String类型,不需要强转。
System.out.println(s);
}
}
}
可见,泛型的应用,不仅可以对集合中元素的添加进行类型的限定,增强安全性,避免出错,而且避免了元素在取出中强转的麻烦。
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------