10_泛型

泛型

泛型的概念

jdk1.5提供的一个内容,泛型实际上就是将数据类型作为一个参数。
1.理解什么是泛型?
对比一下:
 void method(int num){}==>num称之为参数(将数据作为一个参数)
 调用method方法只能传递int类型的数据(只能传递int类型数据)
 
    如果想要通过一个方法能够传递不同的数据类型(重载可以实现,泛型实现)
    
 泛型:所谓泛型与上述不同,是将数据类型作为一个参数,编写方法或者类的时候,不需要声明其数据类型。
 void method(? num)   
2.为什么要用到泛型?
 比如使用动态数组的时候?   
int[] num=new int[10]
 ....   
 这样的动态数组只能放置int类型的数据
 升级
Object[] obj=new Object[10];
obj[0]=1;//默认进行
obj[1]=new Student();//默认进行

这样我们的obj可以放置任意类型的数据
编译期间方任意内容都可以编译通过
Student stu=(Student)obj[index];   //运行的时候检查类型,存在类型转换异常的风险。。。 

今天提供泛型好处:
<1>.将类型的判断从运行期,提前到了编译期间(编译期间就会检查类型,如果类型不对直接编译不通过)
<2>.能够避免运行的时候出现类型转换异常的风险。。。

泛型类

基本格式:
public class 类名<泛型参数1,泛型参数2,...>{
    private 泛型参数1 属性名1;
    private 泛型参数2 属性名2;
    ....
}
说明:
一般来说:泛型参数会使用一些单个大写字母表示:K,T,V,E,...(理论上还可以使用其他的字母)

注意事项:
<1>.创建对象的时候声明数据类型,声明的是什么类型就只能存放对应类型的数据。
<2>.如果创建对象的时候没有声明具体的数据类型,那么默认类型为Object;
<3>.定义的类型必须是引用类型,不能基本数据类型。
<4>.同一个泛型类,创建多个泛型类型不同的对象,最终这多个对象属于同一个类型。    
代码实现:
设计泛型类型:
public class Generic<E> {
	private E key;
	public Generic() {
		super();
	}
	public Generic(E key) {
		super();
		this.key = key;
	}
	public E getKey() {
		return key;
	}
	public void setKey(E key) {
		this.key = key;
	}
	@Override
	public String toString() {
		return "Generic [key=" + key + "]";
	}
}
测试:
	public static void main(String[] args) {
		Generic<Integer> g1=new Generic<Integer>();//Generic g1=new Generic();
		//1.编译的时候就会检查类型,只能存放整数类型的数据
		g1.setKey(123);
		System.out.println(g1);
		
		Generic<String> g2=new Generic<>();//Generic g2=new Generic();
		g2.setKey("admin");
		System.out.println(g2);
		
		//2.没有指定类型,那么默认可以存放任意类型的数据...
		Generic g3=new Generic();
		g3.setKey(123.456);
		System.out.println(g3);
		
		//1.g1,g2,g3属于同类吗? 是同类型
		//利用反射查看对象的数据类型
		System.out.println(g1.getClass().getSimpleName());
		System.out.println(g2.getClass().getSimpleName());
		System.out.println(g3.getClass().getSimpleName());
	} 

泛型接口

public interface 接口名<类型参数1,类型参数2,...>{
    
}

//1.非泛型类实现泛型接口的时候,必须指定类型,非泛型接口继承泛型接口的时候也必须指定类型
public class MyLinkedList implements MyList<String>{//==>必须指定类型
	@Override
	public void add(String ele) {
		
	}
}
public interface MySet extends MyCollection<String>{
	
}

//2.泛型类 实现泛型接口的时候可以不指定泛型的类型 ,或者泛型接口也可以不指定类型
代码实现:
public interface MyCollection<E> {
	void add(E ele);
}

继承
public interface MyList<E> extends MyCollection<E>{
	
}

实现
public class MyArrayList<E> implements MyList<E>{
	@Override
	public void add(E ele) {
		System.out.println(ele);
	}

}

总结:对于泛型类与泛型接口去继承或者实现另一个泛型接口的时候,子类泛型参数必须包含父类泛型参数
    子类的泛型参数可以有多个...

泛型方法

泛型方法的基本语法:
public <参数类型1> void/其他返回值  方法名(参数类型1 参数名...){}

//注意1:不是泛型方法,是成员方法
public E getKey() {
		return key;
}	

//注意2:静态的方法中使用了泛型参数,那么静态方法必须是泛型方法
public static <T> void method(T t){
    
}
代码实现:
public class Generic<K,V> {
	private K key;
	private V value;
	
	public K getKey() {
		return key;
	}
	public void setKey(K key) {
		this.key = key;
	}
	public V getValue() {
		return value;
	}
	public void setValue(V value) {
		this.value = value;
	}
	
