1.泛型类:在定义类的时候,在类名的后面加上

1)E只是起到占位的作用,当创建对象时,赋予真正的类型。

2)E是泛型的形参,可以是一个,也可以是多个,如果是多个,用逗号隔开。

3)泛型形参的命名规则,只要符合java的标识符规范就可以。但是,通常泛型形参是一个大写字母。如:E(element),K(key),V(value)。

4)E可以再整个类中使用。比如:类的属性,类的方法参数,类的方法返回值。

5)在创建对象的时候,泛型类型,左边一定要写,右边可写可不写。如果右边写了,左边没写,跟没写一样。

FanXingClass<String> fanXingClass=new FanXingClass<>();

public class FanXingClass<E> {
    //E作为属性类型
    private E e;
    //E作为返回值类型
    public E getE() {
        return e;
    }
    //E作为参数类型
    public void setE(E e) {
        this.e = e;
    }
    
    public static void main(String[] args) {
        //E为String类型
        FanXingClass<String> fanXingClass=new FanXingClass<>();
        fanXingClass.setE("hahaha");
        System.out.println(fanXingClass.getE());

        //E为Integer类型
        FanXingClass<Integer> fanXingClass2=new FanXingClass<>();
        fanXingClass2.setE(111);
        System.out.println(fanXingClass2.getE());

        //E为Float类型
        FanXingClass<Float> fanXingClass3=new FanXingClass<>();
        fanXingClass3.setE(3.1415F);
        System.out.println(fanXingClass3.getE());
    }
}

2.泛型接口:在定义接口的时候,在接口名的后面加上

关于泛型接口的实现,有两种方式:

1)如果接口后面还是泛型,那么前面的类也必须是泛型。在创建对象时,再将类型传进去。

2)如果接口后面是具体的类型,那么前面的类中不用写<>。在创建对象时,不需要传类型了,因为类型在接口中已经确定了。

 

接口类:FanXingInterfaceDemo

public interface FanXingInterfaceDemo<E> {
    //E e; 接口中的属性默认是public static final修饰的,是常量,而 E 泛型是不确定的。所以不能再接口中定义泛型变量。
    public void test1(E e);
    public E test2();
}

1)如果接口后面还是泛型,那么前面的类也必须是泛型。

public class FanXingInterfaceSub<E> implements FanXingInterfaceDemo<E>

public class FanXingInterfaceSub<E> implements FanXingInterfaceDemo<E> {
    private E e;
    public void setE(E e){
        this.e=e;
    }
    public E getE(){
        return e;
    }
    @Override
    public void test1(E e) {
        System.out.println(e);
    }

    @Override
    public E test2() {
        return e;
    }

    public static void main(String[] args) {
        FanXingInterfaceSub<String> fxis1=new FanXingInterfaceSub<>();
        fxis1.setE("abc");
        fxis1.test1(fxis1.getE());
        System.out.println(fxis1.test2());

        FanXingInterfaceSub<Integer> fxis2=new FanXingInterfaceSub<>();
        fxis2.setE(111);
        fxis2.test1(fxis2.getE());
        System.out.println(fxis2.test2());
    }
}
------------------------------------------------------------------------
输出结果:
abc
abc
111
111

2)如果接口后面是具体的类型,那么前面的类中不用写<>。

public class FanXingInterfaceSub2 implements FanXingInterfaceDemo<String>

public class FanXingInterfaceSub2 implements FanXingInterfaceDemo<String> {
    @Override
    public void test1(String s) {
        System.out.println(s);
    }

    @Override
    public String test2() {
        return "test2";
    }
    public static void main(String[] args) {
        FanXingInterfaceSub2 fxis1=new FanXingInterfaceSub2();
        fxis1.test1("abc");
        System.out.println(fxis1.test2());
    }
}

3.泛型方法

在方法的返回值前面定义泛型,然后在方法中使用泛型。

public <E> void show(E e){

e);

}

public class FangXIngMethod {
    public <E> void show(E e){
        System.out.println(e);
    }

    public static void main(String[] args) {
        FangXIngMethod fxm=new FangXIngMethod();
        fxm.show(123);
        fxm.show("abc");
    }
}

