泛型的详细教程

JDK1.5之前

那时候是没有泛型的概念的。当时 Java 程序员们写集合类的代码都是类似于下面这样:

List list = new ArrayList(); 
list.add("www.cnblogs.com"); 
list.add(23);
String name = (String)list.get(0);
Integer number = (Integer)list.get(1);

在代码中声明一个集合,我们可以往集合中放入各种各样的数据,而在取出来的时候就进行强制类型转换。

泛型的介绍

泛 型的定义:泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type)的应用,也就是说所操作的数据类型被指定为一个参数,在用到的时候在指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛 型类、泛型接口和泛型方法。

泛型的本质

泛型只在编译阶段有效,编译后进入JVM会采取去泛型化的措施,也就是说生成class文件时,并不在有泛型的说法。
泛型在运行阶段是没有效果。

ArrayList<String> a = new ArrayList<String>(); 
ArrayList<Integer> b = new ArrayList<Integer>(); 
Class c1 = a.getClass(); 
Class c2 = b.getClass(); System.out.println(c1 == c2);

在继续往下看之前,先想一想,这道题输出的结果是什么?

是 true 还是 false ?

这道题输出的结果是 true。因为无论对于 ArrayList 还是 ArrayList,它们的 Class 类型都是一直的,都是 ArrayList.class。

那它们声明时指定的 String 和 Integer 到底体现在哪里呢?

答案是体现在类编译的时候。

当 JVM 进行类编译时,会进行泛型检查,如果一个集合被声明为 String 类型,那么它往该集合存取数据的时候就会对数据进行判断,从而避免存入或取出错误的数据。
也就是说:
泛型只存在于编译阶段,而不存在于运行阶段。在编译后的 class 文件中,是没有泛型这个概念的。
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。

泛型通配符

泛型通配符
1.无边界通配符

<?> 通用的类型
public class Demo02 {
    
    
public static void main(String[] args) {
    
    
List<String> list1 = new ArrayList<>();
list1.add("111");
list1.add("222");
list1.add("333");
loop(list1);
}

public static void loop(List<?> list){
    
    
for (int i = 0; i < list.size() ; i++) {
    
    
System.out.println(list.get(i));
}
}
}

2.上边界通配符

< ? extends Number > 代表从Number往下的子类货孙类对象都可以使用

public class Demo03 {
    
    
public static void main(String[] args) {
    
    
List<String> list1 = new ArrayList<>();
list1.add("111");
list1.add("222");
list1.add("333");
// loop(list1);
List<Number> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
}
/**
* ? extends Number
* 通用的类型必须是Number及其子类
* @param list
*/
public static void loop(List<? extends Number> list){
    
    
for (int i = 0; i < list.size() ; i++) {
    
    
System.out.println(list.get(i));
}
}

3.下边界通配符

<? super Integer> 代表从Integer 到Object所有的对象都可以

public class Demo04 {
    
    
public static void main(String[] args) {
    
    
List<String> list1 = new ArrayList<>();
list1.add("111");
list1.add("222");
list1.add("333");
loop(list1);
List<Number> list2 = new ArrayList<>();
list2.add(1);
list2.add(2);
list2.add(3);
loop(list2);
}

/**
* ? super Number
* 通用类型必须是Integer 到Object类型的对象
* @param list
*/
public static void loop(List<? super Number> list){
    
    
for (int i = 0; i < list.size() ; i++) {
    
    
System.out.println(list.get(i));
}
}
}

泛型类、方法、接口使用

泛型的前提是使用前声明
泛型的声明是通过"<>"实现
约定泛型可以使用单个大写字母来表示 K E T V 等

泛型类

public class PersonNew <T> {
    
    

private T t;

public T getT() {
    
    
return t;
}

public void setT(T t) {
    
    
this.t = t;
}

public PersonNew(T t) {
    
    
this.t = t;
}
}

增加我们代码的灵活度

泛型方法

public class Demo07 <K,V> {
    
    

/**
* 普通方法 可以使用 类中定义的泛型
* @param k
* @param v
* @return
*/
public K method1(K k,V v){
    
    
return (K)null;
}

/**
* 普通方法 使用方法中自己定义的泛型,此时的T与类的T类型可以相同,可以不同
* @param t
* @param v
* @param <T>
* @return
*/
public <T> T method2(T t,V v){
    
    
return (T)null;
}

/**
* 在静态方法中我们没法使用 类中定义的泛型
* @return
*/
public static <K> K method3(){
    
    
return null;
}

静态方法与泛型
静态方法有一种情况需要注意一下,那就是在类中的静态方法使用泛型:静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。
即:如果静态方法要使用泛型的话,必须将静态方法也定义成泛型方法 。

public class StaticGenerator<T> {
    
    
/**
* 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法)
* 即使静态方法要使用泛型类中已经声明过的泛型也不可以。
* 如:public static void show(T t){..},此时编译器会提示错误信息:
"StaticGenerator cannot be refrenced from static context"
*/
public static <T> void show(T t){
    
    

}
}

泛型类,是在实例化类的时候指明泛型的具体类型;
泛型方法,是在调用方法的时候指明泛型的具体类型 。

泛型接口

public interface CalGeneric <T> {
    
    

T add(T a,T b);

T sub(T a,T b);

T mul(T a,T b);

T div(T a,T b);
}

public class CalIntegerGeneric implements CalGeneric<Integer> {
    
    
@Override
public Integer add(Integer a, Integer b) {
    
    
return null;
}

@Override
public Integer sub(Integer a, Integer b) {
    
    
return null;
}

@Override
public Integer mul(Integer a, Integer b) {
    
    
return null;
}

@Override
public Integer div(Integer a, Integer b) {
    
    
return null;
}
}

猜你喜欢

转载自blog.csdn.net/weixin_42371621/article/details/109148387