说说Java中的泛型

一、泛型的引入

直接举例:

package generic;


import java.util.ArrayList;

public class Generic_01 {
    public static void main(String[] args) {
        //使用传统的方式解决
        ArrayList arrayList = new ArrayList();
        arrayList.add(new People("sxp",20));
        arrayList.add(new People("wy",18));
        arrayList.add(new People("scy",21));

        //如果不小心添加一个Dog类在ArrayList中就会出现问题
        // arrayList.add(new Dog("小黄",2));

        for (Object obj:arrayList){
            People O=(People) obj;
            System.out.println(O.getName()+" - "+O.getAge());
        }
    }
}
class People{
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

class Dog{
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

输出结果:

sxp - 20
wy - 18
scy - 21

注意
上面方法中存在2个问题:
1、不能对加入到集合ArrayList中的数据类型进行约束(不安全)
2、遍历的时候,需要进行类型的转换,如果集合中的数据量较大,对效率有影响
例如:

package generic;

import java.util.ArrayList;

public class generic_02 {
    public static void main(String[] args) {
        //使用泛型
        ArrayList<People1> arrayList = new ArrayList<People1>();
        arrayList.add(new People1("sxp",20));
        arrayList.add(new People1("wy",18));
        arrayList.add(new People1("scy",21));
        //1、当我们ArrayList<People1>表示存放到ArrayList集合中的元素是People1类型
        //2、如果编译器发现添加的类型,不满足要求就会报错
        //3、在遍历的时候可以直接取出People1类型而不是Object
        for (People1 p:arrayList){
            System.out.println(p.getName()+" - "+p.getAge());
        }
    }
}

class People1{
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

class Dog1{
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

输出结果:

sxp - 20
wy - 18
scy - 21

总结
1、不使用泛型:某类型数据直接添加入集合中,取得时候先要转换成Object,再向下转型成该类型类型
2、使用泛型:放入时和取出不需要进行类型转换,提高了效率

二、泛型介绍

1、泛型又称参数化类型,是JDK5.0出现的新特性,解决数据类型的安全性问题
2、在类声明或实例化时只要指定好需要的具体的类型即可
3、Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产ClassCastException异常,同时,代码更加简洁、健壮
4、泛型作用:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值类型,或者时参数类型。

例如:

package generic;

public class Generic_03 {
    public static void main(String[] args) {
        Cat<String> stringCat = new Cat<String>("小黄");
        stringCat.f1();
        Cat<Integer> stringCat1 = new Cat<Integer>(5);
        stringCat1.f1();
    }
}

//E表示s的数据类型,该数据类型在定义Cat对象的时候指定
//即在编译期间,就确定E的类型
class Cat<E>{
    E s;

    public Cat(E s) {
        this.s = s;
    }
    public E f(){
        return s;
    }
    public void f1(){
        System.out.println(s.getClass());
    }
}

输出结果:

class java.lang.String
class java.lang.Integer

三、泛型的语法

1、泛型的声明
interface 接口< T >{}class类< K,V >{}

  • 其中,T、K、V不代表值,而是表示类型
  • 意字母都可以,常用T表示,是Type的缩写

2、泛型的实例化
要在类名后面指定类型参数的值(类型)如:

  • ArrayList< String >str=new ArrayList< String >();
  • Iterator< man > iterator=man.iterator();

例如:

package generic;

import java.util.*;

public class Generic_04 {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<Student>();
        students.add(new Student("sls",10));
        students.add(new Student("scy",17));
        students.add(new Student("wy",19));
        for ( Student stu:students){
            System.out.print(stu.getName()+" _ "+stu.getAge()+" ");
        }
        System.out.println();
        //迭代器
        HashMap<String,Student> student1 = new HashMap<String,Student>();
        student1.put("no1",new Student("sls",10));
        student1.put("no2",new Student("scy",17));
        student1.put("no3",new Student("wy",19));