	 //1.泛型方法(遵循就近原则)
	 //泛型方法中定义的泛型参数可以与类中的泛型参数同名,但是 使用的时候方法的泛型参数与类的泛型参数不是同一个。
	 //调用方法的时候去确定方法泛型参数的类型。
	public <K>void method1(K key) {// 泛型方法的 定义的泛型参数(与类上面的泛型参数无关)
		System.out.println("普通的泛型方法:"+key);
	}
	
	 //2.普通方法可以直接获取类上面的泛型参数
	public void method2(K key) {//K 类的泛型参数
		System.out.println("泛型类中的普通方法:"+key);
	}
	
	 //3.静态方法如果想得到泛型参数必须 变成泛型方法。
	public static<K> void method3(K key) {//静态方法拿不到类的泛型参数
		System.out.println("静态的泛型方法:"+key);
	}
	@Override
	public String toString() {
		return "Generic [key=" + key + ", value=" + value + "]";
	}
}
测试:
	public static void main(String[] args) {
		Generic<String, String> g1=new Generic<>();
		g1.setKey("jack");
		g1.setValue("abc");
		//1.普通泛型方法(方法参数类型不受类参数类型的影响)
		g1.method1(200);
		//2.普通方法 使用了类的泛型参数,必须与类的泛型参数相同
		g1.method2("admin");
		//3.静态泛型方法(方法参数类型不受类参数类型的影响)
		Generic.method3(123.456);
	}


泛型通配符

?:泛型通配符(可以匹配任意类型)

1.泛型通配符向上修饰 (当前类以及其子类)
? extends 应用类型

2.泛型通配符向下修饰 (当前类以及父类)super 应用类型
---------------------------------------------------------------------------------
public static void main(String[] args) {
		ArrayList<Animal> listAnimal=new ArrayList<>();//动物
		ArrayList<Pet> listPet=new ArrayList<>();//宠物
		ArrayList<Cat> listCat=new ArrayList<>();//小猫
		ArrayList<Dog> listDog=new ArrayList<>();//小狗
		//1.?:泛型参数类型任意
		method1(listAnimal);
		method1(listPet);
		method1(listCat);
		
		method1(listDog);
		//2.? super Cat:Cat类,以及其父类以及其父类的父类都可以放(上级类都可以)。。。
		method2(listCat);
		method2(listPet);
		method2(listAnimal);
		//3.? extends Pet类  可以是当前类以及其后代类。。。
		method3(listPet);
		method3(listCat);
		method3(listDog);
		//4.只能传递Animal类型
		method4(listAnimal);
	}
	//1.可以放任意类型泛型参数
	public static void method1(ArrayList<?> list) {
		System.out.println(list);
	}
	//2.泛型参数类型只能放当前类以及其父类(Cat类以及其父类)  上级类
	public static void method2(ArrayList<? super Cat> list) {
		System.out.println(list);
	}
	//3.泛型参数只能是当前类,以及其下级类(后代类)
	public static void method3(ArrayList<? extends Pet> list) {
		System.out.println(list);
	}
	//4.指定类型
	public static void method4(ArrayList<Animal> list) {
		System.out.println(list);
	}

泛型的嵌套

public class Generic<T>{
    
}

T:类型的参数(可以是任意引用类型)
Generic是什么类型?    引用类型 
Generic<Generic<String>> :泛型的嵌套
    
以ArrayList<E> 为例子:
也可以表示为:ArrayList<ArrayList<String>> list=...
    list.add(ArrayList元素);

代码示例:
public static void main(String[] args) {
		ArrayList<ArrayList<String>> list=new ArrayList<>();
		//list里面只能添加ArrayList类型的元素
		ArrayList<String> list1=new ArrayList<>();
		list1.add("apple");
		list1.add("banana");
		list1.add("watermelon");
		
		ArrayList<String> list2=new ArrayList<>();
		list2.add("pig");
		list2.add("cat");
		list2.add("dog");
		
		//将ArrayList类型的元素添加到list中
		list.add(list1);
		list.add(list2);
		System.out.println(list);
	}

泛型擦除

Generic<Integer> g1=new Generic<Integer>();//Generic g1=new Generic();
Generic<String> g2=new Generic<>();//Generic g2=new Generic();
Generic g3=new Generic();
//1.g1,g2,g3属于同类吗? 是同类型
//利用反射查看对象的数据类型
System.out.println(g1.getClass().getSimpleName());//Generic
System.out.println(g2.getClass().getSimpleName());//Generic
System.out.println(g3.getClass().getSimpleName());//Generic
总结:g1,g2,g3都属于Generic类型,编译完成之后,生成的class文件之后,会自动将泛型的参数去掉,运行期间g1,g2,g3都属于同类型	Generic<Integer>==>	Generic  ,Generic<String>==>Generic...
这个现象我们称之为泛型擦除。   
    
 泛型起到什么作用:
