Java泛型与通配符使用

泛型

什么是泛型?为什么使用泛型?

泛型的出现意味着编写的代码可以被不同类型的对象所重用,提升了代码的重用性。泛型的本质是参数化类型,即将所需操作的数据类型设置为一个参数。
举个实际中的栗子:我们需要设计一个柜子的类,柜子可以用于存放书本、食品或者衣物,但是我们在设计阶段不能确定柜子里具体要存放什么东西,那怎么来设计这样一个通用型的柜子,这里就可以用到泛型。所以,我们把存放元素的类型设计成一个参数,这个类型参数就称之为泛型。
举个JAVA中的栗子:ArrayList,List,这个就是类型参数,也就是泛型。为什么这么写呢?因为我们在创建Arraylist或者List时,无法确定里面具体存储的元素的类型,但是我们有希望一个实例对象中存储的元素的类型时一致的,这就需要泛型来实现操作。

		int[] arr1 = new int[] {159,357,456};
		//没有用泛型,ArrayList中存储的元素格式各样,实际开发中在操作时是很容易出现问题的
		List list1 = new ArrayList();
		list1.add(123);
		list1.add("敲代码的阿茄");
		list1.add(arr1);
		//使用泛型,限制ArrayList存放的元素的类型,就不能添加存储其他类型的元素了
		List<String> list2 = new ArrayList<>();
		list2.add("敲");
		list2.add("代");
		list2.add("码");
		list2.add("的");
		list2.add("阿");
		list2.add("茄");
       //list2.add(123);//无法添加
       //list2.add(arr1);//无法添加

泛型使用的基本要求

  • 异常类不能声明为泛型。
  • 泛型不能是基本数据类型,需要使用基本数据类型的泛型可以写成其包装类。
		//List<int> list2 = new ArrayList<>();
		List<Integer> list2 = new ArrayList<>();

自定义泛型类

在类或接口中声明的泛型,可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值。但是,不能在静态方法中使用类的泛型

	// 泛型类:类中定义有不确定的类型
	public class Dict<T> {
		String dictName;
		int dictCount;
		T dictT;
        //泛型类下用了泛型的方法,报错,需要去掉static
		//public static void get(T dictT) {
		//	this.dictT = dictT;
		//}
        //泛型类下没用泛型的方法
        public static void set() {
			System.out.println("");
		}
	}

泛型方法和泛型类下的方法?

泛型方法:该泛型方法所在的类可以不是泛型类。往直观一点讲,方法中出现了泛型结构<>。
那么,泛型方法可以是静态的吗?可以,因为泛型参数是在调用方法时确定的,并非在实例化时确定的。

      public class GenericTest {
			public static void main(String[] args) {
				Dict<Float> dict = new Dict<>();
				dict.set1(0.0f);
				//调用泛型方法,泛型类型跟类的泛型没关系,不受影响
				dict.set2(" ");
				dict.set2(36);
				dict.set2(new ArrayList());
			}
		}

		//泛型类
		class Dict<T> {
			String dictName;
			int dictCount;
			//泛型类中的方法:如果调用了泛型则不能为静态
			public  void set1(T dictT) {
				System.out.println("我是泛型类下的方法");
			}
		    //泛型方法:可以为静态
			public  static <T> void set2(T dictT) {
				System.out.println("我是泛型方法");
			}
		}

泛型与继承

  • 如果类A是类B的父类,但是,G<A>不是G<B> 的父类(G是类或者接口),两个属于不同的类。所以不存在两者间的多态和向上转型。
  • 但是呢,A<G>仍然是B<G>的父类。

通配符

通配符:?
  • 利用通配符,创建二者的共同父类,G<A>G<B>的共同父类G<?>
  • 但是,不能往其中添加新数据,常用于赋值操作而已,仅能添加null;
  • 允许读取数据,读取数据的类型为object;

举例说明:定义List<?>List<Object>List<String>的公共父类。

        //不能添加数据,除了null
		List<?> list = new ArrayList<>();
        //list.add(16);//报错
        //list.add(" ");//报错
		list.add(null);
        //允许读取数据
        List<?> list = new ArrayList<>();
		List<String> list1 = new ArrayList<>();
		list1.add("newstring");
		list =list1;
		list.add(null);
		Object obj = list.get(0);
		System.out.println(obj);//newstring
有限制条件的通配符
  • G<? extends A>可以作为G<A>G<B>的父类,其中B是A的子类;即,可以作为所有继承于A类的类G<A的子类>的父类。
  • G<? super A>可以作为G<A>G<B>的父类,其中B是A的父类;即,可以作为所有A的父类的G<A的父类>的父类。
        // 下面举例类的关系:Earth extends Sun, Sun extends Universe
		List<? extends Sun> list1 = new ArrayList<>();// 可以作为List<Sun及其子类>的父类
		List<? super Sun> list2 = new ArrayList<>();// 可以作为List<Sun及其父类>的父类
		List<Universe> list3 = new ArrayList<>();
		List<Sun> list4 = new ArrayList<>();
		List<Earth> list5 = new ArrayList<>();
		list1 = list4;// 多态
		list2 = list4;//多态
		// 读取数据
		Sun s1 =list1.get(0);//获取的数据是Sun或者Sun的子类的对象,可以实现多态
		Earth e1 =(Earth)list1.get(0);//不强转会报错,因为获取的数据可能是Sun的对象,父类转子类需要强转
		Sun s2=(Sun)list2.get(0);//不强转会报错,获取的数据可能是Sun的父类,父类转子类需要强转
		Object o=list2.get(0);//不强转情况下,只能是Object
		// 写入数据
		list2.add(new Sun());//只能添加Sun本身,或者Sun的子类
        //因为list2存的可能是Sun及其父类,假设new的是Universe,但是list2中存储的是Sun,
        //即实际?=Sun,那么Universe作为父类是无法直接赋给子类的
		list2.add(new Earth());
		//list1.add();//无法添加数据,因为你无法确定存储的子类有多小
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:1024 设计师:我叫白小胖 返回首页

打赏作者

CodeKnocker_AQ

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值