package Demo30;
/*
创建集合对象,不适用泛型
好处:集合不使用泛型,默认的类型是object类型,可以存储任意的数据类型
弊端:不安全,会发生异常

创建集合对象,使用泛型
好处:1、避免了类型转换的麻烦,存储的是什么类型,输出就是什么类型
     2、把运行期异常提升到了编译期异常

 */

import java.util.ArrayList;
import java.util.Iterator;

public class DemoGeneric {
    public static void main(String[] args) {
        show1();
        show2();

    }
    private static void show2() {
        ArrayList<String> list = new ArrayList<>();
        list.add("abc");
        //存储其它类型会报错
        //list.add(30)
    }

    private static void show1() {
        ArrayList list = new ArrayList();
        list.add("abc");
        list.add(1);

        //使用迭代器遍历集合
        //获取迭代器
        Iterator it = list.iterator();
        while(it.hasNext()){
            Object next = it.next();
            System.out.println(next);

            //想要使用String类的特有方法,length获取字符串长度,不能使用,因为多态Object obj = "abc
            //需要向下转型
            //会抛出异常java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
            String s = (String) next;
            System.out.println(((String) next).length());

        }
    }
}
package Demo30;

public class DemoGenericClass {
    public static void main(String[] args) {

        //不写泛型默认为object类型
        GenericClass gc = new GenericClass();
        gc.setName("只能是字符串");
        Object name = gc.getName();

        //创建GenericClass对象,泛型使用Integer类型
        GenericClass<Integer> gc2 = new GenericClass<>();
        gc2.setName(111);

        Integer name1 = gc2.getName();
        System.out.println(name1);
    }
}
package Demo30;
/*
定义含有泛型的方法:泛型定义在方法的修饰符和返回值之间

格式:
    修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){
        方法体;
    }
    含有泛型多的方法,在调用方法的时候确定泛型的数据类型
    传递什么类型的参数,泛型就是什么类型
 */
public class GenericMethod {
    //定义一个含有泛型的方法
    public <M> void method(M m){
        System.out.println(m);
    }
    //定义一个含有泛型的静态方法
    public static <S> void method01(S s){
        System.out.println(s);
    }
}
package Demo30;
/*
测试含有泛型的方法
 */
public class DemoGenericMethod {
    public static void main(String[] args) {
        //创建GenericMethod
        GenericMethod gc = new GenericMethod();

        /*
        调用含有泛型的方法,
        这里传入什么类型,泛型就是什么类型
         */
        gc.method(10);
        gc.method("abc");
        gc.method(8.8);
        gc.method(true);


        gc.method01("静态方法");
        //静态方法可以通过类名.方法名来调用
        GenericMethod.method01("静态方法1");
    }
}
package Demo30;
/*
定义一个泛型类模拟ArrayList集合
 */
public class GenericClass <E>{
    private E name;

    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }
}
package Demo30;
/*
含有泛型的接口,第一种使用方式,定义接口的实现类,实现接口,指定接口的泛型
public interface Iterator <E> {
        E next();
    }
含有泛型的接口第二种使用方式,接口是使用什么泛型,实现类就使用什么泛型
 */
public class GenericInterfaceImpl1 implements GenericInterface<String>{
    @Override
    public void method(String s) {
        System.out.println(s);
    }
}
package Demo30;
/*
含有泛型的接口第二种使用方式,接口是使用什么泛型,实现类就使用什么泛型
 */
public class GenericInterfaceImpl2<I> implements GenericInterface<I>{


    @Override
    public void method(I i) {

    }
}
package Demo30;
/*
定义含有泛型的接口
 */
public interface GenericInterface <I> {
    public abstract void method(I i);
}
package Demo30;
/*
第一种使用方式,定义接口的实现类,实现接口,指定接口的泛型
含有泛型的接口第二种使用方式,接口是使用什么泛型,实现类就使用什么泛型
 */

public class DemoGenericInterface {
    public static void main(String[] args) {
        //创建GenericInterfaceImpl1对象
        GenericInterfaceImpl1 gil = new GenericInterfaceImpl1();
        gil.method("字符串");

        //创建GenericInterfaceImpl2对象,自己定义泛型
        GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
        gi2.method(18);

        GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();

    }
}
package Demo30;

import java.util.ArrayList;
import java.util.Iterator;

/*
泛型的通配符:
        ?: 代表任意的数据类型
    使用方式:
        不能创建对象使用
        【只能作为方法的参数使用】
 */
public class DemoGenericTPF {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);

        ArrayList<String> list1 = new ArrayList<>();
        list1.add("a");
        list1.add("b");

        /*
        定义一个方法,能遍历所有类型的ArrayList集合
        但是这时候不知道ArrayList集合使用的是什么类型,就可以使用泛型的通配符来接收数据类型4
        注意: 泛型是没有继承的
         */

        printArray(list);
        printArray(list1);
    }

    private static void printArray(ArrayList<?> list) {
        Iterator<?> it = list.iterator();
        while(it.hasNext()){
            Object next = it.next();
            System.out.println(next);
        }
    }
}
package Demo30;
/*
泛型的上限限定: ? extends E 代表使用的泛型只能是 E类型的子类/本身
泛型的上限限定: ? super E 代表使用的泛型只能是 E类型的父类/本身

//类与类之间的继承关系
Integer extends Number extends Object
String extends Object
 */
public class DemoGenericGJ {
}