泛型
//不能new泛型类型的数组
T[] t = new T[5];//这是错误的
//但是可以new一个Object的,然后强制类型转换,但是这样子并不好
T[] t = (T[])new Object[5];
class MyArray<T> {
public T[] array = (T[])new Object[10];
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos, T val) {
this.array[pos] = val;
}
}
public class Test {
public static void main(String[] args) {
MyArray<Integer> myArray = new MyArray<Integer>();//后面的这个<Integer>可以省略,叫做类型推倒
myArray.setVal(0,10);
myArray.setVal(1,20);
myArray.setVal(2,30);
System.out.println(myArray.getPos(1));
}
}
泛型可以有很多个:
class MyArray<T, E, P> {
//只要在里面加逗号就行,在构造出来的时候也要对应的有多少种类型。
}
- 裸类型
MyArray list = new MyArray();
我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制
小结:
- 泛型是将数据类型参数化,进行传递
- 使用 表示当前类是一个泛型类。
- 泛型目前为止的优点:数据类型参数化,编译时自动进行类型检查和转换
官方用法
public Object[] obj = new Object[3];
public E getPos2(int pos) {
return (E)obj[pos];
}
- 反射(说明了为什么不能实现泛型类型数组)
import java.util.Arrays;
class MyArray1<T> {
public T[] array = (T[])new Object[10];
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos, T val) {
this.array[pos] = val;
}
public Object[] getArray() {
return array;
}
}
public class Test1 {
public static void main(String[] args) {
MyArray1<Integer> myArray = new MyArray1<>();
myArray.setVal(0,10);
myArray.setVal(1,20);
myArray.setVal(2,30);
Integer[] integer = (Integer[])myArray.getArray();
System.out.println(Arrays.toString(integer));
}
}
//Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
原因:替换后的方法为:将Object[]分配给Integer[]引用,程序报错
通俗讲就是:返回的Object数组里面,可能存放的是任何的数据类型,可能是String,可能是Person,运行的时候,直接转给Integer类型的数组,编译器认为是不安全的
需要改为:
import java.lang.reflect.Array;
import java.util.Arrays;
class MyArray1<T> {
public T[] array;
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos, T val) {
this.array[pos] = val;
}
public Object[] getArray() {
return array;
}
public MyArray1() {
}
public MyArray1(Class<T> clazz, int capacity) {
array = (T[])Array.newInstance(clazz, capacity);
}
}
public class Test1 {
public static void main(String[] args) {
MyArray1<Integer> myArray = new MyArray1<>(Integer.class, 10);
myArray.setVal(0,10);
myArray.setVal(1,20);
myArray.setVal(2,30);
Integer[] integer = (Integer[])myArray.getArray();
System.out.println(Arrays.toString(integer));
}
}
//[10, 20, 30, null, null, null, null, null, null, null]
- 泛型的上界
class Alg<E extends Comparable<E>> {
public E findMax(E[] array) {
E max = array[0];
for(int i = 1; i < array.length;i++) {
if(max.compareTo(array[i]) < 0 ) {
max = array[i];
}
}
return max;
}
}
泛型方法:
public <E extends Comparable<E>> E findMax(E[] array) {
E max = array[0];
for(int i = 1; i < array.length;i++) {
if(max.compareTo(array[i]) < 0 ) {
max = array[i];
}
}
return max;
}
泛型进阶
<>当中的数据类型 不参与类型的组成 JVM当中没有泛型的概念 泛型 只存在于编译阶段,通过擦除机制
在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制
比如我们看一下ArrayList源码中:
它定义了一个Object类型的数组,包括它new的时候都是new一个Object的数组
那么它是怎么搞成泛型的呢?我们看一下它在add方法的技巧:
get返回了E类型的,再看一下elementData中的源码:
我们知道了它把elementData数组的类型强制转换成了E类型的,这种是官方的写法,也是最标准的写法
泛型的上界
public class MyArray<E extends Number>
//这里的E只能是Number或者是Number的子类,比如Integer就行,而String就不行
public class MyArray<E extends Comparable<E>>
//这里的E必须要是实现了Comparable接口的
通配符
class Message<T> {
private T massage;
public T getMassage() {
return massage;
}
public void setMassage(T massage) {
this.massage = massage;
}
}
public class Test {
public static void main(String[] args) {
Message<String> message = new Message<>();
message.setMassage("欢迎进入字节跳动!");
func(message);
Message<Integer> message1 = new Message<>();
message1.setMassage(111);
func(message1);
}
private static void func(Message<?> message) {//假设这里没有用通配符而是用泛型,在message1 会报错,因为指定了用String
//message.setMassage("字节跳动"); 类型不能确定,无法设置 无法修改
System.out.println(message.getMassage());
}
}
- 通配符的上界
<? extends 上界>
<? extends Number>//可以传入的实参类型是Number或者Number的子类
<? super 下界>
<? super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类类型
class Food {
}
class Fruit extends Food {
}
class Apple extends Fruit {
}
class Banana extends Fruit {
}
class Plate<T> {
private T message;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Test1 {
public static void main(String[] args) {
Plate<Fruit> fruitPlate = new Plate<>();
fruitPlate.setMessage(new Fruit());
func2(fruitPlate);
Plate<Food> foodPlate = new Plate<>();
foodPlate.setMessage(new Food());
func2(foodPlate);
}
//泛型的下界:传进来的是Fruit和Fruit的父类,所以你既然传了父类或者它自己
//那么它的子类就可以进行修改
public static void func2(Plate<? super Fruit > tmp) {
tmp.setMessage(new Apple());
tmp.setMessage(new Banana());
//Fruit fruit = tmp.getMessage(); 这里因为你不知道传进来的是哪个父类,所以不能接收,只能直接打印结果
System.out.println(tmp.getMessage());
}
public static void main1(String[] args) {
Plate<Apple> applePlate = new Plate<>();
applePlate.setMessage(new Apple());
func1(applePlate);
Plate<Banana> bananaPlate = new Plate<>();
bananaPlate.setMessage(new Banana());
func1(bananaPlate);
}
//泛型的上界:传进来的可以是Fruit和Fruit的子类,所以下面那里不知道传进来的是Apple还是Banana等
//所以不能进行修改
public static void func1(Plate<? extends Fruit> tmp) {
//这里仍然不可以进行修改!
Fruit fruit = tmp.getMessage();
System.out.println(tmp.getMessage());
}
}