# 11.泛型

## 11.1 什么是泛型

> 泛型，即“参数化类型”。一提到参数，最熟悉的就是定义方法时有形参，然后调用此方法时传递实参。那么参数化类型怎么理解呢？顾名思义，就是将类型由原来的具体的类型参数化，类似于方法中的变量参数，此时类型也定义成参数形式（可以称之为类型形参），然后在使用/调用时传入具体的类型（类型实参）。
>
> 泛型的本质是为了参数化类型（在不创建新的类型的情况下，通过泛型指定的不同类型来控制形参具体限制的类型）。也就是说在泛型使用过程中，操作的数据类型被指定为一个参数，这种参数类型可以用在类、接口和方法中，分别被称为泛型类、泛型接口、泛型方法。



首先来看一个例子

```java
import java.util.ArrayList;
import java.util.List;

public class test {

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("string");
        list.add(100);

        for (int i = 0; i < list.size(); i++) {
            String name = (String) list.get(i); // 1
            System.out.println("name:" + name);
        }
    }
}
```

上述代码会出现 **Exception in thread "main" java.lang.ClassCastException** 错误

ArrayList由String类型和Integer类型，而两者都以String格式使用，所以出现了上述错误。

这个时候就用得上泛型了

```java
import java.util.ArrayList;
import java.util.List;

public class test {

    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();
        list.add("string");
        list.add(100);   

        for (int i = 0; i < list.size(); i++) {
            String name = list.get(i); // 2
            System.out.println("name:" + name);
        }
    }
}
```

上述代码会编译错误，如果使用idea的话，会出现下述错误提示

```
java: 对于add(int), 找不到合适的方法
    方法 java.util.Collection.add(java.lang.String)不适用
      (参数不匹配; int无法转换为java.lang.String)
    方法 java.util.List.add(java.lang.String)不适用
      (参数不匹配; int无法转换为java.lang.String)
```

这里通过List\<String\>限定了集合内的元素只能是String类型。

泛型使得代码可以被不同类型的对象重用



## 11.2 泛型类

一个泛型类就是拥有一个或者多个类型变量的类。下面看一个简单例子：

```java
public class test {

    public static class Point<T> {
        private T var;

        public void setVar(T x) {
            this.var = x;
        }

        public T getVar() {
            return this.var;
        }

    }

    public static void main(String[] args){
        Point<Float> p = new Point<Float>() ;
        p.setVar(new Float(100.12f)) ;
        System.out.println(p.getVar());
    }

}
```

括号里面的T，是形式类型参数，可以随意指定，当类被使用的时候，就会使用具体的实际类型参数。

需要注意的是，泛型类只能用在成员变量上，并且只能使用引用类型。



## 11.3 泛型方法

下面是定义泛型方法的规则：

- 所有泛型方法声明都有一个类型参数声明部分（由尖括号分隔），该类型参数声明部分在方法返回类型之前
- 每一个类型参数声明部分包含一个或多个类型参数，参数间用逗号隔开。一个泛型参数，也被称为一个类型变量，是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型，并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型，不能是原始类型（像int,double,char的等）。



```java
public class MethodTest {
	int var = 100;
    String varStr = "Hello Datawhale";
	public <T> T Method(T a) {
		return a;
	}
	public static void main(String[] args) {
		MethodTest t=new MethodTest();
		System.out.println(t.<Integer>Method(t.var));
		System.out.println(t.<String>Method(t.varStr));
	}
 

```



## 11.4 泛型接口



```java
class InfoImpl implements Info<String>{   // 定义泛型接口的子类  
    private String var ;                // 定义属性  
    public InfoImpl(String var){        // 通过构造方法设置属性内容  
        this.setVar(var) ;  
    }  
    @Override  
    public void setVar(String var){  
        this.var = var ;  
    }  
    @Override  
    public String getVar(){  
        return this.var ;  
    }  
}  
  
public class GenericsDemo24{  
    public  void main(String arsg[]){  
        InfoImpl i = new InfoImpl("harvic");  
        System.out.println(i.getVar()) ;  
    }  
};  

```



## 11.5 类型通配符

类型通配符一般是在不确定具体参数时候，使用?代替。？表示未知类型，类型参数赋予不确定值，只能用在声明类型、方法参数上，不能用在定义泛型类上

```java
public class match {
 
  public static void test(List<?> list) {
 
   List<?> list2; 
   list2 = new ArrayList<String>();
   list2 = new ArrayList<Integer>();
   list2 = new ArrayList<Object>();
 
  }
 
  public static void main(String[] args) {
   test(new ArrayList<String>());
   test(new ArrayList<Integer>());
  }
 
}

```



