泛型与集合

泛型:
类型参数化,解决不确定对象类型的问题。好处是代码复用性高。

作用范围:
类,方法,接口。 编译器通过识别尖括号内的字母来解析泛型。
约定俗成的泛型名: E (Element 集合中元素) , T (the Type of Object)某个类。

应用举例:
在没有使用泛型前:

 //未使用 泛型,会出现强制类型转换报错风险
    public static Object heap (Object food)
    {
        System.out.println(food + "is done");
        return food;
    }

    public static void main(String[] args) {

        // 加热肉
        Meat meat  = new Meat();
        Meat me = (Meat)Stove.heap(meat);
        // 加热汤
        Soup soup  = new Soup();
        Soup soup = (Soup)Stove.heap(soup);

    }

这里用 Object 来避免为每种食物都写一种加热的方法,但根据墨菲定律,会发生强制类型转换的危险。

使用泛型:

  public static T heap (T food)
    {
        System.out.println(food + "is done");
        return food;
    }
    public static void main(String[] args) {
        // 加热肉
        Meat meat  = new Meat();
        Meat me = Stove.heap(meat);
        // 加热汤
        Soup soup  = new Soup();
        Soup soup = Stove.heap(soup);

    }

好处:不会出现类型转换的错误,代码复用性高。

泛型与集合的联合使用:
List, List , List<?> 这三个对象有啥区别?直接看代码:

public static void main(String[] args)
	{
  //  1 无泛型约束
		List a1 = new ArrayList<>();
		a1.add(new Integer(1));
		a1.add(new Object());
		a1.add("hello");

		//将 a1 的引用赋值给 a2 , 但是在接受其他泛型赋值时会出现编译错误
		List<Object> a2 = a1;
		a2.add(new Integer(1));
		a2.add(new Object());
		a2.add("hello");

		//将 a1 的引用赋值给 a3
		List<Integer> a3 = a1;
		a3.add(new Integer(1));
		a3.add(new Object());
		a3.add("hello");

		//将 a1 的引用赋值给 a4
		List<?>a4 = a1;
		a4.add(new Object());
		a4.remove(2);
		a4.clear();
	}

第一段,因为不存在类型约束,所以向集合内添加任何对象都不会报错。
第二段,泛型是 Object ,也可以添加任何类型的对象,但唯一的区别是在进行类型转化时会报错的风险。
第三段,泛型是 Integer, 此时就有了约束,不是 Integer 类型的就无法成功添加其中
第四段, 添加通配符,只能进行 删除和清理操作,不能进行添加操作。

我们可以发现,这几种用法只能添加一种泛型约束,那有没有添加多种泛型约束呢?

List<? extend> 与 List<? super> 的区别:
创建三个类,动物,狗,柯基。(柯基继承狗,狗继承动物):

        List<Animal> animal = new ArrayList<>();
		List<Dog> dog = new ArrayList<>();
		List<keji>kj = new ArrayList<>();
		
		animal.add(new Animal());
		dog.add(new Dog());
		kj.add(new keji());
		
		// 只能赋值给 Dog 和子类(keji),所以此时会报错
		List<? extends Dog>extendsDogFromAnimal = animal;
		//只能赋值给 Dog 和父类
		List<? super Dog> superDogFromAnimal = animal;
		
		// 不能添加任何元素,会报错
		extendsDogFromAnimal.add(new Dog());
		// 可以添加元素
		superDogFromAnimal .add(new Dog());
	 // 类型丢失,只能返回 对象类型
	  Object ob =	superDogFromAnimal.get(0);
	
	 //返回类型不会擦除,子类对象被擦除
	  Dog do = extendsDogFromAnimal.get(0);
		

通过上面的代码可以发现,
List<?extends T>只能赋值给 自己和子类,上限是 T,不能添加元素,能返回父类和本类对象,但子类对象会被擦除。
List<? super T> 只能赋值自己和父类,下限是 T , 能添加元素,能返回 Object 类型的元素。

应用场景:
使用 <? extend T> 是 put 的功能受限,<? super T>是 get , 功能受限。
进行匿名投票时,向箱子里投票,在想拿出来时就会被告知 “”您以参与投票!“”,而这里就可以是使用 <? super T>
还可以拿上面的例子来说明 <?extend T> 适合放数据,<? super T>适合拿数据。

场景一: 当我们想放进一只狗时,你会向哪个箱子选择,是 动物箱子,还是狗箱子,抑或是 柯基箱子?
场景二: 当我们想拿出一只动物时,你会向哪个箱子选择,是 动物箱子,还是狗箱子,抑或是 柯基箱子?

总结:
花了些许的时间,介绍了 泛型,以及泛型和集合的联合使用。看了一位大佬的视屏说如果你想提高编程能力,使代码更富有条理性,利用 java 的泛型和反射 API 是最好的办法。

发布了51 篇原创文章 · 获赞 65 · 访问量 3246

猜你喜欢

转载自blog.csdn.net/weixin_44678969/article/details/103482731
今日推荐