<1>.将检查类型提前到了编译期(如果类型不对,直接无法编译通过)
<2>.能够避免类型转换异常的风险。。。    

作业:

  1. 将自定义MyList自己写熟练,几个基本的方法使用熟练,泛型的

    public class MyList<E> {
    	//1.定义初始化长度
    	private Object[] list=new Object[10];
    	private int size;
    	/**
    	 * @description 将元素添加动态数组中...
    	 * @param E 新元素
    	 * */
    	public void add(E ele) {
    		//1.判断是否需要扩容
    		if(size==list.length) {
    			//2.开始扩容
    			Object[] newArr=new Object[size+(size>>1)];
    			//3.将旧数组中的数据搬到新数组中
    			for(int i=0;i<size;i++) {
    				newArr[i]=list[i];
    			}
    			//4.新数组替换旧数组
    			list=newArr;
    		}
    		//5.将你需要添加的数据放在数组中
    		list[size++]=ele;
    	}
    	
    	/**
    	 * @description 返回动态数组中实际的元素个数...
    	 * */
    	public int size() {
    		return size;
    	}
    	
    	/**
    	 * @description 根据下标获得元素的方法
    	 * @param index 返回元素对应的下标位置
    	 * */
    	public E get(int index) {
    		if(index>=0 &&index<size) {
    			return (E) list[index];
    		}
    		//1.如果下标越界抛出异常(告诉别人哪里错了)
    		throw new ArrayIndexOutOfBoundsException("数组越界...");
    	}
    	/**
    	 * @description 根据指定的index索引位置 修改数组中的数据...
    	 * @param index 修改的索引位置
    	 * @param ele 新元素
    	 * */
    	public void set(int index,E ele) {
    		if(index>=0&&index<size) {
    			list[index]=ele;
    		}else {
    			throw new ArrayIndexOutOfBoundsException("检索的位置不存在...");
    		}
    	}
    	
    	/**
    	 * @description 根据指定的索引位置进行删除 
    	 * @param index 删除的下标
    	 * */
    	public void remove(int index) {
    		if(index>=0&&index<size) {
    			for(int i=index;i<size-1;i++) {
    				//1.将后面的元素搬到前一个位置
    				list[i]=list[i+1];
    			}
    			//2.最后一个元素置空
    			list[size-1]=null;
    			size--;//没减少一个元素,长度-1
    		}else {
    			throw new ArrayIndexOutOfBoundsException("检索的位置不存在...");
    		}
    	}
    	/**
    	 * @description 根据元素进行删除
    	 * @param ele 需要删除的元素
    	 * */
    	public void remove(E ele) {
    		int index=indexOf(ele);
    		remove(index);
    	}
    	
    	/**
    	 * @description 根据指定元素返回其在数组中第一次出现的索引位置,不存在返回-1
    	 * @param ele 需要检索位置的元素 
    	 **/
    	public int indexOf(E ele) {
    		for(int i=0;i<size;i++) {
    			if(ele.equals(list[i])){
    				return i;
    			}
    		}
    		return -1;
    	}
    	/**
    	 * @description 根据指定元素返回其在数组中最后一次出现的索引位置,不存在返回-1
    	 * @param ele 需要检索位置的元素 
    	 **/
    	public int lastIndexOf(E ele) {
    		for(int i=size-1;i>=0;i--) {
    			if(ele.equals(list[i])){
    				return i;
    			}
    		}
    		return -1;
    	}
    	/**
    	 * @description 根据指定元素判断其是否存在 存在 返回true 不存在返回false
    	 * @param ele 需要检索位置的元素 
    	 * */
    	public boolean contains(E ele) {
    		for(int i=0;i<size;i++) {
    			if(ele.equals(list[i])){
    				return true;
    			}
    		}
    		return false;
    	}
    	/**
    	 * @description 根据指定下标交换集合中元素的位置
    	 * @param i,j 交换的下标
    	 * */
    	public void swap(int i,int j) {
    		if(i!=j&&i>=0&&i<size&&j>=0&&j<size) {
    			Object temp=list[i];
    			list[i]=list[j];
    			list[j]=temp;
    		}else {
    			throw new ArrayIndexOutOfBoundsException("检索的位置不存在...");
    		}
    		
    	}
    	
    	/**
    	 * @description 改写toString()方法 方便测试数据...
    	 * */
    	@Override
    	public String toString() {
    		Object[] objs=new Object[size];
    		for(int i=0;i<size;i++) {
    			objs[i]=list[i];
    		}
    		return Arrays.toString(objs);
    	}
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值