java泛型学习(2)
一:深入泛型使用。主要是父类和子类存在泛型的demo
/** * 父类为泛型类 * @author 尚晓飞 * @date 2014-7-15 下午7:31:25 * * * 父类和子类的泛型。 * 【泛型的具体声明】 * (1)子类直接声明具体类型 * (2)使用时指定具体类型(new 对象时) * (3)子类泛型>=父类泛型(个数,类型,顺序无关) * * 【泛型的确定】 * (1)属性:在父类中,泛型随父类泛型而定 * 子类中,泛型随子类泛型而定 * (2)重写方法中: * 泛型全部随父类而定 * 【泛型的擦除】 * 父类和子类泛型要么同时擦除。统一object对待 * 子类不能擦除泛型,而父类存在泛型 * * * @param <T> */ public abstract class Father<T,T1> { T name; public abstract T test(T t); } //子类声明时指定具体类型 //属性类型为具体类型 class Child1 extends Father<String,Integer>{ @Override//重写方法中,泛型全部随父类而定 public String test(String t) { // TODO Auto-generated method stub return null; } } //子类为泛型类.类型在使用时确定(new 对象时) //子类类型>=父类类型 class Child2<T1,T,T2> extends Father<T,T1>{ @Override public T test(T t) { // TODO Auto-generated method stub return null; } } //子类为泛型类,父类不指定泛型,统一object对待,父类泛型的擦除 //子类和父类同时擦除泛型。 //子类不能单独擦除泛型,而父类不擦除泛型 class Child3<T1,T> extends Father{ T1 name2;//子类中属性,随子类泛型而定 @Override public Object test(Object t) { // TODO Auto-generated method stub return null; } } //这是报错的,子类擦除,父类使用泛型。编译通不过。 class Child extends Father<T, T1>{ }
二:泛型的一个误区使用demo
Student泛型类
public class Student<T> { T javase; T oracle; public T addStudent(T t1){ T sT=t1; return sT ; } public Student() { super(); } public Student(T javase, T oracle) { super(); this.javase = javase; this.oracle = oracle; } public T getJavase() { return javase; } public void setJavase(T javase) { this.javase = javase; } public T getOracle() { return oracle; } public void setOracle(T oracle) { this.oracle = oracle; } }
测试Test类
泛型的擦除
* 【1】子类继承|实现时不指定泛型
* 【2】使用时不指定泛型
* 统一Object对待,但泛型不是object,编译时不会类型检查
* 编译器会发出警告,但不报错
1 /** 2 * 泛型的擦除 3 * 【1】子类继承|实现时不指定泛型 4 * 【2】使用时不指定泛型 5 * 统一Object对待,但泛型不是object,编译时不会类型检查 6 * 编译器会发出警告,但不报错 7 * @author 尚晓飞 8 * @date 2014-7-15 下午8:26:21 9 * 10 */ 11 public class Test { 12 public static void main(String[] args) { 13 Student stu1=new Student();//如果使用时不确定泛型类型,编译器会发出警告,但不算错; 14 Object sd=stu1.javase;//类型统一用object对待。相当于object,而不是指object 15 16 Student<Object> stu2=new Student<Object>(); 17 18 test1(stu1);//虽然没确定泛型,以object对待,只是相当于,但不确定。泛型擦除,编译时编译器不会类型检查。所以不报错 19 test1(stu2);//如果泛型指定是Object时,那么传入的实参的泛型必须是Object.此方法报错。泛型一旦确定,哪怕是指定Object,编译器会编译类型检查 20 21 test2(stu1); 22 test2(stu2); 23 24 } 25 26 //方法一 27 public static void test1(Student<Integer> st){} 28 //方法二 29 public static void test2(Student<?> st){} 30 }
java泛型的深入理解
在学习泛型之前,简单介绍下泛型的一些基本术语,以ArrayList<E>和ArrayList<Integer>做简要介绍:
整个成为ArrayList<E>泛型类型
ArrayList<E>中的 E称为类型变量或者类型参数
整个ArrayList<Integer> 称为参数化的类型
ArrayList<Integer>中的integer称为类型参数的实例或者实际类型参数
·ArrayList<Integer>中的<Integer>念为typeof Integer
ArrayList称为原始类型
以下为泛型擦除的概念和示例代码,帮助理解java泛型的原理
1 //【1】java的泛型是伪泛型,只是在编译时起作用,进行类型检查,可称为java的语法糖。 2 //【2】一旦编译通过,编译成内存中的class文件信息,jvm就将所有的泛型擦除。在jvm中的class信息是无泛型的,都统一是object 3 //【3】泛型擦除后的原始类型-->,什么是原始类型?原始类型(raw type)就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型。 4 //无论何时定义一个泛型类型,相应的原始类型都会被自动地提供。类型变量被擦除(crased), 5 //并使用其限定类型(无限定的变量用Object)替换。 6 //【4】,类型检查就是针对引用的,谁是一个引用,用这个引用调用泛型方法,就会对这个引用调用的方法进行类型检测,而无关它真正引用的对象 7 //因此arryList3能添加Integer类型数据,而与new ArrayList<String>();对象无关,它只是开辟一个空间 8 ArrayList<String> arrayList1=new ArrayList<String>(); 9 arrayList1.add("shangxiaofei"); 10 11 ArrayList<Integer> arrayList2=new ArrayList<Integer>(); 12 arrayList2.add(125); 13 //【4】 14 ArrayList arrayList3=new ArrayList<String>(); 15 arrayList3.add(125); 16 17 //【2】本身arrayList2中只能存放Integer类型的数据,但通过反射获取arrayList2的class信息,并操作add方法,却往里添加了字符串。 18 //证明了java泛型是伪泛型,只存在编译器检查语法错误和类型转换层面,一旦编译成class文件,所有泛型全部擦除 19 arrayList2.getClass().getMethod("add", Object.class).invoke(arrayList2, "zifuchuan"); 20 //【1】虽然指定了不同的泛型,但类信息还是相同,说明java泛型是伪泛型。 21 System.out.println("Test.main()"+(arrayList1.getClass()==arrayList2.getClass())); 22 23
2、泛型中的?通配符的扩展
1:界定通配符的上边界
Vector<? extends 类型1> x = new Vector<类型2>();
类型1指定一个数据类型,那么类型2就只能是类型1或者是类型1的子类
Vector<? extends Number> x = new Vector<Integer>();//这是正确的
Vector<? extends Number> x = new Vector<String>();//这是错误的
2:界定通配符的下边界
Vector<? super 类型1> x = new Vector<类型2>();
类型1指定一个数据类型,那么类型2就只能是类型1或者是类型1的父类
Vector<? super Integer> x = new Vector<Number>();//这是正确的
Vector<? super Integer> x = new Vector<Byte>();//这是错误的
3:泛型不存在多态
首先回顾一下java的多态
1 //java的多态回顾 2 public class Animal { 3 4 } 5 6 class Dog extends Animal{ 7 8 } 9 10 class Test1 { 11 public static void main(String[] args) { 12 //【1】多态 父类引用指向子类对象 13 Animal animal=new Dog(); 14 add(new Dog()); 15 } 16 //【2】形参使用多态 17 public static void add(Animal animal){ 18 19 } 20 //【3】返回值类型使用多态 21 public static Animal get(){ 22 return new Dog(); 23 } 24 }
泛型不存在多态的示例代码
1 //泛型类 2 class App<T>{} 3 class Test2{ 4 public static void main(String[] args) { 5 //【1】泛型不存在多态 ,因此错误 6 //App<Animal> app=new App<Dog>(); 7 App<Animal> app=new App<Animal>(); 8 9 //【2】当形参规定什么泛型时,传递的实参必须是什么泛型,不存在多态 10 //add(new App<Dog>()); 11 } 12 //形参使用多态 13 public static void add(App<Animal> app){} 14 15 //【3】返回值类型的多态,也不正确 16 public static App<Animal> get(){ 17 //return new App<Dog>();返回值类型不存在多态 18 //return (App<Animal>)(new App<Dog>());强制类型转化也不对 19 return null; 20 } 21 }
4:泛型的通配符:? extends super
[1]通过通配符号,可以实现类似多态的功能
(1)?号的使用 声明类型|声明方法 时使用。不能声明类和使用泛型时使用。
?号可以接受所有类型,只能接收和输出,不能修改
1 //?的使用 2 //【1】声明类泛型时不能使用 3 //【2】声明方法参数时泛型可以使用?号 4 //【3】声明返回值类型时泛型可以使用?号 5 //【4】具体使用泛型时不能使用?号,要把?号确定成某一类型 6 7 //【1】class Student<?>{}声明类时不能使用 8 class Student2<T>{ 9 T score; 10 public static void add(Student2<?> stu){}//【2】声明方法参数时使用?号 11 //【3】声明返回值类型时可以使用?号 12 public static Student2<?> get(){ 13 return new Student2<Integer>(); 14 } 15 } 16 17 class Test3{ 18 public static void main(String[] args) { 19 Student2<?> student=new Student2<String>(); 20 //student.add(new Student2<?>());//【4】使用时不能使用?号 21 student.add(new Student2<Integer>() );//使用时要把?号确定成指定的类型 22 } 23 }
(2)? extends V 上限 所使用的泛型必须<=V 必须是V的子类或本身
(3)? super V 下限 所使用的泛型必须>=V 必须是V的超类或本身
1 //extends super使用 2 class Student2<T>{ 3 T score; 4 5 public static void test1(Student2<? extends Animal> st){} 6 public static void test2(Student2<? super Animal> st){} 7 8 //annimal是dog的父类 9 public static void main(String[] args) { 10 test1(new Student2<Dog>()); 11 //test1(new Student2<Object>());object是Animal的超类,超过上限,报错 12 13 test2(new Student2<Object>()); 14 //test2(new Student2<Dog>());dog是Animal的子类,不在下限范围内,报错 15 } 16 }
5:泛型的嵌套
1 public class Bjsxt<T> { 2 T pe; 3 } 4 class Person<T>{ 5 T socre; 6 } 7 class Test5{ 8 public static void main(String[] args) { 9 //泛型的嵌套 10 Bjsxt<Person<String>> bjsxt=new Bjsxt<Person<String>>(); 11 //从外到内拆分 12 Person<String> pe=bjsxt.pe; 13 String socreString=pe.socre; 14 } 15 }
6:泛型和数组
(1)没有泛型数组,不能创建泛型数组
(2)可以只有声明,可以使用?
1 package com.bjsxt.shangxiaofei; 2 3 public class Array { 4 public static void main(String[] args) { 5 Integer[] arr=new Integer[30];//声明一个数组 6 //Student<String>[] sts=new Student<String>[10];没有泛型数组,但可以声明 7 Student<String>[] sts=new Student[10]; //可以声明,但并没有什么实际意义 8 Student<?>[] stss=new Student[10]; 9 10 11 MyArrayList<String> mList=new MyArrayList<String>(); 12 mList.add(0, "尚晓飞"); 13 //mList.add(1, new Student());泛型规定是String,也就是说数组里只能存放String 14 String nameString=mList.get(0); 15 String[] strs=mList.getAll(); 16 System.out.println("Array.main()"+nameString); 17 } 18 } 19 20 //泛型与数组的应用。巧妙在于将一个object数组,固定存放String的值 21 class MyArrayList<E>{ 22 //声明一个object数组 23 Object[] objs=new Object[30]; 24 25 //给数组添加一个值 26 public void add(int idx, E e){ 27 objs[idx]=e; 28 } 29 //获取数组 30 public E[] getAll(){ 31 return (E[])objs; 32 } 33 //获取某个下标的值 34 public E get(int idx){ 35 return (E)objs[idx]; 36 } 37 38 }
7:jdk1.7对泛型的修改
1 //jdk1.7后对泛型的修改 2 //只在声明时用一次泛型,创建和使用时不需要,只需要加上<> 3 List<String> ad=new ArrayList<String>();//1.7以前使用泛型 4 //List<String> ad2=new ArrayList<>();//1.7以后只需要声明一次 使用和创建时不需要指定类型
asdf