1.泛型简介
泛型是参数化类型
public class MyArrayList<E> {
private E[] array;
private int size;
...
}
- 尖括号 <> 是泛型的标志;
- E 是类型变量,变量名一般要大写;
- 数据类型E被指定为一个参数,代表最终传入的类型,在用到的时候再指定具体类型;
泛型可以用在类、方法、接口的创建中,分别称为泛型类、泛型接口、泛型方法;
泛型的类型传入的只能是引用类型,不能是基本类型;
2.泛型特点和作用时期
- Java中的泛型只是在编译期间起作用的,在运行期间会把泛型信息擦除;
- 只在编译期间启动类型安全检查的作业,在运行时不起作用;
List<String> list = new ArrayList<String>();
//这里指定了泛型String,但在运行时依然可向该List中存放其他类型数据
3.泛型的好处
MyArrayList<Book> books = new MyArrayList<Book>();
books.add(new Book());
// 会产生编译错误,Person 类型无法转换为 Book 类型
books.add(new Person());
// 不需要做类型转换
Book book = book.get(0);
// 不需要做类型转换,会产生编译错误,Book 类型无法转换为 Person 类型
Person person = book.get(0);
如果没有定义泛型,则需要强制类型转换,但有可能编译成功,运行时出错!
例如:
// 这里类型转换在编译时正确,但运行时会抛出异常 ClassCastException
Person person = (Person)books.get(0);
编译期间的问题只会让开发者感觉到,运行期间的错误会让所有的软件使用者
承受错误风险;
泛型是为了解决在数据装入集合时的类型都被当做Object对待从而失去本身特有的类型,从集合里读取时还需要强制转换,java在编译期间就能确定一个对象的类型,强制类型转换在编译期间不会有问题,而在运行期间有可能导致错误,而这个错误编译器无法预测;
所以泛型的好处就在于:
1.类型安全,主要实现Java的类型安全,泛型可以使编译器知道一个对象的限定类型,在编译期间进行类型安全检查;
2.消除了强制转换,使代码可读性更好,减少出错;
总结泛型
- 泛型是为了解决某些容器、算法等代码的通用性而引入,并且能在编译期间做类型安全检查,消除了强制转换;
- 泛型利用的是 Object 是所有类的祖先类,并且父类的引用可以指向子类对象的特点而工作;
- 泛型是一种编译期间的机制,在运行期间会把泛型信息擦除;
关于包装类
为什么要有包装类?
- 包装类可以定义泛型参数,而基本数据类型不可以,将泛型改为基本数据类型编译器就会报错
因为泛型在编译后会被类型擦除为Object类,而Object不能存储基本数据类型; - 包装类拥有一些有用的方法(类型转换方法如parseInt)
- 在程序中,有些结果可能会返回空值,转化为基本数据类型如 int 就会发生异常,因为基本数据类型是没有 null 值的,而基本数据类型对应的如 Integer 包装类类型的对象可以为 null 值;
- 包装类天然继承了Serializable(空接口),所以可以实现序列化和反序列化;
- 所以java 引入了一类特殊的类,即这 8种基本数据类型的包装类,在使用过程中,会将例如 int 这样的值包装到一个对象中去;
基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
包装类中属性和方法都是静态的;
例如:Integer.MAX_VALUE
自动装箱和自动拆箱
int i =1;
Integer a =i;//自动装箱,把字面值为1的变量i包装成Integer类型对象
//自动拆箱,把Integer对象转变为一个int类型值
int b = new Integer(i);
int c = a;
自动装箱和自动拆箱是工作在编译期间的一种机制;
当向泛型参数为 Integer 的 ArrayList 添加 int 值时,便需要用到自动装箱了
既然泛型会被类型擦除,我们还有必要用它吗?
Java 编译器可以根据泛型参数判断程序中的语法是否正确。尽管经过类型擦除后,ArrayList.add 方法所接收的参数是 Object 类型,但是往泛型参数为 Integer 类型的 ArrayList 中添加字符串对象,Java 编译器是会报错的。