一、为什么要用泛型

在实际的开发中,对于数据一致化的要求是比较重要的
例如:ArrayList list = new ArrayList()//构建了一个容器 int[] arr = new int[10];
如果对将要保存到ArrayList中的数据类型没有进行约束的话,就会导致容器里放了各种类型的数据。
那么取数据时,就可能需要强制类型转换,浪费时间,执行效率低,甚至数据丢失。
所以为了解决这样数据乱的情况,就要使用泛型里里面的数据约束。
ArrayList< String> list = new ArrayList();
< String>就是泛型的约束,用来约束数据类型的,要求容器里保存的数据必须是String类型的数据。
泛型约束的好处:
1、数据一致化
2、避免了没有必要的强制类型转换
3、避免了因数据类型不一致导致的问题
4、操作统一化

二、最基本的泛型格式

泛型:
<无意义英文大写字母的占位符> 例如:< T>、< E>
使用泛型泛型来进行约束数据类型,同时让代码更具普适性
格式:
ArrayList< String> list = new ArrayList();—IDEA
ArrayList< String> list = new ArrayList< String>();—Eclipse

三、自定义泛型在方法中的使用

语法格式:权限修饰符 [Static] <自定义的无意义的占位符> 返回值类型(可以使用自定义的泛型) 方法名字 (参数列表必须带有一个自定义的参数)){}
带有自定义泛型的方法,是依赖于方法的参数来确定泛型的返回值的

例子
class Cat {
    String name = "小猫";
}

public class Demo2 {
    public static void main(String[] args) {
        String s1 = test1("哈哈哈");
        System.out.println(s1);

        int a = test1(10);
        System.out.println(a);

        System.out.println(new Cat().name);

        Integer[] arr = new Integer[]{1,2,3,4,5};
        printArr(arr);
    }

    /**
     * 带有自定义泛型的方法
     * @param t  参数用于约束泛型的具体类型
     * @param <T>  自定义泛型的占位符
     * @return
     */
   public static <T> T test1(T t) {
        return t;
   }

   public static <T> T printArr(T[] arr) {
       for (int i = 0; i < arr.length; i++) {
           System.out.print(arr[i] + " ");
       }
       return arr[0];
   }
}

运行结果:

哈哈哈
10
小猫
1 2 3 4 5

四、自定义泛型在类中如何使用

语法格式:
class 类名<自定义泛型无意义的占位符>{
//类内的非静态成员变量和非静态成员方法可以使用类声明的自定义泛型
}
【注意事项】
1、在类名之后使用自定义的占位符,声明当前类带有泛型
2、类声明的自定义泛型,就是创建对象的时候确定具体的泛型是哪一种
Test1< Stirng>stringTest1 = new Test<>();
在类内凡是使用到的都会被替换成String
3、一个类带有自定义的泛型,但是在创建类对象的时候没有约束泛型具体的数据类型,那么在类中所有的泛型都会被Object代替。
4、类声明了自定义的泛型之后,不能用于静态的成员变量和静态成员方法。因为静态的成员变量和静态成员方法在类加载的时候,就已经在内存的数据区加载完,而毕泛型具体数据类型是在创建的对象的时候确定的

例子
class Test1<T> {
    /**
     * 该方法使用了在类名上声明的自定义的泛型
     * @param t
     * @return
     */
    public  T getType(T t) {
        return t;
    }
    public void testArgs(T t) {
        System.out.println(t);
    }
    public boolean testBoolean(T t) {
        System.out.println(t);
        return true;
    }
    /*public static T testStatic (T t) {
        System.out.println(t);
        return t;
        }*/

    /*  自己定义一个泛型和类的泛型没有关系*/
        /*public static <E> E testStatic(E e) {
            return e;
        }*/
}
class Dog {
    String name = "二哈";
}
public class Demo3 {
    public static void main(String[] args) {
        Test1<String> stringTest1 = new Test1<String>();
        String type = stringTest1.getType("123");
        System.out.println(type);
        
        Test1<Dog> dogTest1 = new Test1<>();
        Dog type1 = dogTest1.getType(new Dog());
        System.out.println(type1);

        dogTest1.testArgs(new Dog());
        Test1 stringTest2 = new Test1();
        //stringTest2.testArgs();
    }

}

运行结果:

123
fanxing_test.Dog@1b6d3586
fanxing_test.Dog@4554617c

五、自定义泛型在接口的使用

语法格式:
interface 接口名字< T> {
//有且只有成员方法才能使用泛型

//接口里面的成员变量public static final
}

例子
interface A<T> {
    public void test(T t);
}

// 当前类去实现一个接口,这个类名字后面必须和接口后面的泛型保持一致
class TestA<T> implements A<T> {

    @Override
    public void test(T t) {
        System.out.println(t);
    }
}

public class Demo4 {
    public static void main(String[] args) {
        TestA<String> stringTestA = new TestA<>();
        stringTestA.test("哇哈哈");
    }
}

运行结果:

哇哈哈