JAVA泛型基础

好,我们聊一聊泛型。泛型允许在不指定类、接口方、法的具体类型下,通过一个抽象的类型参数动态设定。

就是说我事先不知道你要传入什么类型的参数,我先拿一个对象去代替你的参数写在我的方法里。等到编译时系统会自动将这个对象转换成你给的参数去执行,保证了代码的安全性和可读性。

泛型中的这个对象我们通常用具体的大写字母来表示,可以任意写,但有常见约束 :

T (Type):表示任意类

E (Element):表示集合中的元素类型

K (Key):表示键值对中的键

V (Value):表示键值对中的值

N (Number):表示数值类型

我们用具体实例来做展示,我们先创建一个类名叫Gen的类,传入泛型参数。再创建一个Test文件,里面写我们的main方法。

想要传入泛型到类里,只需在类名后面加一个尖括号,里面填写想要表示的泛型参数即可。既class Gen<T>{} 这样我们就拿到了泛型的参数。当我们想创建和T类型的方法或属性时,就可以直接将类型用T替换就可以了。

T会在定义对象时也就是在编译时就确定了,所以当传入类型不符合时会报错。而且当一个类中需要多个泛型时,可以在尖括号里填写多个泛型,并用","隔开。

如何调用泛型类呢?只需要Gen<> 对象名 = new Gen<>(); 在尖括号里填写引用类型即可。作为初学者经常犯的错误就是会在尖括号里传基本数据类型,而泛型是不支持基本数据类型的,所以会报错。

有小伙伴可能早就发现了,我们使用ArraySet、ArrayList、HachMap时传入的参数都是基本数据类型的包装类。没错,这里就用到的是泛型,所以必须传入引用数据类型。

给大家出道题:在Gen类中创建一个private修饰的泛型数组和set方法,在Test文件中调用set方法分别创建一个String类型和一个Integer类型的数组并打印出结果。

在Gen中创建泛型ArrayList:

java 复制代码
    //创建泛型数组
    private ArrayList<T> arr = new ArrayList<T>();
	//简写形式(建议使用)
	private ArrayList<T> arr2 = new ArrayList<>();

创建set方法:

java 复制代码
    //创建set方法给arr属性中添加T类型元素
	public void setArr(T va) {
		arr.add(va);
	}

创建get方法和print方法获取和打印arr中元素:

java 复制代码
    //创建get方法
	public ArrayList<T> getArr(){
		ArrayList<T> arr2 = new ArrayList<T>();
		for(T va:arr) {
			arr2.add(va);
		}
		return arr2;
	}
	//创建打印方法
	public void printAll(ArrayList<T> arr) {
		for(T va:arr) {
			System.out.println(va);
		}
	}

好,我们试试方法能不能用。先在main方法里创建一个Gen类对象,再在数组中添加几个元素:(这里需要注意,如果我们没有在尖括号里添加参数,那么会默认泛型为Object)

java 复制代码
        //创建对象并填入引用类型
		Gen<String> gen1 = new Gen<>();
		Gen<Integer> gen2 = new Gen<>();
		//使用set方法填入内容
		
		gen1.setArr("小明");
		gen1.setArr("小芳");
		gen1.setArr("小红");
		gen1.setArr("小鹏");
		gen1.setArr("小越");
		
		gen2.setArr(1);
		gen2.setArr(2);
		gen2.setArr(3);
		gen2.setArr(4);
		gen2.setArr(5);
		
		

获取并打印:

java 复制代码
        //获取并打印元素
		gen1.printAll(gen1.getArr());
		gen2.printAll(gen2.getArr());

结果正如我们想的那样输出了两个存放不同类型的数组。

我们再说说泛型的通配符,泛型的通配符常用用于方法的参数声明以及返回声明,以增强方法对不同类型和参数的兼容性。其实就是让方法不必绑定一个具体的泛型,而是接受或返回一个泛型类型的任意成员,从而提供代码的灵活性和复用性。

