泛型是在JDK1.5引入的新的语法,泛型:就是适用于许多许多类型。从代码上讲,就是对类型实现了参数化。
类和接口总览
对类型实现了参数化,这是什么意思?
两个类之间可以转,但是两个数组之间不行。
class MyArray{
Object[] obj=new Object[10];
public void setVal(int pos,Object val){
obj[pos]=val;
}
public Object getPos(int pos){
return obj[pos];
}
}
public class Test {
public static void main(String[] args) {
MyArray myArray=new MyArray();
myArray.setVal(0,10);
myArray.setVal(1,"苹果");
myArray.setVal(2,10.5);
String str=(String) myArray.getPos(1);
}
可以发现:在存放元素的时候任何类型的元素都可以存放。但是在取出元素的时候要判断元素的类型(要强转).
class MyArray<T>{
//是占位符,表示当前类是泛型类
public T[] obj=(T[]) new Object[10];//这种写法是不太好的
public void setVal(int pos,T val){
obj[pos]=val;
}
public T getPos(int pos){
return obj[pos];
}
}
public class Test {
public static void main(String[] args) {
MyArray<Integer> myArray=new MyArray<Integer>();
myArray.setVal(0,10);
myArray.setVal(1,2);
myArray.setVal(2,6);
int a =myArray.getPos(1);//类型不用进行强转
}
总结一下:
泛型的作用:
1.存元素的时候进行类型检查
2.取出元素的时候不用强转
(编译的时候完成的)=>擦除机制
擦除机制
:在编译时期把T都擦除成了Object
public T[] obj=(T[]) new Object[10];//这种写法是不太好的
//原因:擦除机制使T->Object,如果写一个返回数组的方法,用一个Int[]类型数组接收,跟上面说的一样会报错。
//正确写法:
public MyArray(Class<T> clazz, int capacity) {
array = (T[])Array.newInstance(clazz, capacity);
}
//这样在存元素传入类型后擦除机制使T->指定的类型(非Object),这样数组之间转换就是正常的
T是一个引用类型,引用类型包括类、接口、委托和装箱值类型。
写一个泛型类,类中有一个泛型方法,可以求数组的最大值。
//传Integer类型
class Alg<T extends Comparable<T>>{
//Object类中没有Comparable接口,没有compareTo方法
public T findMax(T[] array){
T max=array[0];
for(int i=1;i< array.length;i++){
if(max.compareTo(array[i])<0){
//当传入Integer时,Integer中有compareTo方法,不用重写
max=array[i];
}
}
return max;
}
}
public static void main1(String[] args) {
Alg<Integer> alg=new Alg<>();
Integer[] arr={1,2,3,4};
Integer ret=alg.findMax(arr);
System.out.println(ret);
}
}
//传自定义类
class Person implements Comparable<Person>{
public int age;
public Person(int age) {
this.age = age;
}
@Override
public int compareTo(Person o) {
return this.age-o.age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
}
public static void main(String[] args) {
Alg<Person> alg=new Alg<>();
Person[] people={new Person(10),new Person(15)};
Person ret=alg.findMax(people);
System.out.println(ret);
}
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。
public class MyArray<E extends Number> {
//擦除成Number
...
}
只接受 Number 的子类型(包括Number)作为 E 的类型实参
class Alg2{
public static <T extends Comparable<T>>T findMax(T[] array){
T max=array[0];
for(int i=1;i< array.length;i++){
if(max.compareTo(array[i])<0){
max=array[i];
}
}
return max;
}
}
public class Test2 {
public static void main(String[] args) {
Integer[] arr={1,2,3,4};
Integer ret=Alg2.<Integer>findMax(arr); //可以省略,编译器可以根据传入的arr类型进行推导
System.out.println(ret);
}
}
class Message<T> {
private T message ;//消息
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Test {
public static void main1(String[] args) {
Message<String> message = new Message<>() ;
message.setMessage("比特就业课欢迎您");
fun(message);
}
public static void main(String[] args) {
Message<Integer> message = new Message<>() ;
message.setMessage(10);
fun(message);
}
public static void fun(Message<?> temp){
System.out.println(temp.getMessage());
//temp.setMessage(100); 无法修改!
}
通配符"?"可以接收所有的泛型类型,但是又不能够让用户随意修改。
extends Number>//可以传入的实参类型是Number或者Number的子类
class Food {
}
class Fruit extends Food {
}
class Apple extends Fruit {
}
class Banana extends Fruit {
}
class Plate<T> { // 设置泛型 shift+f6
private T plate ;
public T getPlate() {
return plate;
}
public void setPlate(T plate) {
this.plate = plate;
}
}
public static void main1(String[] args) {
Plate<Apple> plate1 = new Plate<>();
plate1.setPlate(new Apple());
fun1(plate1);
Plate<Banana> plate2 = new Plate<>();
plate2.setPlate(new Banana());
fun1(plate2);
}
public static void fun1(Plate<? extends Fruit> temp){
/*
不能放东西
temp.setPlate(new Apple());//如果里面是Banana不行
temp.setPlate(new Banana());//如果里面是Apple不行
temp.setPlate(new Fruit());//如果里面是Banana和Apple都不行,向下转型
*/
Fruit fruit = temp.getPlate();
}
通配符的上界,不能写入数据,只能读取数据。
super Integer>//代表 可以传入的实参的类型是Integer或者Integer的父类
可以写入数据,不能取数据
比如可以写入fruit的子类,不能取不知道用什么来接收。
基本类型->包装类型
Integer b=new Integer(1);
Integer c=2;
Integer d=Integer.valueOf(3);
包装类型->基本类型
Integer a=10;
int b=a;
int c=a.intValue();
Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b);
System.out.println(c == d);
//true
//false
装箱会调用valueOf方法