泛型
泛型的概念
Java泛型是一种在编译时期进行类型检查和类型安全的机制,它可以让我们在编写代码时指定参数或返回值的类型,从而提高代码的可读性和可维护性。
孩童的智商可能还不足以理解泛型的具体概念和实现细节,但是我们可以通过类比的方式来帮助他们理解。
可以将泛型比喻为一个容器,这个容器可以存放不同类型的对象。就像一个玩具箱,可以放入不同种类的玩具,但是每个玩具都有自己的特点和功能。
孩童可以将泛型看作是一个多功能的盒子,可以根据需要放入不同类型的对象。比如,可以有一个盒子专门放玩具车,另一个盒子专门放娃娃。这样,当孩童需要玩具车时,就可以从玩具车盒子中取出玩具车,而不会取出其他类型的玩具。
在Java中,泛型的使用方式类似于上面的例子。我们可以定义一个泛型类或泛型方法,然后在使用时指定具体的类型。这样,编译器会在编译时期进行类型检查,确保我们只能使用指定类型的对象。
例如,我们可以定义一个泛型类Box,用来存放不同类型的对象:
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
然后,孩童可以将Box看作是一个玩具箱,可以放入不同类型的玩具:
Box<Car> carBox = new Box<>();
carBox.setItem(new Car());
Box<Doll> dollBox = new Box<>();
dollBox.setItem(new Doll());
在上面的例子中,carBox是一个Box对象,它只能存放Car类型的对象;dollBox是另一个Box对象,它只能存放Doll类型的对象。这样,孩童就可以根据需要选择不同类型的玩具箱,并确保只能取出相应类型的玩具。
通过这种类比的方式,孩童可以初步理解Java泛型的概念和用法,尽管可能还不完全理解其中的技术细节。随着孩童的成长和学习,他们可以逐渐深入理解泛型的原理和更复杂的用法。
泛型的格式
-
<类型>
:指定一种类型的格式,这里的类型可以看成是形参 -
<类型1, 类型2……>
:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参 -
将来具体调用时,给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
泛型的好处
-
把运行时期的问题提到了编译期间
-
避免了强制数据类型转换的问题
泛型类的定义和使用
-
泛型类的定义格式
-
格式:
修饰符 class 类名<类型>{}
-
范例:
public class Generic<T>{}
此处 T 可以是任意标识符,常见的有 T、E、K、V 等形式的参数,常用于表示泛型
-
demo:
创建一个泛型类
package com.itxiaosi.demo01;
/**
* @Classname : Generic
* @Description : TODO 泛型类
* @Author : lin_refuel@qq.com
*/
public class Generic<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
定义一个学生类
package com.itxiaosi.demo01;
/**
* @Classname : Student
* @Description : TODO 学生类
* @Author : lin_refuel@qq.com
*/
public class Student {
//学生类的两个基本属性
private String name; //姓名
private int age; // 年龄
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试泛型类
package com.itxiaosi.demo01;
/**
* @Classname : GenericTest
* @Description : TODO 泛型类测试
* @Author : lin_refuel@qq.com
*/
public class GenericTest {
public static void main(String[] args) {
//TODO 泛型括号里面的类型必须是引用数据类型
//1.String类型放入
Generic<String> strG = new Generic<>();
strG.setT("我是一个字符串");
String str = strG.getT();
System.out.println(str); // 我是一个字符串
System.out.println("====================");
//2.Integer类型放入
Generic<Integer> intG = new Generic<>();
intG.setT(9527);
Integer interG = intG.getT();
System.out.println(interG); // 9527
System.out.println("===================");
//3.定义的学生类放入
Generic<Student> StuG = new Generic<>();
StuG.setT(new Student("小肆",20));
Student Stud = StuG.getT();
System.out.println(Stud);
}
}
运行结果:
泛型方法
-
泛型方法的定义格式
-
格式:
修饰符 <类型> 返回值类型 方法名(类型名 变量名){}
-
范例:
public <T> void show(T t)
-
个人理解泛型方法,可以避免同一个方法多次重载
package com.itxiaosi.demo02;
/**
* @Classname : Generic
* @Description : TODO 泛型方法
* @Author : lin_refuel@qq.com
*/
public class Generic {
//泛型方法
public <T> void show(T t){
System.out.println(t);
}
}
泛型方法测试
package com.itxiaosi.demo02;
import com.itxiaosi.demo01.Student;
/**
* @Classname : GenericTest
* @Description : TODO 泛型方法测试类
* @Author : lin_refuel@qq.com
*/
public class GenericTest {
public static void main(String[] args) {
Generic Gen = new Generic();
Gen.show("莲");
Gen.show(1231);
Gen.show(new Student("小肆",12));
}
}
运行结果:
泛型接口
-
泛型接口的定义格式
-
格式:
修饰符 interface 接口名<类型>{}
-
范例:
public interface Generic<T>{}
-
demo:
泛型接口实现类
泛型接口测试
运行结果
泛型通配符
为了表示各种泛型 List 的父类,可以使用类型通配符
-
类型通配符:
<?>
-
List<?>
:表示类型未知的 List,它的元素可以匹配 任意类型 -
这种带通配符的 List 仅表示它是 各种泛型 List 的父类,并不能把元素添加到其中
如果说我们不希望
List<?>
是任何泛型 List 的父类, 只希望他代表某一泛型 List 的父类,可以使用类型通配符的上限
-
类型通配符上限:
<? extends 类型>
-
List<? extends Number>
:它表示类型是 Number 或者其子类型
除了可以指定类型通配符的上限,我们还可以指定类型通配符的下限
-
类型通配符的下限:
<? super 类型>
-
List<? super Number>
:它表示的类型是 Number 或者其父类型
可以理解为泛型限制符,不能随意写入
package com.itxiaosi.demo04;
import com.itxiaosi.demo01.Student;
import java.util.ArrayList;
import java.util.List;
/**
* @Classname : demo01
* @Description : TODO 泛型通配符(泛型的限制)
* @Author : lin_refuel@qq.com
*/
public class demo01 {
public static void main(String[] args) {
//<?> : 尖括号里面的?等同于是 Object ,是所有类的父类,可以随意写入
List<?> list = new ArrayList<Object>();
//可以随意放入其他引用数据类型
List<?> list01 = new ArrayList<Integer>();
List<?> list02 = new ArrayList<String>();
List<?> list03 = new ArrayList<Student>();
//****************************************************
//<? extends> // 表示继承的上限例如 <? extends Number> 写入泛型只能写入 Number和继承Number的子类
List<? extends Number> list07 = new ArrayList<Number>();
List<? extends Number> list04 = new ArrayList<Integer>();
List<? extends Number> list05 = new ArrayList<Float>();
List<? extends Number> list06 = new ArrayList<Double>();
//例如:写入一个没有继承Number的类或者Number的类则是超过上限,出现异常
// List<? extends Number> list08 = new ArrayList<Object>();
// List<? extends Number> list08 = new ArrayList<Student>();
//********************************************************
//<? super>//表示泛型的下限,例如 <? super Number> 可以写入 Number和Number的父类,不能写入Number的子类
List<? super Number> list09 = new ArrayList<Object>();
List<? super Number> list10 = new ArrayList<Number>();
// Integer是Number的子类,超过了Number的下限,
// List<? super Number> list11 = new ArrayList<Integer>();
}
}
可变的参数
可变参数有称为参数个数可变,用作方法的参数出现,那么方法参数的可数就是可变的
-
格式:
修饰符 返回值类型 方法名(数据类型...变量名)
-
范例:
public static int sum(int...a)
注意:
可变参数实际上是一个数组
如果普通参数和可变参数结合使用的话,可变参数需要放到形参列表的最后
demo
package com.itxiaosi.demo05;
/**
* @Classname : demo01
* @Description : TODO 可变长的参数
* @Author : lin_refuel@qq.com
*/
public class demo01 {
public static void main(String[] args) {
// 定义一个两个数相加方法,输出两个数的相加后的值
System.out.println(Myadd(1,2));
//TODO 通过可变长参数实现
System.out.println(Myadd2(1,2,3,4,5,6));
}
/**
* 可变长参数的使用
* @param a 可变长的参数
* @return 结果
*/
private static int Myadd2(int ...a) {
int sum = 0;
for(int i : a){
sum+=i;
}
return sum;
}
/**
* 两个数相加
* @param a 第一个数
* @param b 第二个数
* @return 结果
*/
private static int Myadd(int a, int b) {
return a+b;
}
}
可变长参数的使用
所属类 | 方法名 | 说明 |
---|---|---|
Arrays | public static <T> List <T> asList(T...a) | 返回由可变长组成的固定大小的列表 |
List | public static <E> List <E> of(E...e) | 返回包含任意数量元素的不可变列表 |
Set | public static <E> Set <E> of(E...e) | 返回一个包含任意数量元素的不可变集合 |
list.of和Set.of是jdk9之后才有
demo:
package com.itxiaosi.demo05;
import java.util.Arrays;
import java.util.List;
/**
* @Classname : demo02
* @Description : TODO 可变参数的使用
* @Author : lin_refuel@qq.com
*/
public class demo02 {
public static void main(String[] args) {
// 调用方法 aslist(可变参数)
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); // 返回的是一个list集合
System.out.println(list); // 1,2,3,4,5
// *************************************
// asList返回的集合是否可以进行 TODO 删除,增加,修改
// list.add(6);//不能增加
// list.remove(2);//不能删除一个值
list.set(2,1314);// 可以修改里面的值
System.out.println(list);
}
}