什么是泛型
定义
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参列表,普通方法的形参列表中,每个形参的数据类型是确定的,而变量是一个参数。在调用普通方法时需要传入对应形参数据类型的变量(实参),若传入的实参与形参定义的数据类型不匹配,则会报错。
定义的语法结构
class 类名称 <泛型标识、泛型标识,...> {
private 泛型标识 变量名;
......
}
语法创建对象方式
类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();
注意事项!
- 泛型类,如果没有指定具体的数据类型,此时,操作类型是Object
- 泛型的类型参数只能是类类型,不能是基本数据类型
- 泛型类型在逻辑上可以看成是多个不同的类型,但实际上是相同类型
使用
(1)类型参数用于类的定义中,则该类被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map等。
(2)泛型类中的静态方法和静态变量不可以使用泛型类所声明的类型参数
(3)静态泛型方法中可以使用自身的方法签名中新定义的类型参数(即泛型方法,后面会说到),而不能使用泛型类中定义的类型参数。
(4)泛型类不只接受一个类型参数,它还可以接受多个类型参数。
/**
* 泛型类的定义
* @param <T> 泛型标识-----类型形参
* T 创建对象的时候里面具体制定的数据类型
*/
public class Generic<T> {
// T 是由外部使用类的时候来指定的。
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
@Override
public String toString() {
return "Generic{" +
"key=" + key +
'}';
}
}
语法介绍
在创建泛型类的对象时,必须指定类型参数 T 的具体数据类型,即尖括号 <> 中传入的什么数据类型,T 便会被替换成对应的类型。如果 <> 中什么都不传入,则默认是 < Object >。
public static void main(String[] args) {
// 泛型类在创建对象的时候来指定操作的具体数据类型
Generic<String> stringGeneric = new Generic<>("a");
String key = stringGeneric.getKey();
System.out.println("key:" + key);
System.out.println("------------------------");
Generic<Integer> integerGeneric = new Generic<>(100);
Integer key1 = integerGeneric.getKey();
System.out.println("key1:"+key1);
// 总结:泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。
System.out.println("----------注意点1:--------------");
// 泛型类在创建对象的时候,没有指定泛型类,将按照Object类型来操作
Generic generic = new Generic("ABC");
Object key3 = generic.getKey();
System.out.println("key3:"+key3);
System.out.println("----------注意点2:--------------");
// 泛型类不支持基本数据类型,原因就是我们在编译期间会将这个 T 编译成 Object
// 基本数据类型无法转化为 object类型
// Generic<int> intGeneric = new Generic<>(100);
System.out.println("----------注意点3:--------------");
// 同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型
System.out.println(integerGeneric.getClass() == stringGeneric.getClass());
}
java 中泛型标记符
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
特点
泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。
泛型类在创建对象的时候,没有指定泛型类,将按照Object类型来操作
泛型类不支持基本数据类型,原因就是我们在编译期间会将这个 T 编译成 Object
同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型
抽奖器示例
public class ProductGetter<T> {
//奖金或者奖品
private T product;
// 定义奖品、奖金池
ArrayList<T> arrayList = new ArrayList<>();
// 添加奖品到奖品池
public void addProduct(T t){
arrayList.add(t);
}
// 定义一个随机数,用来抽选奖品
Random random = new Random();
//抽奖
public T getProduct(){
product = arrayList.get(random.nextInt(arrayList.size()));
return product;
}
}
public static void main(String[] args) {
ProductGetter<String> stringProductGetter = new ProductGetter<>();
String[] strPro = {"苹果手机","华为手机","扫地机器人","咖啡机"};
//将奖品放入奖金池
for (int i = 0;i< strPro.length;i++){
stringProductGetter.addProduct(strPro[i]);
}
String product = stringProductGetter.getProduct();
System.out.println("恭喜您抽中了:"+product);
System.out.println("******************************");
ProductGetter<Integer> IntegerProductGetter = new ProductGetter<>();
Integer[] intPro = {100,1000,10000,20000};
//将奖品放入奖金池
for (int i = 0;i< intPro.length;i++){
IntegerProductGetter.addProduct(intPro[i]);
}
Integer product1 = IntegerProductGetter.getProduct();
System.out.println("恭喜您,获的了:"+product1+"元");
}
三、从泛型类派生子类(2种情况)
子类也是泛型类,子类和父类的泛型类型要保持一致
class ChildGeneric<T> extends Generic<T>
子类不是泛型类,父类要明确泛型类的数据类型
class ChildGeneric extends Generic<String>
第一种情况:子类和父类的泛型类型要保持一致
父类没有指定数据类型时默认为obj
定义父类
public class Parent<E> {
private E value;
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
定义子类
/**
* 泛型类派生子类,如果子类也是泛型类,子类的泛型标识要和父类一致。
* @param <T>
*/
public class ChildFirst<T> extends Parent<T> {
@Override
public T getValue() {
return super.getValue();
}
测试类
public static void main(String[] args) {
ChildFirst<String> childFirst = new ChildFirst<>();
childFirst.setValue("123");
String value = childFirst.getValue();
System.out.println(value);
}