java--泛型

举报
brucexiaogui 发表于 2021/12/30 00:18:11 2021/12/30
【摘要】 java--泛型 一、什么是泛型   什么是泛型:   java5开始出现的一种对Java语言类型的一种拓展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数类型时指定的类型占位符,就好比方法的形式参数是实际参数的占位符一样.泛型能保证大型应用程序的类型安全和良好的维护性; &nb...

java--泛型

一、什么是泛型

 

  • 什么是泛型:

 

  1. java5开始出现的一种对Java语言类型的一种拓展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数类型时指定的类型占位符,就好比方法的形式参数是实际参数的占位符一样.
  2. 泛型能保证大型应用程序的类型安全和良好的维护性;

 

  • 使用泛型的优势:

 

  1. 类型安全,使编译器对泛型定义的类型做判断限制.如保证TreeSet里的元素类型必须一致;
  2. 消除强制类型的转换,如,使用Comparable比较时每次都需要类型强转;

二、泛型类

 

  • 在类声明时通过一个标识符表示类中某个字段的类型或者某个方法的返回值或参数的类型,这样在类声明或实例化的时候只要指定自己需要的类型就ok。
  • 类型参数规范:推荐使用规范-常见的泛型,泛型只保存在源文件中,class文件中不存在;也就是说在编译阶段就会丢失,基本数据类型不能作为泛型类型;

K 键,比如映射的键  key的类型

V 值,比如Map的值 value类型

E 元素,比如Set<E>  Element表示元素,元素的类型

 

