泛型

概述:

​ 泛型是代表未来的任意引用数据类型,不确定的数据类型,没法书写具体类型名称,所以Java中使用字母来暂时的代表未来的数据类型格式:<字母> <字母1,字母2> <字母1字母2,字母3>

注意:

​ 字母可以是任意的字母【一般使用大写字母 常见 E T K V】

​ 一个泛型的字母的个数可以任意的 【一般使用1个字母】

​ 一个<>可以写多个泛型 泛型和泛型之间使用 逗号 隔开

使用:

​ 使用<大写字母>格式来声明泛型,

​ 泛型只有声明了之后才可以使用,

​ 泛型使用后真正使用的时候需要具体化【实例化】

好处:

​ 1、提供代码的安全性,把运行时的异常提前到编译时发生。

​ 2、避免了强制的类型转换

代码示例:

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

public class GenericDemo {
	public static void main(String[] args) {
		//创建集合
		List<String> list = new ArrayList<String>();
		//list.add(100); //未定义泛型的时候可以添加,定义后编译报错
		list.add("java");
		
		
		//创建迭代器对象
		Iterator<String> iterator = list.iterator();
		while (iterator.hasNext()) {
//			Object next = iterator.next(); //此时返回的是Object类型
//			String s = (String)next; //没有泛型实例化需要强制类型转换
//			System.out.println(s.startsWith("j") ); //true
			
			System.out.println(iterator.next().startsWith("j")); //true
		}
	}
}

泛型类

概述:

​ 具有泛型的类就叫做泛型类

​ 类提前定义了一个未来的数据类型,类中的变量就可以使用这个泛型

格式:

修饰符 class 类名 < E > { 类的内容 }

泛型类的泛型实例化时机:

​ 创建类对象的时候需要制定具体的数据类型

练习

定义一个泛型类,只能在这个类的头部进行增删操作

分析:

​ 1、定义一个类 需要在类名后面声明泛型【不知道】

​ 2、类中含有一个可以操作头部的元素,类的属性可以是一个LinkedList集合对象

​ 3、通过定义方法操作属性的首元素
代码示例:

import java.util.LinkedList;

public class GenericClass<T> {
	
	//定义属性 类的属性可以是一个集合对象
	LinkedList<T> list = new LinkedList<T>();
	
	//头部添加元素
	public void addFirst(T t) {
		list.addFirst(t);
	}
	//删除头部元素
	public void removeFirst() {
		list.remove();
	}
	@Override
	public String toString() {
		return "GenericClass [list=" + list + "]";
	}	
}
测试类:
public class TestGenericClass {
	public static void main(String[] args) {
		//创建泛型类的实例化对象
		GenericClass<String> genericClass = new GenericClass<String>();
		
		genericClass.addFirst("abcd");
		genericClass.addFirst("java");
		genericClass.addFirst("123");		
		System.out.println(genericClass);
		
		genericClass.removeFirst();
		System.out.println(genericClass);
	}
	
}

泛型的方法

概述:

​ 具有泛型声明的方法就叫做泛型方法

​ 自己在方法上声明一个未来的数据类型,之后方法中就可以使用这个数据类型

格式:

普通方法:

		修饰符 <泛型> 返回值类型 方法名(参数列表) {
				方法体
		}

静态方法:

		修饰符 static <泛型> 返回值类型 方法名(参数列表) {
				方法体
		}

注意事项:

1、方法上面一旦声明泛型 方法体中就可以使用该泛型
2、静态方法的泛型声明位置必须在static和返回值类型之间
3、普通方法没有声明泛型,可以使用类的泛型
4、静态方法没有声明泛型,不可以使用类的泛型,方法中就不可以出现泛型使用,要想使用泛型必须自己声明

泛型方法的泛型的实例化时机:

​ 方法被调用传入实际参数的时候
泛型被实例化的时候,泛型就消失

练习

定义一个方法,可以交换任意类型数组中的两个元素

分析:

​ 交换数组两个元素的位置 方法从外界得到 指定的数组 指定两个
​ 元素的索引值
代码示例