        Set<Map.Entry<String, Student>> entries = student1.entrySet();
        Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Student> next =  iterator.next();
            System.out.print(next.getKey()+" : "+next.getValue().getName()+" _ "+next.getValue().getAge()+"     ");

        }
        System.out.println();




    }
}

class Student{
    private String name;
    private int age;

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

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

输出结果:

scy _ 17 sls _ 10 wy _ 19 
no2 : scy _ 17     no1 : sls _ 10     no3 : wy _ 19    

注意
1、interface List < T >{} , public class HashSet< E >{}等等中T,E只能是引用类型

List<integer> list1 = new ArrayList<Integer>();  // 正确
List<int> list2=new ArrayList< int >(); //不正确

2、在指定泛型具体类型后,可以传入该类型或者其子类型
3、泛型的使用:

List<integer> list1 = new ArrayList<Integer>();  
List<Integer> list2=new ArrayList< >();  //编译器会进行类型推断

4、如果写成List list = new ArrayList(); 就是默认泛型其中< E > E为object类型

例如:

package generic;

public class Generic_05 {
    public static void main(String[] args) {
        Bee<Animal> animalBee = new Bee<Animal>(new Animal());
        animalBee.func();
        Bee<Animal> animalBee1 = new Bee<Animal>(new Pig());
        animalBee1.func();
    }
}

class Animal{}

class Pig extends Animal{}

class Bee<E>{
    E e;

    public Bee(E e) {
        this.e = e;
    }
    public void func(){
        System.out.println(e.getClass());
    }
}

输出结果:

class generic.Animal
class generic.Pig

四、自定义泛型

1、自定义泛型类

基本语法

class 类名<T,R...>{   
	成员
}

注意
1、普通成员可以使用泛型(属性、方法)
2、使用泛型的数组,不能初始化
3、静态方法中不能使用类的泛型(因为静态是和类相关的,在类加载时,对象还没有创建。如果静态方法和属性使用了泛型,JVM就无法完成初始化)
4、泛型类的类型,是在创建对象时确定的(因为创建对象时,需要制定确定类型)
5、如果在创建对象时,没有指定类型,默认为Object
例如:

package generic;

public class Generic_06 {
    public static void main(String[] args) {
        Monkey<Double,String,Integer> monkey = new Monkey<>("Tom");
        monkey.setAge(17.2);
        monkey.setHigh("110");
        monkey.setWeight(122);

        System.out.println(monkey.name);
        System.out.println(monkey);

        Monkey monkey1 = new Monkey("Jion");
        monkey1.setWeight("12122");
        System.out.println(monkey1);
    }
}
// 自定义泛型
// T,R,M  : 泛型的标识符 一般时单个大写字母,可以有多个泛型标识符
class Monkey<T,R,M> {
    String name;
    T age;
    R high;
    M weight;

    public Monkey(String name) {
        this.name = name;
    }

    public Monkey(String name, T age, R high, M weight) {
        this.name = name;
        this.age = age;
        this.high = high;
        this.weight = weight;
    }

    public void setAge(T age) {
        this.age = age;
    }

    public void setHigh(R high) {
        this.high = high;
    }

    public void setWeight(M weight) {
        this.weight = weight;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public T getAge() {
        return age;
    }

    public R getHigh() {
        return high;
    }

    public M getWeight() {
        return weight;
    }

    @Override
    public String toString() {
        return "Monkey{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", high=" + high +
                ", weight=" + weight +
                '}';
    }
}

输出结果:

Tom
Monkey{name='Tom', age=17.2, high=110, weight=122}
Monkey{name='Jion', age=null, high=null, weight=12122}

2、自定义泛型接口

基本语法

interface  接口名<T,R...>{

}

注意
1、接口中静态成员也不能使用泛型(这个和泛型类规定一样)
2、泛型接口的类型,在继承接口或者实现接口时确定
3、没有指定类型,默认Object

例如

package generic;

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

    }
}

interface inter<U,R> {
    int n=10;
    // U name;不能这样使用
    R get(U u);
    void func1(R r);
    void func2(R r1,R r2 ,U u1);

    default R method(U u){
        return null;
    }
}

interface outer extends inter<String,Double>{

}

//当实现outer接口时,因为outer在继承inter接口时,指定<U,R>为<String,Double>
// 在实现inter接口的方法时,使用<String,Double>替换为<U,R>
class ter implements outer{

