196 lines
5.3 KiB
Markdown
196 lines
5.3 KiB
Markdown
# 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>());
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|