泛型 (学习补充)
在集合中,泛型可以把它当做参数传进去,当然,也可以不定义类型,此时它的存储默认的就是object类型的,然而在你取出它的时候需要注意:它需要进行一个向下转型操作。
首先,我们提出一个问题:为什么要使用泛型?
早期的object类型可以接收任意的对象类型,但是在实际的使用中,会存在类型转换的问题。也就存在着隐患,所以java语言提供了泛型来解决这个安全问题。
什么是泛型?
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。
参数化类型,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也就定义成参数形式,然后在使用|调用时传入具体的类型。
java泛型,是JDK5中引入的一个新的特性,泛型提供了编译时类型安全检测机制,泛型的好处就是在编译的时候能够检查类型的安全。
泛型类
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。
一个普通的泛型类 :
//T可以为任意标识符,常见的如T、K、E、V等形式的参数常用于表示泛型
public class Demo<T> {
//name这个成员变量的类型为T,T的类型由外部指定
public T name;
T age;
public Demo() {
}
//泛型构造方法形参age的类型也为T,T的类型由外部指定
public Demo(T age) {
this.age = age;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
//泛型方法getAge的返回值类型为T,T类型由外部指定
public T getAge() {
return age;
}
public void setAge(T age) {
this.age = age;
}
public static void main(String[] args) throws NoSuchFieldException {
/*
传入的实参类型需要与泛型的类型相同
Demo<Integer> demo = new Demo<>(18);
实例化对象时,Demo<Integer> demo这里必须声明实参类型,因为左边是编译时检测
new Demo<>(18);右边可以不用声明类型,因为初始化对象是在运行时才会用到,而左边在编译时已经将它的类型指明了
*/
Demo<Integer> demo = new Demo<>(18);
Field fname = demo.getClass().getField("name");
System.out.println(demo.name+" type:"+fname.getType());
}
}
总结:1、泛型的类型参数只能是类类型 2、泛型的类型参数可以有多个。 3、如果没有定义具体类型,默认为object。
从泛型类派生子类
/*如果父类是泛型类,、
1、子类也是泛型类,子类和父类的泛型类型要一致
2、子类不是泛型类,父类要明确泛型的数据类型
*/
/*public class Test_Demo<T> extends Demo<T>{
}*/
public class Test_Demo extends Demo<Integer>{
}
泛型接口
/*
父类/父接口 如果是有泛型的,那么子类继承/实现后有两种选择
1、如果子类没有泛型,那么父类/接口必须在编译期间指明泛型类型
*/
public class TestDemo1 implements Comparable<Integer>{
@Override
public int compareTo(Integer o) {
return 0;
}
}
/*
2、子类也是泛型,子类和父类必须具有相同类型的泛型
*/
public class TestDemo<T> implements Comparable<T>{
@Override
public int compareTo(T o) {
return 0;
}
}
泛型通配符
●类型通配符一般是使用“?”代替具体的类型实参。
**?**代表实际传入的参数类型可以是任意的
public class Demo2 {
/*
类型通配符上限
<? extends Number>类型上限 只能传入number及number的子类
*/
public void test1(Demo<? extends Number> d){
}
/*
类型通配符下限
<? super Integer> 类型下限 只能传入Integer和Integer的父类
*/
public void test2(Demo<? super Integer> d){
}
public static void main(String[] args) {
Demo2 demo2 = new Demo2();
Demo<String> demo4 = new Demo<>();
// demo2.test2(demo4);
//demo2.test1(demo4);
Demo<Integer> demo1 = new Demo<>();
demo2.test1(demo1);
demo2.test2(demo1);
Demo<Number> demo3 = new Demo<>();
demo2.test1(demo3);
demo2.test2(demo3);
Demo<Object> demo5 = new Demo<>();
demo2.test2(demo5);
//demo2.test1(demo5);
}
}
类型擦除
泛型是Java 1.5版本才引进的概念,在这之前是没有泛型的,但是,泛型代码能够很
好地和之前版本的代码兼容。那是因为,泛到信息只存在于代码编译阶段,在进入JVM之
前,与泛型相关的信息会被擦除掉,我们称之为一类型擦除。
泛型类被类型擦除后,相应的类型就被替换成 Object 类型或者上限类型.
示例:
import java.lang.reflect.Field;
public class Demo<T> {
public T name;
public T age;
public Demo() {
}
public Demo(T age) {
this.age = age;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
public T getAge() {
return age;
}
public void setAge(T age) {
this.age = age;
}
public static void main(String[] args) throws NoSuchFieldException {
/*
Demo 是一个泛型类,我们可以通过反射查看他在运行时的状态信息。
*/
Demo<Integer> demo = new Demo<>();
demo.age=78;
Field fage = demo.getClass().getField("age");
System.out.println(demo.age+" type:"+fage.getType());
}
}
运行结果:78 type:class java.lang.Object
**补充反射的一个异常问题:**在我们通过反射查看它在运行时的状态信息时通常会出现Exception in thread “main” java.lang.NoSuchFieldException这样的异常。
那这种异常在什么情况下会出现呢?
当我们要查看的成员变量它是私有的时,当程序运行时会爆出NoSuchFieldException的异常
如下:
import java.lang.reflect.Field;
//T可以为任意标识符,常见的如T、K、E、V等形式的参数常用于表示泛型
public class Demo<T> {
//name这个成员变量的类型为T,T的类型由外部指定
public T name;
private T age;
public Demo() {
}
//泛型构造方法形参age的类型也为T,T的类型由外部指定
public Demo(T age) {
this.age = age;
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
//泛型方法getAge的返回值类型为T,T类型由外部指定
public T getAge() {
return age;
}
public void setAge(T age) {
this.age = age;
}
public static void main(String[] args) throws NoSuchFieldException {
/*
传入的实参类型需要与泛型的类型相同
Demo<Integer> demo = new Demo<>(18);
实例化对象时,Demo<Integer> demo这里必须声明实参类型,因为左边是编译时检测
new Demo<>(18);右边可以不用声明类型,因为初始化对象是在运行时才会用到,而左边在编译时已经将它的类型指明了
*/
Demo<Integer> demo = new Demo<>();
demo.age=78;
Field fage = demo.getClass().getField("age");
System.out.println(demo.age+" type:"+fage.getType());
}
}
运行结果:
解决方法就是把它从私有变量改变成公共变量就好啦!