泛型(学习补充)

泛型 (学习补充)

在集合中,泛型可以把它当做参数传进去,当然,也可以不定义类型,此时它的存储默认的就是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());
    }
}

运行结果:

泛型(学习补充)

解决方法就是把它从私有变量改变成公共变量就好啦!

上一篇:es6中的class与继承


下一篇:C# 批量操作对象属性