4.泛型的上限:

只定义在方法中(工作中不用,查找别人的API,会有)

形式:<? extends 父类>

意义:如果父类确定了,所有的子类都可以直接使用。参数类型只能是该类型或该类型的子类

 

5.泛型的下限:

只定义在方法中

形式:<? super 子类>

意义:如果子类确定了,子类的所有的父类都可以直接传递参数值。参数类型只能是该类型或该类型的父类。

代码示例:

public class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Student extends Person {
    private String classRoom;

    public Student(String name, int age, String classRoom) {
        super(name, age);
        this.classRoom = classRoom;
    }

    @Override
    public String toString() {
        return "Student{" +
        "name='" + name + '\'' +
                ", age=" + age +
                ", classRoom=" + classRoom + '\'' +
                "} " ;
    }
}
public class Test {
    public static void method1(ArrayList<? extends Person> list){
        for(Person p:list){
            System.out.println(p);
        }
    }
    public static void method2(ArrayList<? super Student> list){
        for(Object o:list){
            System.out.println(o);
        }
    }

    public static void main(String[] args) {
        ArrayList<Person> list1=new ArrayList<>();
        list1.add(new Person("a",11));
        list1.add(new Person("b",12));
        list1.add(new Student("c",13,"classRoom1"));
        System.out.println("method1_<? extends Person>_list1:");
        method1(list1);
        System.out.println("----------------------------------");
        ArrayList<Student> list2=new ArrayList<>();
        list2.add(new Student("d",14,"classroom2"));
        list2.add(new Student("e",15,"classroom2"));
        System.out.println("method1_<? extends Person>_list2:");
        method1(list2);
        System.out.println("----------------------------------");
        ArrayList<Student> list3=new ArrayList<>();
        list3.add(new Student("f",14,"classRoom3"));
        list3.add(new Student("g",15,"classroom3"));
        System.out.println("method2_<? super Student>_list3:");
        method2(list3);
        System.out.println("------------------");
        System.out.println("method2_<? super Student>_list4:");
        ArrayList<Person> list4=new ArrayList<>();
        list4.add(new Person("h",14));
        list4.add(new Person("i",15));
        method2(list4);
    }
}
--------------------------------------------------
输出结果:
method1_<? extends Person>_list1:
Person{name='a', age=11}
Person{name='b', age=12}
Student{name='c', age=13, classRoom=classRoom1'} 
----------------------------------
method1_<? extends Person>_list2:
Student{name='d', age=14, classRoom=classroom2'} 
Student{name='e', age=15, classRoom=classroom2'} 
----------------------------------
method2_<? super Student>_list3:
Student{name='f', age=14, classRoom=classRoom3'} 
Student{name='g', age=15, classRoom=classroom3'} 
------------------
method2_<? super Student>_list4:
Person{name='h', age=14}
Person{name='i', age=15}

总结:

1.泛型分为:泛型类,泛型接口,泛型方法。

2.泛型类是在类名后面加上<E>,E起到一个占位符的作用,相当于一个形参。当创建对象时,在确定具体参数类型。实现了解耦。E可以是类属性类型,方法参数类型,方法返回值类型。

3.泛型接口是在接口后面加上<E>,E起到一个占位符的作用,相当于一个形参。子类在实现接口的时候,有两种方式。方式一:接口中不是具体的类,还是泛型,则子类名称后面还要加上泛型。方式二:接口中用具体的类代替泛型,子类名称后面不用加上泛型。E可以是方法参数类型,方法返回值类型。但不能是属性类型。因为接口中的属性值都是常量,泛型不是常量。

4.泛型方法是在方法返回值前面声明泛型<E> ,E可以是方法参数类型,方法返回值类型。

5.泛型通配符有3种:<?>,<? extends E>,<? super E>.

6.<? extends E>:泛型的上限。只要是E或者E的子类都可以。只定义在方法中。

7.<? super E>:泛型的下限。只要是E或者E的父类都可以。只定义在方法中。

8.泛型的优点:数据安全;获取数据时,效率高。

9.定义泛型后,把一些异常由运行期提前到编译器。