设计目的
当我们将一个对象放入集合中,集合不会记住此对象的类型,
当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型
取出集合元素时需要人为的强制类型转化到具体的目标类型,强转的时候容易报错"java.lang.ClassCastException"
引出泛型
使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不会出现“java.lang.ClassCastException”异常呢
字母代表规则
一般Java中,使用变量E表示集合元素类型。K表示关键字,V表示值。T(或者U、S)表示"任意类型"。
类型
1.集合中用到泛型
Map<String, Integer> hm = new HashMap<String, Integer>();
List<String> list = new ArrayList<String>();
2.类中用到泛型
2.1成员变量可以使用泛型
/**
* @description: ${description}
* @create: 2019-02-16
* 泛型类
* 用在成员变量上,只能使用引用类型
**/
public class Lottery<T> {
private T number;
public Lottery(T number) {
this.number = number;
}
public T getNumber() {
return number;
}
public void setNumber(T number) {
this.number = number;
}
public static void main(String[] args) {
Lottery<String> lottery1=new Lottery<String>("123abc");
Lottery<Integer> lottery2=new Lottery<Integer>(123);
System.out.println(lottery1.getNumber());
lottery2.setNumber(456);
System.out.println(lottery2.getNumber());
}
}
运行结果:
2.2类中方法的参数或者返回值可以使用泛型
package fanxing;
/**
* @description: ${description}
* @create: 2019-02-17
**/
public class Iphone<K,V>{
void method1(K k){
System.out.println(k.toString());
}
V method2(V v){
return v;
}
K method3(String s){
System.out.println(s.length());
return (K) (s+s);
}
public static void main(String[] args) {
Iphone<String,Integer> iphone6=new Iphone<>();
iphone6.method1("kakaka");
Integer integer = iphone6.method2(9999);
System.out.println(integer);
String s = iphone6.method3("6666");
System.out.println(s);
}
}
运行结果:
3.接口使用泛型
3.1接口
public interface Fruit <T> {
public T get();
}
3.2接口的实现类1
public class PriceFruit implements Fruit<Integer> {
@Override
public Integer get() {
return 666;
}
}
3.3接口的实现类2
public class RedFruit implements Fruit<String> {
@Override
public String get() {
return "red apple";
}
}
4泛型方法
普通方法、构造方法和静态方法中都可以使用泛型
package fanxing;
/**
* @description: ${description}
* @create: 2019-02-17
**/
public class Swap {
static <T> void swap(T[] a,int i,int j){
T temp=a[i];
a[i] = a[j];
a[j]=temp;
}
public static void main(String[] args) {
Swap s=new Swap();
String[] a1={"a","b","c","d"};
s.swap(a1,1,2);
for (String string:a1
) {
System.out.print(string+" ,");
}
System.out.println();
Integer[] a2={1,2,3,4,5,6};
s.swap(a2,1,2);
for (Integer i:a2
) {
System.out.print(i);
}
}
}
运行结果:
知识点记忆
1,泛型通配符
使用"?“通配符可以引用其他各种参数化的类型,”?"通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
例:Collection<?>可以适配Collection、Collection或Collection等
2,限定通配符的上边界
用于匹配Number及Number的子类
<? extends Number>
3,限定通配符的下边界
//用于匹配Integer及Integer的父类。
<? super Integer>
4,Java 中的泛型基本上是在编译器中实现。编译器进行执行类型检查和类型推断,然后生成普通的非泛型的字节码。编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除。这种实现技术称为擦除(erasure)
5,泛型实际是提供给Javac编译器使用的。限定输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉"类型"信息。程序运行期间,没有任何泛型泛型的痕迹。使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样
6,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段
7,Java中没有所谓的泛型数组一说