T 泛型,Type的意思

 


      class 类名<泛型类型1,泛型类型2……>{
      	泛型类型  变量名;
      	泛型类型  方法名(){}
      	返回值类型 方法名(泛型类型 变量名){}
  
 

泛型类使用实例


      package generic;
      /**
       * 坐标点
       */
      public class Point<T> {//定义一个类的时候,采用T来表示一种类型,仅仅表示占位符;,但是此时真正的类型尚未确定,使用的时候才确定
     	private T x;
     	private T y;
     	public T getX() {
     		return x;
      	}
     	public void setX(T x) {
     		this.x = x;
      	}
     	public T getY() {
     		return y;
      	}
     	public void setY(T y) {
     		this.y = y;
      	}
      }
      ----------------------------
      package generic;
      import java.util.Date;
      import java.util.HashMap;
      import java.util.HashSet;
      import java.util.Map;
      import java.util.Set;
      import java.util.TreeSet;
      public class PointDemo {
     	public static void main(String[] args) {
     		//使用泛型类
     		//给定泛型类型的时候,只能给定引用类型,
     		//创建一个带泛型的类的对象时,尽量保证编译类型的泛型和运行类型的泛型一致
      		Point<Integer> p = new  Point<Integer>();
      		p.setX(1);
      		p.setY(1);
      		Point<Double> p2 = new Point<Double>();
     		Double x = p2.getX();
      		Point<String> p3 = new Point<String>();
     		String x3 = p3.getX();
     		//============================
      		Set<String> s = new HashSet<String>();//创建一个容器对象,应该在创建的时候就明确是装什么的
      		s.add("a");
     		//s.add(1);//
     		//此时就能保证集合里元素类型一致,
      		Set<Integer> treeSet = new  TreeSet<Integer>();
     		//规定key只能是String,value是Date
      		Map<String,Date> map = new HashMap<String,Date>();
     		// V put(K key, V value) 
     		Date v = map.put("", new Date());
     		//V get(Object key) 
     		Date val = map.get("");
      	}
      }
  
 

 

三、泛型通配符

 

  • 在进行引用传递的时候泛型类型必须匹配才可以传递,否则编译不通过;
  • 使用 ? ,表示未知类型的泛型对象:

 

 

  1. List<?> 表示未知元素的List集合;
  2. 这种带通配符的List仅表示各种泛型List的父类,并不能把元素添加入集合中;
  3. List<?> list = new ArrayList<>(); list.add(1);//ERROR

 

 

  • public void show(List<?> list){}

 

 

  1. //表示可接受任意类型的List集合

 

 

四、泛型上下限

 

  • 设置泛型对象的上限使用extends,表示参数类型只能是该类型或该类型的子类:

 

 

  1. 声明对象:类名<? extends 类> 对象名
  2. 定义类:类名<泛型标签 extends 类>{}

 

 

  • 设置泛型对象的下限使用super,表示参数类型只能是该类型或该类型的父类:

 

 

  1. 声明对象:类名<? super 类> 对象名称
  2. 定义类:类名<泛型标签 extends类>{}

 

demo例子


      public static void  show(List<? extends Number> l){
      }
      public static void  show(List<? super String> l){
      }
  
 

 

实例


      package generic;
      import java.util.ArrayList;
      import java.util.List;
      public class GenericDemo3 {
     	public static void main(String[] args) {
     		/**
       List<?> l = new ArrayList<Integer>();
       l.add(1);//ERROR
       */
      		List<Integer> l1 = new ArrayList<>();//new ArrayList<Integer>();
      		show(l1);
      		List<String> l2 = new ArrayList<>();
      		show(l2);
      		List<Double> l3 = new ArrayList<>();
      		show(l3);
      		List<Number> l4 = new ArrayList<>();
      		show(l4);
      		List<Object> l5 = new ArrayList<>();
      		show(l5);
     		//========================
      		up(l1);
      		up(l3);
      		up(l4);
     		//up(l2);//ERROR
     		//=================
     		//down(l1); //ERROR
     		//down(l2); //ERROR
     		//down(l3); //ERROR
      		down(l4);
      		down(l5);
     		//没有继承关系
     		//Point<Number> p = new Point<Integer>();//ERROR
      	}
     	/**
       *
       * ? <= Number
       * 设置泛型对象的上限使用extends,表示参数类型只能是该类型或该类型的子类:
       */
     	public static void up(List<? extends Number> l){
     		for (Object object : l) {
      			System.out.println(object);
      		}
      	}
     	/**
       * ? >= Number
       * 设置泛型对象的下限使用super,表示参数类型只能是该类型或该类型的父类:
       */
     	public static void down(List<? super Number> l){
     		for (Object object : l) {
      			System.out.println(object);
      		}
      	}
     	public static void show(List<?> l){
     		//l.add(?)
     		for (Object object : l) {
      			System.out.println(object);
      		}
      	}
      }
  
 

五、泛型和子类继承限制

 

  • 对象的多态性,我们可以

 

 

  1. 父类  对象 = new  子类();

 

 

  • 但是在父类泛型类型和子泛型类型之间不存在这种关系:

 

 

 

  1. 类<Number> 对象 = new 类<Integer>();×

 

 


      Object obj = new Person();Person<Object>  p = new Person<String>();×
  
 

 

六、泛型接口

 

 

  • java5后,可以声明泛型接口,声明方式和声明泛型类是一样的。

 

 

public interface IDAO<T>{}

 

 

 

  • 泛型接口子类有两种方式:

 

 

直接在子类后申明泛型;

 

 

在子类实现的接口中给出具体的泛型类型

 

 

 


      public class DaoImpl<T> implements IDAO<T>{
      }
      public class DaoImpl implements IDAO<String> {
      }
  
 

七、泛型方法

 

  • 方法中可定义泛型参数,形参的参数类型就是实参的类型。
  • 格式:

 

 

 

<泛型标签> 返回值类型 方法名([泛型标签 参数]...)

 

 

 


      public static <T> T show(T param){
     	return param;
      }
      .....main.....{
      	System.out.println(show(new Date()));
      	System.out.println(show("cditcast"));
      }
  
 

 

实例  泛型方法


      package generic;
      import java.util.Arrays;
      import java.util.Date;
      import java.util.List;
      class  A{
      }
      public class GenericMethodDemo {
     	public static void main(String[] args) {
     		//调用方法的时候,才能确定其真正的类型
      		show(1);
      		show("");
      		show(new A());
     		//====================
      		System.out.println("-->"+show2(1).getClass());
      		System.out.println("-->"+show2(new Date()).getClass());
      		System.out.println("-->"+show2(new int[]{}).getClass());
     		//=======================
     		//Arrays :static <T> List<T> asList(T... a) 返回一个固定大小的列表。 
     		int[] arr   = {1,2,3};
      		List<int[]> list = Arrays.asList(arr);
      		System.out.println("list==" + list);
     		for (int[] is : list) {
      			System.out.println("--->>>"+is);
     			for (int i : is) {
      				System.out.println(i);
      			}
      		}
     		//================
      		Integer[] arr2 = {7,8,9};
      		List<Integer> list2  = Arrays.asList(arr2);
      		System.out.println("-list2-->"+list2);
     		for (Integer i : list2) {
      			System.out.println(i);
      		}
     		//========可变参数========
      		list2 = Arrays.asList(1,2,3,4);
      		List<String> s  = Arrays.asList("","","");
      	}
     	/**
       *
       * @param t
       * @return
       */
     	public static <T> T show2(T t) {
     		return t;
      	}
     	/**
       * <T>表示声明使用 T 表示一种类型, 作用域仅仅在该方法类
       * @param t
       */
     	public static <T> void show(T t) {
      		System.out.println(t.getClass());//获得对象的真正类型
      	}
      }
  
 

 

实例 泛型嵌套

 


      package generic;
      import java.util.HashMap;
      import java.util.Iterator;
      import java.util.Map;
      import java.util.Set;
      /**
       * 泛型嵌套
       */
      public class MapDemo {
     	public static void main(String[] args) {
      		Map<Integer,String> map = new HashMap<>();
      		map.put(1, "A");
      		map.put(2, "B");
      		map.put(3, "C");
      		map.put(4, "D");
     		//迭代出Map里的每一个key 和 value
      		Set<Map.Entry<Integer,String>> entrys = map.entrySet();
      		Iterator<Map.Entry<Integer, String>> it = entrys.iterator();
     		while(it.hasNext()){
      			Map.Entry<Integer, String> entry = it.next();//每一个Enter
     			Integer key = entry.getKey();
     			String value = entry.getValue();
      		}
      	}
      }
  
 

八、泛型擦除

 

  • 在严格的泛型代码里,带泛型声明的类总应该带着类型参数。但是为了和老的Java代码保持一致,也允许在使用带泛型声明的类时不指定类型参数,若没有为这个泛型类指定类型参数则该类型参数被称做一个原始类型,默认是该声明参数时指定的最上限类型;
  • 当把一个具有泛型信息的对象赋给另一个没有泛型信息的变量时,则所有在尖括号之间的类型信息都被扔掉。

 

比如List<String> 类型转换成List,则该List对集合元素的类型检查变成了变量的上限即Object。

 

 

九、泛型擦除和转换


      public class Demo {
     	public static void main(String[] args) {
      		List<Integer> li = new ArrayList<>();
      		li.add(1);
      		List<String> ls = null;
     		//ls = li;不能转换
     		List list = li;
      		ls = list;//不会报错,只有未经检查警告,此时list实际引用的是List<Integer>
      		System.out.println("-->" + ls.get(0));//企图当做String类型对象取出
      	}
      }
  
 

 

实例 泛型擦除和转换

 


      package generic;
      import java.util.ArrayList;
      import java.util.List;
      /**
       * 搞泛型类的时候,只能写泛型上限,不能写下线
       *
       * @param <T>
       */
      class Emp<T extends Number> {
      	T value;
      	T get() {
     		return value;
      	}
      }
      public class GenericDemo4 {
     	public static void main(String[] args) {
     		/**
       * 允许在使用带泛型声明的类时不指定类型参数,若没有为这个泛型类指定类型参数则该类型参数被称做一个原始类型,默认是该声明参数时指定的最上限类型
       * ;
       */
     		Object o = new Emp().get();
     		Number n = new Emp().get();
     		//==============================
     		//泛型擦除
      		List<Integer> l1 = new ArrayList<Integer>();
      		l1.add(1);
      		l1.add(2);
     		Integer val = l1.get(0);
     		List l2  = l1;//把带有泛型信息的对象付给不带泛型信息的变量,//泛型擦除
     		//=============
      		List<String> l3 = new ArrayList<String>();
      		l3 = l2;//造成堆污染
      		l3.add("A");
      		System.out.println(l3.size());
     		//java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
     		//String ret = l3.get(0);//好比String s = 1;//ERROR
     		String ret = l3.get(2);//YES
      		System.out.println(ret);
      	}
      }
  
 

 

 

 

 

文章来源: brucelong.blog.csdn.net,作者:Bruce小鬼,版权归原作者所有,如需转载,请联系作者。

原文链接:brucelong.blog.csdn.net/article/details/80020680

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。