ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

简述Java的泛型机制

2021-09-16 19:06:15  阅读:140  来源: 互联网

标签:Java ArrayList Person 简述 void 泛型 static public


  • 泛型类

什么时候定义泛型类?在类中要操作的数据类型不明确的时候,早期通过定义Object来完成扩展,而现在定义泛型来完成扩展,集合类就是使用了泛型的一个经典例子。

class Person{}
class Utils<QQ>{
	private QQ q;
	public void setObject(QQ q){
		this.q=q;
	}
	public QQ getObject(){
		return q;
	}
}
public class GenericDemo{
	public static void main(String[] args){
		Utils<Person> u=new Utils<Person>();
		u.setObject(new Person());
		Person p=u.getObject();
		System.out.println(p); //Person@512ddf17
	}
}
  • 泛型方法

class Person<T>{
	private T t;
	public Person(T t){
		this.t=t;
	}
	public void set(T t){  //这不是泛型方法
		this.t=t;
	}
	public T get(){  //这不是泛型方法
		return t;
	}
	public <Q> void print1(Q q){ //泛型方法的格式:<类型>写在返回值前面、访问修饰符后面
		System.out.println(q);
	}
	public <T> void print2(T t){
		System.out.println(t);
		//泛型方法中定义的T和泛型类上定义的T没有关系,它们独立存在
		//只有非泛型方法中使用的T才是泛型类限定的T,如上面的get()和set()
	}
}

注意:类上限定的<T>不能用于静态方法
如:public static void method(T t){ }这种写法是错误的。

正确写法为:public static <T> void method(T t){ }这是泛型方法,此处的<T>与类限定的<T>无关。

  • 泛型方法的实际应用

import java.util.Arrays;

public class Demo{
	public static void main(String[] args){
		String[] arr1 ={"a","b","c"};
		swap(arr1,0,2);
		System.out.println(Arrays.toString(arr1)); //[c, b, a]
		Integer[] arr2 = {1,2,3};
		//泛型要求包容的是引用类型,而基本数据类型在Java中不属于引用类型,但是基本数据类型有其包装类可以使用
		swap(arr2,0,2);
		System.out.println(Array.toString(arr2)); //[3, 2, 1]
	}
	public static <T> void swap(T[] arr,int index1,int index2){
		T temp = arr[index1];
		arr[index1] = arr[index2];
		arr[index2] = temp;
	}
}

从上面的例子可以看出使用泛型的方便之处。如果按照早期的思想,这里要定义Object[]来接收参数。

  • 泛型接口

interface Inter<T>{ //泛型接口
	void method(T t);
}
class Student{}

class Person implements Inter<Student>{ //实现接口时传入实际类型
	private Student s;
	public void method(Student s){
	//由于实现接口时传入了具体类型,所以实现了接口的这个方法也必须是那个具体的类型,否则编译报错。
		System.out.println(s); //Student@2c13da15
	}
}

class A<T> implements Inter<T>{//如果定义实现类时也不明确传入的具体类型,可以这样写
//然后当类创建对象时使用泛型传入具体的实际类型,则接口的泛型也会跟着确定。
	private T t;
	public void method(T t){
		System.out.println(t); //由泛型传入的类型决定。
	}
}
public class GenericDemo{
	public static void main(String[] args){
		Person p = new Person();
		p.method(new Student());
		A<String> a = new A<String>();
		//a.methood(1);编译报错
		//a.method("hello");完全OJBK
	}
}
  • 泛型通配符

先来看一段原始代码:

import java.util.*;

public class GenericDemo{
	public static void main(String[] args){
		ArrayList<String> al1 = new ArrayList<String>();
		al1.add("java1");
		al1.add("java2");
		al1.add("java3");

		ArrayList<Integer> al2 = new ArrayList<Integer>();
		al2.add(1);
		al2.add(2);
		al2.add(3);

		printList(al1);
		printList(al2);
	}
	public static void printList(ArrayList<String> al){
		for(Iterator<String> it = al.iterator();it.hasNext();){
			System.out.println(it.next());
		}
	}
}

