写在前面
部分知识点来源于https://blog.csdn.net/s10461/article/details/53941091
泛型
例子
List arrayList = new ArrayList();
arrayList.add("aaaa");
arrayList.add(100);
for(int i = 0; i< arrayList.size();i++){
String item = (String)arrayList.get(i);
}
程序的运行结果会以崩溃结束:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
ArrayList可以存放任意类型,目前可以统一都是按照String类型进行操作,所以报错了,为了在编译阶段就可以解决这样的问题,泛型应运而生。
特性
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
Class classStringList = stringList.getClass();
Class classIntegerList = integerList.getClass();
System.out.println(classStringList+"====="+classIntegerList);
//class java.util.ArrayList=====class java.util.ArrayList
通过上面的例子可以证明,在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
泛型是jdk1.5使用的新特性,泛型的好处:
- 将运行时的异常提前至了编译时。
- 避免了无谓的强制类型转换 。
注意:
- 泛型没有多态的概念,左右两边的数据 类型必须 要一致,或者只是写一边的泛型类型,推荐使用: 两边都写泛型。
- 在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型。
泛型在集合中的常见应用:
ArrayList<String> list = new ArrayList<String>(); //正确 推荐使用。
ArrayList<Object> list = new ArrayList<String>(); //错误
ArrayList<String> list = new ArrayList<Object>(); //错误
//以下两种写法主要是为了兼顾新老系统的兼用性问题。
ArrayList<String> list = new ArrayList(); //正确
ArrayList list = new ArrayList<String>(); //正确
自定义泛型
自定义泛型: 自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量。
方法上自定义泛型
修饰符 <声明自定义的泛型>返回值类型 函数名(使用自定义泛型 …){
}
注意的事项:
1. 自定义函数泛型中具体类型的确认实在该函数被调用时所传递实参类型来决定的。
2. 自定义泛型只要符合标识符的命名规则即可, 但是自定义泛型我们一般都习惯使用一个大写字母T表示。
class Demo1{
public <T> T getData(T t){
return t;
}
}
public class Test {
public static void main(String[] args) {
String str = new Demo1().getData("abc");
System.out.println(str);
}
}
类上自定义泛型
格式:
class 类名<声明自定义泛型>{
}
class Demo2<T>{
public <T> T[] reverse(T[] t){
for (int start = 0, end = t.length-1; start < end; start++,end--){
T temp = t[start];
t[start] = t[end];
t[end] = temp;
}
return t;
}
/**
* 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法)
* 即使静态方法要使用泛型类中已经声明过的泛型也不可以。
* 如:public static void show(T t){..},此时编译器会提示错误信息:
"StaticGenerator cannot be refrenced from static context"
*/
public static <A> A[] staticReverse(A[] a){
for (int start = 0, end = a.length-1; start < end; start++,end--){
A temp = a[start];
a[start] = a[end];
a[end] = temp;
}
return a;
}
}
public class Test {
public static void main(String[] args) {
String str[] = {"1","2","3","4","5"};
Demo2<String> stringDemo2 = new Demo2<>();
stringDemo2.reverse(str);
for (String value:str) {
System.out.println(value);
}
}
}
泛型类要注意的事项:
-
自定义泛型类中具体的数据类型是在该类创建时来确认的,且如果创建对象的时候没有指定泛型的具体数据类型,那么默认为Object类型。
-
静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上
接口上自定义泛型
泛型接口的定义格式:
interface 接口名<声明自定义泛型>{
}
如果要延长接口自定义泛型 的具体数据类型,那么格式如下:
public class 类名 implements 接口名{
}
注意的事项:
- 自定义泛型接口的具体数据类型是在该接口被实现的时候指定的。
- 在接口上自定义的泛型如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型。
class Student{
}
interface Dao<T>{
public void add(T t);
}
class StudentDao implements Dao<Student>{
@Override
public void add(Student student) {
System.out.println("学生被添加");
}
}
public class Test {
public static void main(String[] args) {
StudentDao studentDao = new StudentDao();
studentDao.add(new Student());
}
}
泛型的上限与下限
泛型中通配符: ?
? super Integer : 只能存储Integer或者是Integer父类元素。 泛型 的下限
? extends Number : 只能存储Number或者是Number类型的子类数据。 泛型上限
public class Demo5 {
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Number> list2 = new ArrayList<Number>();
HashSet<String> set = new HashSet<String>();
//getData(set);
}
//泛型的上限
public static void getData(Collection<? extends Number> c){
}
//泛型的下限
public static void print(Collection<? super Integer> c){
}
}