import java.util.Arrays;

public class GenericMethod2 {
	
	public static void main(String[] args) {
		Integer[] arr = {10,20,30};
		GenericMethod2 genericMethod2 = new GenericMethod2();
		exchangeArr(arr, 0, 2);
		System.out.println(Arrays.toString(arr)); //[30, 20, 10]
		
	}
	
	//泛型方法的练习方法
	public static <T> void exchangeArr(T[] ts , int index1, int index2) {
		T temp = ts[index2];
		ts[index2] = ts[index1];
		ts[index1] = temp;
	}

}

泛型接口:

在接口名后面声明泛型的接口就是泛型接口

泛型实例化时机:

1、创建实现类对象的时候必须实例化接口中的泛型【实现类实现接口时接口没有实例化泛型 继承给类】

​ 2、子接口或实现类实现的时候接口本身实例化泛型

代码示例:

接口:
public interface InterfaceA<T> {
	
	void show(T t);
}

实现类1public class ClassA implements InterfaceA<String>{

	@Override
	public void show(String t) {
	}

}
实现类2public class ClassB<T> implements InterfaceA<T>{

	// 实现类实现接口的时候没有实例化 接口没有实例化泛型 泛型就被类继承 需要声明同样类型的泛型
	//泛型想要实例化: 在创建实现类对象的时候实例化
	@Override
	public void show(T t) {
	}


	public static void main(String[] args) {
		//创建实现类对象时候,实例化泛型
		ClassB<String> classB = new ClassB<String>();
	}

}

泛型通配符

概述:

​ 给别人传给我们的泛型匹配的一个符号【对泛型的一种实例化】,使用<?>表示泛型通配符

比如:

Collection接口中的方法:boolean containsAll(Collection<?> c);

​ 方法接收一个传入的集合,集合里面肯定有具体的数据,数据对应就有具体的数据类型,未来传什么数据类型数据的集合进来不知道,但是方法准备容器c来接收, c的类型知道是Collection, 但是接收集合的数据类型不知道,传入的集合的数据的数据类型,其实就是对泛型的实例化,c容器接收的时候不知道具体的实例化的数据类型,就使用?代替了实例化的具体类型

泛型通配符的权限:

上限:<? extends 类型>

​ 传入参数的实例化类型只能是类型自己或类型的子类类型

下限:<? super 类型>

​ 传入参数的实例化类型只能是类型自己或类型的父类类型

代码示例:

import java.util.ArrayList;

public class GenericWildcardDemo {
	
	public static void main(String[] args) {
		ArrayList<Integer> list1 = new ArrayList<Integer>();
		ArrayList<String> list2 = new ArrayList<String>();
		ArrayList<Number> list3 = new ArrayList<Number>();
		ArrayList<Object> list4 = new ArrayList<Object>();
		
		show(list1); // ? 就是Integer
		show(list2); // ? 就是String
		show(list3); // ? 就是Number
		show(list4); // ? 就是Object
		
		show01(list1); // ? 实例化的类型是Integer 是Number的子类  ? 就匹配上了
     	//show01(list2); // ? 要求必须是Number家族 子类和自己  泛型的实例化类型是String,所以报错
		show01(list3); // ? 实例化的类型是Number ? 就匹配上了
		//show01(list4); // ? 实例化的类型是Object 太顶层了   ?就匹配不上了
		
		// show02(list1);// ? 实例化的类型是Integer super是找Number自己及父类 ?就匹配不上了
		// show02(list2);// ? 要求必须是Number家族 父类和自己  泛型的实例化类型是String
		show02(list3);// ? 实例化的类型是Number 正好 ? 就匹配上了
		show02(list4);// ? 实例化的类型是Object 是Number的顶层父类 ? 就匹配上了
	}

	
	public static void show(ArrayList<?> list) {
	}
	//传入参数的实例化类型只能是类型自己或类型的子类类型
	public static void show01(ArrayList<? extends Number> list) {
	}
	//传入参数的实例化类型只能是类型自己或类型的父类类型
	public static void show02(ArrayList<? super Number> list) {
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值