我们说无法直接创建通配符类型的对象,必须传入一个"具体类型的对象",使其方法中用通配符声明的参数类型。这个"具体类型对象"可以是我们自己写的类,也可以是java提供的类。就比如说接下来我要讲的例子中就是用ArrayList作为具体对象传入方法。

再强调一下,通配符仅能用于"定义类型"的场景,而不能用于"创建具体类型"或"声明泛型占位符"。(<T>不能写成<?>)

三种通配符类型:

1.<?>:无界通配符,支持任意泛型类型

2.<? extends A>:上界通配符,规定了泛型的上界,支持A以及A的子类

3.<? super A>:下界通配符,规定了泛型的下界,支持A以及A的父类

我们举个例子:我们在Test类里创建一个main方法,同时另外创建三个具有相互继承关系的类。

java 复制代码
public class Test {
	public static void main(String[] args) {	
	}	
}
class A{
}
class B extends A{
}
class C extends B{
}

我们在Test中写入三种方法,分别调用不同的通配符类型作为参数。

java 复制代码
	public static void printArrAll(ArrayList<?>arr) {
		//相当于<? extends Object>
		for(Object obj:arr) {
			System.out.println(obj);
		}
	}
	public static void printArrExtends(ArrayList<? extends B>arr) {
		//上界通配符,上界是B
		for(Object obj:arr) {
			System.out.println(obj);
		}
	}
	public static void printArrSuper(ArrayList<? super B>arr) {
		//下界通配符,下界是B
		for(Object obj:arr) {
			System.out.println(obj);
		}
	}

分别使用Object、A、B、C、作为引用类型创建ArrayList对象。

java 复制代码
		//创建不同类型的ArrayList对象,验证泛型上下界通配符
		ArrayList<Object>arr1 = new ArrayList<>();
		ArrayList<A>arr2 = new ArrayList<>();
		ArrayList<B>arr3 = new ArrayList<>();
		ArrayList<C>arr4 = new ArrayList<>();

使用三种不同的方法分别调用我们创建的对象。我们知道泛型在编译时会被确定,所以可以根据报错情况判断是否能使用此引用类型。

java 复制代码
		//调用无界通配符:
		printArrAll(arr1);
		printArrAll(arr2);
		printArrAll(arr3);
		printArrAll(arr4);
		
		//调用上界通配符
		printArrExtends(arr1);
		printArrExtends(arr2);
		printArrExtends(arr3);
		printArrExtends(arr4);
		
		//调用下界通配符
		printArrSuper(arr1);
		printArrSuper(arr2);
		printArrSuper(arr3);
		printArrSuper(arr4);

正如我们所设想的一样,上界通配符无法调用父类引用类型。下界通配符无法调用子类引用类型,而无界通配符可以调用所有的引用类型包括最上级Object引用类型。

相关推荐
时间行者_知行合一2 小时前
Spring如何选择依赖注入方式
java
田里的水稻2 小时前
C++_数据类型和数据结构
java·数据结构·c++
兔兔西2 小时前
【数据结构、java学习】数组(Array)
java·数据结构·算法
是2的10次方啊2 小时前
并发容器的艺术:从ConcurrentHashMap到BlockingQueue的完美协奏
java
007php0072 小时前
Go语言面试:传值与传引用的区别及选择指南
java·开发语言·后端·算法·面试·golang·xcode
XerCis2 小时前
Python的RSS/Atom源解析库feedparser
开发语言·python
algonaut2 小时前
adobe acrobat 安装到使用再到PDF编辑【适合小白,只看一篇就够!!!】
java·开发语言·其他·pdf
boonya3 小时前
Java JVM核心原理与面试题解析
java·开发语言·jvm
g_i_a_o_giao3 小时前
Android8 binder源码学习分析笔记(一)
android·java·笔记·学习·binder·安卓源码分析