Java基础二十七(泛型)

泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。泛型擦除

泛型一般有三种使用方式:泛型类、泛型接口、泛型方法。

public class Type<E>{}
public interface Interface<E> {}
public <E> E test(E e) {
		return e;
}

的区别 【了解】

分两种情况:

1. 作为容器时 【了解】

没有意义,只能存null

可以放它本身和其子类类型,可以存null

public static void main(String[] args) {
		SuperMan man = new SuperMan();
		Person p = new Person("", 1);
		Student s = new Student("", 1);
		
		List<? extends Person> list = new ArrayList();
//		list.add(man);
//		list.add(p);
//		list.add(s);
//		list.add(1);
		list.add(null);
		
		List<? super Person> list1 = new ArrayList();
//		list1.add(new Object());
//		list1.add(man);
		list1.add(p);
		list1.add(s);
		list1.add(null);
//		list1.add(1);
	}
public class Person extends SuperMan implements Comparable{

	private String name;
	
	private int age;

	//省略部分代码

}

class Student extends Person{

	public Student(String name, int age) {
		super(name, age);
	}
	
}

class SuperMan {
	
}

2. 作为方法参数时

支持其本身类型及其子类类型,也就是设置上限。

支持本身类型及其父类类型,也就是设置下限。

public static void main(String[] args) {
		List<Object> listObj = new ArrayList();
		List<SuperMan> listMan = new ArrayList();
		List<Person> listPson = new ArrayList();
		List<Student> listStu = new ArrayList();
		
		// ? extends Person
//		test(listObj);
//		test(listMan);
		test(listPson);
		test(listStu);
		
		// ? super Person
		test1(listObj);
		test1(listMan);
		test1(listPson);
//		test1(listStu);
		
	}

	
	public static void test(List<? extends Person> list) {
		
	}
	
	
	public static void test1(List<? super Person> list) {
		
	}

常用的通配符为: T,E,K,V,?通配符介绍

  • ? 表示不确定的 java 类型
  • T (type) 表示具体的一个java类型
  • K V (key value) 分别代表java键值中的Key Value
  • E (element) 代表Element

泛型的使用限制

1. 无法使用基本数据类型

List<int> list = new ArrayList<>(); // 编译时错误

2. 无法创建泛型参数类型的实例

public <E> void test(E e) {
    E e1 = new E(); // 编译时错误
}

但是可以通过反射来创建对象

public <E> void test(E e) {
    E e1 = e.getClass().newInstance();// 正确
}

3. 不能为static字段(属性)声明为泛型类型

class Test<T>{
	private static T name; // 编译错误
	private T age; // 正确
}

4. 无法使用泛型类型进行强制类型转换或者 instanceof

List<Integer> li = new ArrayList<>();
List<Number> ln = (List<Number>)li; //编译错误

除非使用无界符号(?)才可以强制转换

List<?> li = new ArrayList<>();
List<Number> ln = (List<Number>)li;
// 或者
List<Integer> li = new ArrayList<>();
List<?> ln = (List<?>)li;

在某种情况下,编译器知道泛型类型始终有效并允许强制类型转换

List<String> li = new ArrayList<>();
ArrayList<String> ln = (ArrayList<String>)li;

instanceof

public <E> void test(List<E> list) {
    if(list instanceof ArrayList<String>) {} //编译错误
}

运行时是不跟踪参数类型的,所以无法区分泛型类型。可以使用无界符号

public <E> void test(List<E> list) {
    if(list instanceof ArrayList<?>) {} //正确
}

5. 无法创建泛型类型的数组

List<String>[] lists = new ArrayList<String>[2]; //编译时错误

将不同类型元素插入到数组中:

Object[] objs = new String[2];
objs[0] = "s";
objs[1] = 1; // java.lang.ArrayStoreException

使用集合进行相同的操作

Object[] obs = new List<String>[2]; // 编译错误
obs[0] = new ArrayList<String>();
obs[1] = new ArrayList<Integer>();

6. 无法创建、捕获或者抛出泛型类型异常

泛型不能直接或间接扩展Throwable类。

class Ex<T> extends Exception{} // 编译错误
class Exc<T> extends Throwable{} // 编译错误

无法捕获泛型类型实例

public <T extends Exception> void test() {
    try {
    }catch(T t) { // 编译错误
    }
}

但是可以在throws子句中出现

public <T extends Exception> void test() throws T{}

7. 泛型擦除到原生类型的方法无法重载

​ 因为泛型擦除后,方法的签名一样。

public void test(List<String> list) {} //编译错误
public void test(List<Integer> list) {} // 编译错误

你可能感兴趣的:(Java,java,开发语言)