    @Override
    public Double get(String s) {
        return null;
    }

    @Override
    public void func1(Double aDouble) {

    }

    @Override
    public void func2(Double r1, Double r2, String u1) {

    }
}

class AA implements inter<Integer,Float>{

    @Override
    public Float get(Integer integer) {
        return null;
    }

    @Override
    public void func1(Float aFloat) {

    }

    @Override
    public void func2(Float r1, Float r2, Integer u1) {

    }

}
//不推荐
//默认为<Object,Object>
class BB implements inter{

    @Override
    public Object get(Object o) {
        return null;
    }

    @Override
    public void func1(Object o) {

    }

    @Override
    public void func2(Object r1, Object r2, Object u1) {

    }
}

自定义泛型方法

基本语法

修饰符<T,R..>返回类型方法名(参数列表){

}

注意
1、泛型方法,可以定义在普通类中,也可以定义在泛型类中
2、当泛型方法被调用时,类型会确定
3、public void eat(E e){},修饰符后没有<T,R..>eat方法不是泛型方法,而使用了类声明的泛型,泛型方法可以使用类声明的泛型,也可以使用自己声明泛型

例如:

package generic;

public class Generic_08 {
    public static void main(String[] args) {
        Car car = new Car();
        car.func1("nihao",788);

        Fish<String, Integer> objectObjectFish = new Fish<>();
        objectObjectFish.func4("niahb",123.98);

    }
}

//泛型方法可以定义在普通类中,也可以定义在泛型类中
class Car{
    public void func(){

    }
    //<T,R>就是泛型标识符,是提供给fly使用的
    public <T,R> void func1(T t,R r){
        System.out.println(t.getClass());
        System.out.println(r.getClass());
    }
}

class Fish<T,R>{
    public void func(){

    }
    public <U,M> void eat(U u,M m){

    }
    //不是泛型方法,,而是func1方法使用了声明的泛型
    public void func1(T t){

    }
    public<K,k> void func4(T t,K k){
        System.out.println(t.getClass());
        System.out.println(k.getClass());

    }
}

输出结果:

class java.lang.String
class java.lang.Integer
class java.lang.String
class java.lang.Double

泛型的继承和通配符

1、泛型不具备继承性
2、<?> :支持任意泛型类型
3、<? extends A >:支持A类以及A类的子类,规定了泛型的上限
4、<? super A>:支持A类以及A类的父亲,不限于直接父类,规定了泛型的下限

例如:

package generic;

import java.util.ArrayList;
import java.util.List;

public class Generic_09{
    public static void main(String[] args) {
        Object o=new String("xxx");

        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<FF1> list3 = new ArrayList<>();
        List<FF2> list4 = new ArrayList<>();
        List<FF3> list5 = new ArrayList<>();

        // 如果是 List<?> c ,可以接受任意的泛型类型
        printCollection(list1);
        printCollection(list2);
        printCollection(list3);
        printCollection(list4);
        printCollection(list5);

        // printCollection1(list1); 报错
        // printCollection1(list2); 报错
        printCollection1(list3);
        printCollection1(list4);
        printCollection1(list5);

        printCollection2(list1);
        // printCollection2(list2); 报错
        printCollection2(list3);
        // printCollection2(list4); 报错
        // printCollection2(list5); 报错


    }
    public static void printCollection(List<?> c){
        for (Object object:c){
            System.out.println(object);
        }
    }
    //?extends FF1 :表示上限,可以接受FF1或者FF1子类
    public static void printCollection1(List<? extends FF1> c){
        for (Object object:c){
            System.out.println(object);
        }
    }
    //? super FF1 子类类名FF1: 支持FF1类以及FF1类的父类,不限于直接父类
    public static void printCollection2(List<? super FF1> c){
        for (Object object:c){
            System.out.println(object);
        }
    }
}

class FF1{

}

class FF2 extends FF1{

}

class FF3 extends  FF1{

}
  • 32
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值