泛型类:
package fanxing;
public class fanxing <T>{
private T data;
public void fanxing(T addnum){
this.data=addnum;
}
public T getData(){
return data;
}
public void setData(T data) {
this.data = data;
}
public static void main(String[] args) {
fanxing fanxing1=new fanxing<>();
fanxing1.setData("jiage");
System.out.println(fanxing1.getData());
}
}
泛型接口
泛型类的泛型只影响该类内的普通方法,若是泛型类()中声明了一个泛型方法(如),其可以是任意类型;可以类型与T同,也可以不同;
也可以限定类型变量,目的是让传入的两个变量均有某种方法便于比较等,如图为了使传入的参数均有compareTo方法,要注意这里均是写extends无论是派生类还是接口,先写类且只能有一个,再写接口
泛型的局限性
静态域或者方法里不能引用泛型方法【不可以定义静态泛型的变量】静态方法本身是泛型方法就行;
原因在于:泛型变量的类型实在类创建之后才清楚的。而静态变量的初始化在执行类的构造方法之前就执行了,因此虚拟机不知道其到底是什么类型;
静态方法本身是泛型方法就行;
不能实例化类型变量;
eg:this.data=new T();【错误的】
在定义泛型的时候不允许写基本的数据类型,只能写包装类,如int–>Integer;double–>Double;
原因是基本数据类型在jdk里不是对象;而泛型只允许是对象;
就算传入的泛型的类型不一样,同一个泛型类创建的对象getclass()获取的类是一样,即泛型类的原生类型;
可以定义泛型的数组,但不可以new进行初始化;
泛型类和异常结合的时候,对象是不可以被捕获的(无法被catch)
但通过特殊方式可以抛出;
若原本两个类具备继承关系,如animal为父类,dog为子类,若其作为泛型传入泛型类,那么泛型类的两个对象直接没有继承关系;即Pair和Pair之间没有任何的继承关系
Pair<animal> animalpair =new Pair<>();
Pair<dog> dogpair =new pair<>();
泛型类是可以扩展和继承其他泛型类的
fanxing<String> fanxing2= new ExtendsFanxing<String>();
private static class ExtendsFanxing<T> extends fanxing<T> {
}
为了便于使用,故而有了通配符
不可以在类声明里用,只能在方法里用;<? extends fanxingsuper>
若遇到类中有set和get方法;
get方法只能在泛型为fanxingsuper的对象下使用,而set则是不允许被使用的,无论是fanxingsuper还是其子类;
此外有<? super fanxing>这意味着传入其中的是fanxing的超集,即fanxing自身以及其父类;
当前可以进行set,但只能传入fanxing及其子类,传入fanxingsuper报错;get方法获取值的时候,数据类型为Object
此外,可以通过该方式实现安全的写入数据;
对比于c#的泛型实现,c#中泛型无论是在程序源码中还是编译后的IL中,或是是在运行期CLR,都是实际存在的,List与List就是两个不同类;其在系统运行期生成,有自己的虚方法表和类型数据,这种实现为类型膨胀,基于这种方法实现的泛型称为真实泛型;
而java中的泛型只在程序的源码中存在,在编译后的字节码文件中就已经替换为原来的原生类型(裸类型)了,并在相应的地方插入了强制转型的代码;对于运行期的java而言,ArrayList与ArrayList是同一个类,因此泛型技术实际上是Java语言的一颗语法糖;其泛型的实现方法称之为类型擦除,基于这种方法实现的泛型称为伪泛型;
由于java泛型的引入,虚拟机也有所调整,引入了signature,localvariableTypeTable等新的属性。Signature是其中最重要的一项属性,作用是存储一个方法在字节码层面的特征签名;该属性中保存的参数类型不是原生类型,而是包括了参数化类型的信息。修改后的虚拟机规范要求所有能识别49.0以上版本的class文件的虚拟机都能要能正确的识别Signature参数;
一项属性,作用是存储一个方法在字节码层面的特征签名;该属性中保存的参数类型不是原生类型,而是包括了参数化类型的信息。修改后的虚拟机规范要求所有能识别49.0以上版本的class文件的虚拟机都能要能正确的识别Signature参数;
由此,从signatur属性的出现可以得出结论,擦除法所谓的擦除其实只是对方法的Code属性中字节码进行擦除,实际上元数据中还是保留了泛型信息,这也是我们能通过反射手段取得参数化类型的根本依据。