这段代码是会报错的,因为ArrayList泛型是String类型,所以无法传入泛型为Integer的ArrayList实参,那怎么办呢?可以用通配符来解决:

import java.util.*;

public class GenericDemo{
	public static void main(String[] args){
		ArrayList<String> al1 = new ArrayList<String>();
		al1.add("java1");
		al1.add("java2");
		al1.add("java3");

		ArrayList<Integer> al2 = new ArrayList<Integer>();
		al2.add(1);
		al2.add(2);
		al2.add(3);

		printList(al1);
		printList(al2);
	}
	public static void printList(ArrayList<?> al){
		for(Iterator<?> it = al.iterator();it.hasNext();){
			System.out.println(it.next());
		}
	}
}

通配符“?”,代表未知类型,有点类似于Object类型的形参接收任意类型的实参一样。通配符并不是一定要用“?”,任意一个字母比如T,V,K都可以,但是二者有区别:使用字母做为通配符的话,要使用泛型方法的格式

比如:public static <T> void printList(ArrayList<T> al){}前面的不可省略,而使用<?>如例图所示不用。

还有一个区别是:字母通配符代表的是具体类型,可以用来定义变量,而“?”不行:

public static <T> void printList(ArrayList<T> al){
	T t;
	for(Iterator<T> it = al.iterator();it.hasNext();){
		t=it.next();
		System.out.println(t);
	}
}
  • 泛型限定

学了泛型通配符,接下来就以通配符为基础,进一步了解一下泛型限定的应用:
先来看个代码:

import java.util.*;

class Person{ }
class Student extends Person{ }

public class GenericDemoo{
	public static void main(String[] args){
		ArrayList<Person> al1 = new ArrayList<Person>();
		al1.add(new Person());
		ArrayList<Student> al2 = new ArrayList<Student>();
		al2.add(new Student());

		printList(al1);
		printList(al2);
	}
	public static void printList(ArrayList<> al){
		for(Iterator<> it = al.iterator();it.hasNext();){
			System.out.println(it.next());
		}
	}
}

代码中的泛型没有写出来,那么应该怎么写比较合适?
写“?”,还是"Person"?。 都不对,写“?”会导致泛型范围太大,根据题意,该泛型只需要Person和Student,而写Person又会导致Student无法传入导致编译失败。

正确写法是<? extends Person>代表未知类型,但是这个未知类型有一定的范围,是Person类或者Person类的子类,叫做泛型的上限限定

同理,还有 <? super Student> 代表Student类或者Student类的父类,叫做泛型的下限限定。

但是新的问题又出现了:用<? extends Person>的话下面的Iterator<>中无法使用"?",那么怎么办呢?正确应该写为:

public static <T extends Person> void printList(ArrayList<T> al){
	for(Iterator<T> it = al.iterator();it.hasNext();){
		System.out.println(it.next());
	}
}

用字母通配符来代替"?",字母通配符与"?"不同,必须在返回值之前声明它

在泛型方法中添加上下限定时,必须在权限声明与返回值之间的字母通配符添加上下边界,即在泛型声明的时候添加

public <T> void printList(ArrayList<T extends Person> al){ }
编译器会报错:"Unexpected bound"

public <T extends Person> void printList(ArrayList<T> al){ }
正确

  • 泛型擦除

泛型是提供给javac编译器使用的,它用于限定输入类型,让编译器在源代码级别上挡住非法类型数据,但编译器编译完带有泛型的java程序后,生成的class文件中将不再带有泛型信息,以使程序的运行效率不受到影响
这个过程称之为泛型擦除

标签:Java,ArrayList,Person,简述,void,泛型,static,public
来源: https://www.cnblogs.com/l-cai/p/15294720.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有