一、概述
1、概念:泛型就是参数化的类型,使用广泛的类型。
2、作用:
*安全:指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。
*省心:所有的类型转换都是自动的和隐式的,提高代码的重用率
二、泛型类
1、格式:< 字母列表>
class类名 <字母列表>{
修饰符 字母 属性;
修饰符 构造器 (字母){
}
修饰符 返回类型 方法名(字母){
}
字母列表中的每个字母都代表一种还未确定的引用类型(泛型是在使用时确定具体类型),可以使用任何字母表示,但为了规范使用,一般使用以下常见字母
T 表示Type即类型;
K 和V 分别表示键值中的key和Value
E 表示Element
? 表示不确定的类型(通配符)
2、泛型类在声明时使用泛型,不能将泛型字母使用在静态方法和静态属性上,因为泛型是在使用时确定具体类型,而static是在编译时确定。
3、泛型不能使用基本数据类型,必须使用引用类型,否则编译出错。
下面举一个泛型类的例子说明
public class Student<T1,T2> {
private T1 javaScore;
private T2 oracleScore;
//泛型声明时不能使用 静态属性|静态方法上
//private static T1 test;
public T1 getJavaScore() {
return javaScore;
}
public void setJavaScore(T1 javaScore) {
this.javaScore = javaScore;
}
public T2 getOracleScore() {
return oracleScore;
}
public void setOracleScore(T2 oracleScore) {
this.oracleScore = oracleScore;
}
public static void main(String[] args) {
//使用时指定类型(引用类型)
Student<String,Integer> stu = new Student<String,Integer> ();
//1、安全:类型检查
stu.setJavaScore("优秀");
//2、省心:类型转换
int it =stu.getOracleScore(); //自动拆箱
}
}
三、泛型接口
泛型在接口中的使用与泛型类基本一致,需要注意的是在接口中泛型字母只能使用在方法中,不能使用在全局常量中(接口中的成员变量均为全局常量)。
四、泛型方法
泛型方法就是为方法的返回类型签名,< >位于返回类型前面,泛型方法因为类型还未确定,所以只能访问对象信息,不能修改信息。
五、泛型的擦除
1.擦除:
*在使用时没有指定具体类型
*子类继承|实现时没有指定具体类型
2.后果:
*擦除后不类型检查
*擦除后按Object接收,以Object对待
*存在编译警告,加上Object可以去除,但显得有些画蛇添足
/**
* 父类为泛型类
* 1、属性
* 2、方法
*
* 要么同时擦除,要么子类大于等于父类的类型,
* 不能子类擦除,父类泛型
* 1、属性类型
* 父类中,随父类而定
* 子类中,随子类而定
* 2、方法重写:
* 随父类而定
*/
public abstract class Father<T,T1> {
T name;
public abstract void test(T t);
}
/**
* 子类声明时指定具体类型
* 属性类型为具体类型
* 方法同理
*/
class Child1 extends Father<String,Integer>{
String t2;
@Override
public void test(String t) {
}
}
/**
* 子类为泛型类 ,类型在使用时确定,大于等于父类的类型
* @author Administrator
*
*/
class Child2<T1,T,T3> extends Father<T,T1>{
T1 t2;
@Override
public void test(T t) {
}
}
/**
* 子类为泛型类,父类不指定类型 ,泛型的擦除,使用Object替换
*/
class Child3<T1,T2> extends Father{
T1 name2;
@Override
public void test(Object t) {
// TODO Auto-generated method stub
}
}
/**
* 子类与父类同时擦除
*/
class Child4 extends Father{
String name;
@Override
public void test(Object t) {
}
}
/**
*错误:子类擦除,父类使用泛型
class Child5 extends Father<T,T1>{
String name;
@Override
public void test(T t) {
}
*/
/**
*泛型的擦除
*1、继承|实现声明 不指定类型
*2、使用时 不指定类型
*统一Object 对待
*1、编译器警告 消除使用Object
*2、不完全等同于Object ,编译不会类型检查
*/
public class Student<T> {
private T javaScore;
private T oracleScore;
//泛型声明时不能使用 静态属性|静态方法上
//private static T1 test;
public T getJavaScore() {
return javaScore;
}
public void setJavaScore(T javaScore) {
this.javaScore = javaScore;
}
public T getOracleScore() {
return oracleScore;
}
public void setOracleScore(T oracleScore) {
this.oracleScore = oracleScore;
}
public static void main(String[] args) {
Student stu1 = new Student();
//消除警告 使用 Object
Student<Object> stu = new Student<Object>();
//stu.setJavaScore("af"); //以Object对待
test(stu1); //stu1 相当于Object 但是不完全等同Object
//擦除,不会类型检查
//test(stu);
test1(stu1);
test1(stu);
}
public static void test(Student<Integer> a){
}
public static void test1(Student<?> a){
}
}
六、泛型没有多态
public class Fruit {
}
class Apple extends Fruit{
}
public class App {
public static void main(String[] args) {
//A<Fruit> f = new A<Apple>();错误,泛型没有多态
A<Fruit> f =new A<Fruit>();
//test(new A<Apple>());错误
}
//形参使用多态
public static void test(A<Fruit> f){
}
//返回类型使用多态
public static A<Fruit> test2(){
//return (A<Fruit>)(new A<Apple>());错误
return null;
}
}
七、通配符?、extends和super在泛型中的使用
1.通配符的作用:虽然泛型没有多态,但通过通配符的使用,我们可以实现类似多态的功能。
public class Student<T> {
T score;
public static void main(String[] args) {
Student<?> stu = new Student<String>();
test(new Student<Integer>());
test2(new Student<Apple>());
//test3(new Student<Apple>()); //泛型没有多态
//test4(new Student<Apple>()); //<
stu = new Student<Fruit>();
//test4(stu); //使用时确定类型
test4(new Student<Object>());
test4(new Student<Fruit>());
}
public static void test(Student<?> stu){
}
public static void test3(Student<Fruit> stu){
}
//extends <=
public static void test2(Student<? extends Fruit> stu){
}
//super >=
public static void test4(Student<? super Fruit> stu){
}
}
八、泛型的嵌套
1.声明:嵌套使用泛型
A<B<C>> = new A<B<C>>();
2.使用:从外到内,层层拆分
public class Bjsxt <T>{
T stu ;
public static void main(String[] args) {
//泛型的嵌套
Bjsxt<Student<String>> room =new Bjsxt<Student<String>>();
//从外到内拆分
room.stu = new Student<String>();
Student<String> stu = room.stu;
String score =stu.score;
System.out.println(score);
}
}
九、没有泛型数组
可以声明泛型数组,但是不能创建泛型数组。虽然如此,但是我们可以通过使用Object接收,再将其强制转换为泛型数组。
public static void main(String[] args) {
Integer[] arr = new Integer[4];
//Student<String>[] arr2 = new Student<String>[10];
Student<?>[] arr2 = new Student[10];
MyArrayList<String> strList =new MyArrayList<String>();
strList.add(0, "a");
String elem =strList.getElem(0);
System.out.println(elem);}
class MyArrayList<E>{
//E[] cap =new E[10]; 没有泛型数组
Object[] cap = new Object[10];
public void add(int idx,E e){
cap[idx] =e;
}
@SuppressWarnings("unchecked")
public E[] getAll(){
return (E[]) cap;
}
@SuppressWarnings("unchecked")
public E getElem(int idx){
return (E) cap[idx];
}
}
十、JDK7泛型使用的新特性
JDK1.7中使用泛型,声明一次类型即可,在使用|创建时不用指定类型。
例如List<String> arrList2= new ArrayList<>();
终于写完了第一次写博客,有写的不好的地方还望指教。