因为JAVA中假如构建了一个object集合,在集合里存储任何的数据类型对象,定义了一个字符串,又定义一个常数。呢么在遍历数组Arraylist的时候,在代码行里并不会报错,但是运行之后会出现ClassCastException异常。
JAVA泛型提供了编译时类型安全检测机制,在代码行里就可以看到报错啦,能够检测到非法的类型数据结构,而不是在运行才能看到。
泛型的本质就是参数化类型,也就是所操作的数据类型是指定为一个参数。
得到代码的复用
class 类名称 <泛型标识,泛型标识,...> {private 泛型标识 变量名;......
}
常用的泛型标识:T,E,K,V,N
T - Type(Java 类)
E - Element (在集合中使用,因为集合中存放的是元素)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的 java 类型
使用语法
类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>();
Java1.7之后,后面的<>中的具体的数据类型可以省略不写
类名<具体的数据类型> 对象名 = new 类名<>();
泛型类的定义
package demo1;/*** 泛型类的定义* @param 泛型标识-类型形参* T 创建对象的时候里指定具体的数据类型*/
public class Generic {
// T是由外部使用类的时候来指定的private T key;public Generic(T key) {this.key = key;}public T getKey() {return key;}public void setKey(T key) {this.key = key;}public String toString() {return "Generic{" +"key=" + key +"}";}
}
泛型类
package demo1;public class MainClass {public static void main(String[] args) {//泛型类在创建对象的时候,来指定操作的具体数据类型。Generic strGeneric = new Generic<>("abc");String key1 = strGeneric.getKey();System.out.println("key1:" + key1);
输出结果:key1:abc
试一下定义integer型
Generic integerGeneric = new Generic<>(100);int key2 = integerGeneric.getKey();System.out.println("key2:" + key2);
运行得到
key1:abc
key2:100
泛型类注意:
泛型类,如果没有指定具体的数据类型,此时,操作类型是object
泛型的类型参数只能是类类型,不能是基本数据类型(不能用int,用interger)
泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同的类型。
第三条难理解的话 上代码
System.out.println(intGeneric.getClass());System.out.println(strGeneric.getClass());
输出结果:
class demo1.Generic
class demo1.Generic
是一样的
从泛型类派生子类
子类也是泛型类,子类和父类的泛型类型要一致。
class ChildGeneric extends Generic
子类不是泛型类,父类要明确泛型的数据类型。
class ChildGeneric extends Generic
第一种情况
泛型类派生子类,子类也是泛型类,呢么子类的泛型式表示要和父类一致
父类
package demo2;public class Parent {private E value;public E getValue() {return value;}public void setValue(E value) {this.value = value;}
}
子类
package demo2;public class ChildFilrst extends Parent {public T getValue(){return super.getValue();}}
主类
package demo2;public class TEST {public static void main(String[] args) {ChildFilrst childFilrst = new ChildFilrst<>();childFilrst.setValue("abc");String value = childFilrst.getValue();System.out.println(value);}
}
运行得到 abc
第二种情况
泛型类派生子类,如果子类不是泛型类,呢么父类要明确数据类型
ChildSecond childSecond = new ChildSecond();childSecond.setValue(100);Integer value1 =childSecond.getValue();System.out.println(value1);
定义语法
interface 接口名称 <泛型标识,泛型标识,...> {泛型标识 方法名();......
}
泛型接口的使用
实现类不是泛型类,接口要明确数据类型
实现类也是泛型类,实现类和接口的泛型类型要一致。
第一种
实现泛型接口的类,不是泛型类,需要明确实现泛型接口的数据类型
这里Test类不是泛型类,所以要明确泛型接口的数据类型 这里定义T是String类型
public class Test extends Generator {
实现类
package demo3;public class Test extends Generator {public String getKey() {return "hello generic";}
}
泛型接口类
package demo3;/*** 泛型接口*/public class Generator {T getKey() {return null;}
}
主类
package demo3;public class main {public static void main(String[] args) {Test test = new Test();String key = test.getKey();System.out.println(key);}
}
运行得到
hello generic
泛型接口的实现类,是一个泛型类,呢么要保证实现接口的泛型类的泛型标识包含泛型接口的泛型标识
实现类Test1
package demo3;public class Test1 extends Generator {private T key;public Test1(T key) {this.key = key;}public T getKey() {return key;}}
主类
Test1 test1 = new Test1<>("generic");String key1 = test1.getKey();System.out.println(key1);}
}
输出 generic
泛型类:是在实例化类的时候指明泛型的具体类型
泛型方法:是在调用方法的时候指明泛型的具体类型
语法
修饰符 返回值类型 方法名(形参列表) {方法体...
}
public 与返回值中间 非常重要,可以理解为声明此方法为泛型方法。
只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法
表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T,E,K,V等形式的参数常用于表示泛型,
Test.java
package demo4;import java.util.ArrayList;public class Test {public static void main(String[] args) {ProductGetter productGetter = new ProductGetter<>();ArrayList strList = new ArrayList<>();strList.add("电脑");strList.add("手机");strList.add("机器人");//泛型方法的调用,类型是通过调用方法的时候来指定。String product1 = productGetter.getProduct(strList);System.out.println(product1 + "\t" + product1.getClass().getSimpleName());}
}
package demo4;import java.util.ArrayList;
import java.util.Random;public class ProductGetter {static Random random = new Random();//奖品private T product;//奖品池ArrayList list = new ArrayList<>();/*** 添加奖品*/public void addProduct(T t) {list.add(t);}/*** 抽奖*/public T getProduct() {product = list.get(random.nextInt(list.size()));return product;}/*** 定义泛型方法* list 参数* 泛型标识,具体类型由调用方法的时候来指定*/public E getProduct (ArrayList list) {return list.get(random.nextInt(list.size()));}}
运行得到:
电脑 String
java类里面的泛型和方法里面的泛型是完全无关的,
java类里的泛型假如是T ,而方法里的也是T
public T getProduct (ArrayList list) {return list.get(random.nextInt(list.size()));
在这里定义了T已经是integer类型
ProductGetter productGetter = new ProductGetter<>();
但是运行没有变化
即使定义泛型标识的名字和泛型类里面的标识是相同的,但是在使用上,我们泛型方法里面的泛型和泛型类里的泛型是没有任何关系的,是独立存在的。
泛型方法与可变参数
泛型可变参数的定义
public void print(E... e) {for (E el : e) {System.out.println(e);}
}
/*** 泛型可变参数的定义*/public static void print(E... e) {for(int i = 0; i < e.length; i++ ) {System.out.println(e[i]);}}
productGetter.print(1,2,3,4,5);productGetter.print("a","b","c");
泛型方法总结
泛型方法能使方法独立于类而产生变化
如果static方法要使用泛型能力,就必须使其成为泛型方法。
类型通配符一般是使用"?"代替具体的类型实参。
所以,类型通配符是类型实参,而不是类型形参。
Test.java
package demo5;public class Test {public static void main(String[] args) {Box box1 = new Box<>();box1.setFirst(100);showBox(box1);Box box2 = new Box<>();box2.setFirst(200);showBox(box2);}public static void showBox(Box box) {Number first = box.getFirst();System.out.println(first);}
}
Box,java
package demo5;public class Box {private E first;public E getFirst() {return first;}public void setFirst (E first) {this.first = first;}
}
我们这里
public static void showBox(Box box) {
定义的是number类型,在第二条
Box box2 = new Box<>();
咱们用的是Integer类型
所以出现了报错 呢么怎么办呢?
引用了类型通配符
public static void showBox(Box> box) {
语法
类/接口 extends 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的子类类型。
public static void showBox(Box extends Number> box) {Number first = box.getFirst();System.out.println(first);
决定了最大上限只能是Number
类/接口 super 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的父类类型。
public static void showBox(Box super Number> box) {Object first = box.getFirst();System.out.println(first);
这里定义类型只能是Object,不能是Number。不然会报错(因为super定义了下限。)
Super叫做下限,因为要从指定的参数往上看
extends叫做上限,因为要从参数往下看
集合比较器用super,因为确定了所有类型不可能超过已经规定的类型,保证安全地比较。
上一篇:数据分析经典算法——红黑树