2025年java 泛型引入及详解,泛型通配符使用示例,JUnit 单元类测试框架

java 泛型引入及详解,泛型通配符使用示例,JUnit 单元类测试框架一 引入 1 泛型是什么 泛型 顾名思义就是 广泛的数据类型 也就是说什么数据类型都可以 一般来说 我们见到的泛型就是这个样子 用 T 表示 如下所示 在类名后方申明泛型 T 接着就可以在成员变量 方法中使用泛型了 其中我们在 java 集合构架中以及以后将会广泛的应用到泛型

大家好,我是讯享网,很高兴认识大家。

一、引入

1、泛型是什么

泛型 ,顾名思义就是 广泛的数据类型,也就是说什么数据类型都可以。一般来说,我们见到的泛型就是这个样子,用 T 表示。如下所示,在类名后方申明泛型 T,接着就可以在成员变量、方法中使用泛型了。其中我们在java 集合构架中以及以后将会广泛的应用到泛型。

首先告诉大家ArrayList就是泛型之一。

首先让我们来看一个例子,认识一下泛型的作用之一。

在ArrayList 集合遍历中,我们又是在处理时将会用到泛型,但若保存了不同的对象,在遍历时就将报类型转换错误:

package fanxing.com; import java.util.ArrayList; @SuppressWarnings({"all"}) public class fanxingTest { public static void main(String[] args) { // 泛型: ArrayList<Dog> dogs = new ArrayList<Dog>();// 当我们这样写,表示ArrayList 集合中的元素只能是Dog 类型 // 如果加入的是Cat那编译器就会报错 dogs.add(new Dog("tom",6)); dogs.add(new Dog("小黄",10)); dogs.add(new Dog("招财",8)); // 在遍历使用get 和 set 方法时不用在向下转型 for (Dog dog :dogs) { System.out.println(dog.getName()+"-"+dog.getAge()); } } } class Cat{ private String name; private int age; public Cat(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } class Dog{ private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

讯享网

以上代码中,如果我们不使用泛型而同时存放了Cat 类对象和 Dog类对象,那在遍历时就将出错

那为了解决这个问题就可以参考以上代码,使用泛型,在生成ArrayList 对象时指定他所存储对象的类型。

另外泛型当然不仅仅只是为了解决这个问题啦,等到后面的题目时你就能感受到它的神奇之处了。

二、各种泛型定义及使用
 

那么参照上一段代码,让我们来看看泛型可以怎样在集合中使用:

讯享网package fanxing.com; import java.util.*; @SuppressWarnings({"all"}) public class GenericTest01 { public static void main(String[] args) { // 使用泛型,在HashSet中放入三个学生对象 HashSet<Student> students = new HashSet<>(); students.add(new Student("jact",19)); students.add(new Student("tom",21)); students.add(new Student("jhon",18)); Iterator<Student> iterator = students.iterator(); while (iterator.hasNext()) { Student next = iterator.next(); System.out.println(next.getName()+"-"+next.getAge()); } // 用HashMap 存放 key 为name ,value 为学生对象 HashMap<String, Student> map = new HashMap<>(); map.put("jact",new Student("jact",19)); map.put("tom",new Student("tom",23)); map.put("majunyi",new Student("majunyi",20)); Set<Map.Entry<String, Student>> entries = map.entrySet(); Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator(); while (iterator1.hasNext()) { Map.Entry<String, Student> next = iterator1.next(); Student value = next.getValue(); System.out.println(value.getName()+"-"+value.getAge()); } } } class Student{ private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

另外在对进一步了解之前让我们看看泛型的一些注意事项吧:

package fanxing.com; import java.util.ArrayList; import java.util.List; // 泛型使用注意事项 @SuppressWarnings({"all"}) public class GenericTest02 { public static void main(String[] args) { // 注意: E 不能是基本数据类型,比如 int、float、double 等 // 1. 在给泛型指定具体类型以后,可以传入该类型或其子类对象 Pig<A> aPig = new Pig<A>(new A()); aPig.f(); // class fanxing.com.A Pig<A> aPig1 = new Pig<A>(new B()); aPig1.f(); // class fanxing.com.B // 2.泛型的使用形式 List<Integer> list1 = new ArrayList<Integer>(); // 在实际开发中可以简写,并且更为推荐下面一种写法 List<Integer> list2 = new ArrayList<>(); ArrayList<Pig> pigs = new ArrayList<>(); // 3. 如果是这样写 泛型默认是 Object 类 ArrayList arrayList = new ArrayList();//等价于 ArrayList<Object> arrayList = new ArrayList<>(); arrayList.add("majnuyi");//默认添加为 Object Tige tige = new Tige(); /* 相当于: class Tige{ Object e; public Tige(){ } public Tige(Object e) { this.e = e; } } */ } } class Tige<E>{ E e; public Tige(){ } public Tige(E e) { this.e = e; } } class A{} class B extends A{} class Pig<E>{ E e; public Pig(E e) { this.e = e; } public void f(){ System.out.println(e.getClass()); } }

1.泛型接口:

讯享网package fanxing.com; // 泛型接口 public class Generic_interface { public static void main(String[] args) { } } / * 1. 接口中静态成员也不能使用泛型 * 2. 泛型接口的类型,在继承接口或者实现接口时确定,如果没有指定默认Object 类 */ interface Usb<U,R>{ // 普通方法中,可以使用接口泛型 R get(U u); void hi(R r); void run(R r1,R r2,U u1,U u2); // 在 jdk8 中,可以在接口中使用默认方法,也可以使用泛型 default R method(U u){ return null ; } } // 当我们去实现IA 接口时,因为 IA 在继承Usb 接口时指定了U 为String ,T 为 Double // 在实现Usb 接口中方法时,使用String 代替 U,用 Double 代替 T class AA implements IA{ @Override public Double get(String s) { return null; } @Override public void hi(Double aDouble) { } @Override public void run(Double r1, Double r2, String u1, String u2) { } @Override public Double method(String s) { return IA.super.method(s); } } // 在继承接口时指定泛型 interface IA extends Usb<String,Double>{ } / * 在实现接口时指定泛型接口的类型 * 给 U指定了 Integer, 给 T 指定了 Float */ class BB implements Usb<Integer,Float>{ @Override public Float get(Integer integer) { return null; } @Override public void hi(Float aFloat) { } @Override public void run(Float r1, Float r2, Integer u1, Integer u2) { } @Override public Float method(Integer integer) { return Usb.super.method(integer); } } / 不指定时默认为Object 类 class CC implements Usb{// 等价于 给 U 和 T 指定了 Object,不建议这种写法,建议下面的写法 } */ class CC implements Usb<Object,Object>{ @Override public Object get(Object o) { return null; } @Override public void hi(Object o) { } @Override public void run(Object r1, Object r2, Object u1, Object u2) { } @Override public Object method(Object o) { return Usb.super.method(o); } }

2.泛型方法:

package fanxing.com; // 泛型方法 public class Generic_main { public static void main(String[] args) { Car car = new Car(); car.fly("majnuyi",5784);// 调用时传入参数,自动装箱,编译器,就会确定类型 car.fly(845,""); Fish<String, Double> fish = new Fish<>(); System.out.println(fish.hi("zhanguhgds")); } } // 泛型方法可以放在普通类中,也可以放在泛型类中 class Car{// 普通类 public void run(){ } // 说明泛型方法 // 1. <T,R> 就是泛型 // 2. 是提供给fly使用 public <T,R> void fly(T t,R r){// 泛型方法 System.out.println(t+"-"+r); } } class Fish<T,R>{ T t; R r; public void run(){ } // 泛型方法 public <U,M> void eat(U u,M m){ } /* 注意: 下面方法只是使用了泛型,并不是泛型方法 是 hi方法使用了类声明的泛型 另外 泛型方法不仅可以使用类声明的泛型,还可以使用泛型方法中声明的泛型 并且,普通方法使用泛型,必须是类声明的泛型 */ public T hi(T t){ return t; } } 

3.自定义泛型类:

讯享网package fanxing.com; // 自定义泛型 @SuppressWarnings({"all"}) public class GenericTest04 { public static void main(String[] args) { Tiges<Double, String, Integer> Tige = new Tiges<Double, String, Integer>("jhon"); Tige.setT(10.87); Tige.setM(68); Tige.setR("majunyi"); System.out.println(Tige); // 输出 Tiges{name='jhon', r=majunyi, m=68, t=10.87} // 以下代码也对,默认Object 类 Tiges tiges = new Tiges("tom"); tiges.setR("bfhjdrgh"); tiges.setT("zhang"); tiges.setM(3568); System.out.println(tiges);// 输出 Tiges{name='tom', r=bfhjdrgh, m=3568, t=zhang} } } // 1. Tiges 后面有泛型,所以我们将 Tiges 称为泛型类 // 2. T、R、M为泛型标识符,一般使用大写字母 // 3. 泛型标识符可以有多个 // 4. 普通成员可以是泛型(方法、属性) // 5. 使用泛型数组时不能进行初始化 // 6. 静态方法中不能使用类的泛型 class Tiges<T,R,M>{ String name; R r; M m; T t; // T[] ts=new T[8]; 错误,因为数组类型无法确定下来,无法在内存中开辟空间 public Tiges(String name) { this.name = name; } public Tiges( R r, M m, T t) { this.r = r; this.m = m; this.t = t; } /* 因为静态是和类相关的,在类加载时,对象还没有被创建 所以,如果静态方法和静态属性中定义了泛型,JVM 就无法完成初始化 static R r2; public static void f(M m){ } */ public String getName() { return name; } public void setName(String name) { this.name = name; } public R getR() { return r; } public void setR(R r) { this.r = r; } public M getM() { return m; } public void setM(M m) { this.m = m; } public T getT() { return t; } public void setT(T t) { this.t = t; } @Override public String toString() { return "Tiges{" + "name='" + name + '\'' + ", r=" + r + ", m=" + m + ", t=" + t + '}'; } }

那么通过以上对泛型的了解,让我们来做一个间的泛型题目吧:

package fanxing.com; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; // 泛型练习 @SuppressWarnings({"all"}) public class GenericTest03 { public static void main(String[] args) { /* 定义Employee类,该类包括 private: neme,sal,birthday(MyDate)类, 其中 birthday 为 MyDate类包括: year,month,day,要求: 使用泛型 添加三个员工存入ArrayList 中,并调用sort 方法传入 Comparator 对象(使用泛型) 先按照name 排序,name相同则按照日期先后 最后遍历集合 */ ArrayList<Employee> employees = new ArrayList<>(); employees.add(new Employee("tom",20000,new MyDate(2002,12,29))); employees.add(new Employee("jact",30000,new MyDate(2001,10,7))); employees.add(new Employee("tom",50000,new MyDate(2003,9,19))); System.out.println(employees+"\n\n\n"); employees.sort(new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { // 先对传入的参数判断 if (!(o1 instanceof Employee) && !(o2 instanceof Employee)){ System.out.println("类型不匹配!!!"); return 0; } // 先比较名字 字典顺序 int i = o1.getName().compareTo(o2.getName()); // 如果 i!=0;则直接返回 if (i!=0){ return i; }// name相同则按照日期先后 // ====因为下面是对日期的比较,代码较乱,不利于代码封装,因此 将日期比较交给 MyDate 类完成== // 封装后,将来的可复用性和可维护性将大大提升 else { return o1.getBrithday().compareTo(o2.getBrithday()); } } }); Iterator<Employee> iterator = employees.iterator(); while (iterator.hasNext()) { Employee next = iterator.next(); System.out.println(next); } } } class Employee{ private String name; private double Sal; private MyDate brithday; public Employee(String name, double sal, MyDate brithday) { this.name = name; Sal = sal; this.brithday = brithday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSal() { return Sal; } public void setSal(double sal) { Sal = sal; } public MyDate getBrithday() { return brithday; } public void setBrithday(MyDate brithday) { this.brithday = brithday; } @Override public String toString() { return "\nEmployee{" + "name='" + name + '\'' + ", Sal=" + Sal + ", brithday=" + brithday + '}'; } } class MyDate implements Comparable<MyDate>{ private int year; private int month; private int day; public MyDate(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } @Override public String toString() { return "MyDate{" + "year=" + year + ", month=" + month + ", day=" + day + '}'; } @Override public int compareTo(MyDate o) {// 把比较放在这里 int yearMinus=year- o.getYear(); // 继续判断 if (yearMinus!=0){ return yearMinus; } else { int monthMinus=month-o.getMonth(); // 再判断 if (monthMinus!=0){ return monthMinus; } else { return day-o.getDay(); } } } }

其中,并调用sort 方法传入 Comparator 对象(使用泛型) 先按照name 排序,name相同则按照日期先后,关于Comparator的使用在我的另一篇文章(java 集合构架)中我有详细介绍.

4.泛型通配符使用:

讯享网package fanxing.com; // 泛型继承和通配符 import java.util.ArrayList; import java.util.List; public class Generic_Extends { public static void main(String[] args) { Object o=new String("majuniy");// 没有问题 System.out.println(o); // 泛型不具备继承性 以下使用错误 //List<Object> list=new ArrayList<String>(); / * 泛型通配符 *1. <?> :支持任意泛型类型 * 2. <? extends A> : 支持 A类以及A 类的子类,规定了泛型的上限 * 3. <? super A> : 支持 A类以及A 类的父类,不限于直接父类,规定了泛型的下限 包括 Object 类 */ ArrayList<Object> list1 = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); ArrayList<X> list3 = new ArrayList<>(); ArrayList<Y> list4 = new ArrayList<>(); ArrayList<Z> list5 = new ArrayList<>(); // 如果是 <?> :支持任意泛型类型 printCollenction1(list1); printCollenction1(list2); printCollenction1(list3); printCollenction1(list4); printCollenction1(list5); // 如果是 <? extends X> : 支持 X类以及X 类的子类,规定了泛型的上限 // printCollenction2(list2); 错误使用 printCollenction2(list3); printCollenction2(list4); printCollenction2(list5); // 如果是 <? super Z> : 支持 Z类以及Z 类的父类,不限于直接父类,规定了泛型的下限 包括 Object 类 printCollenction3(list1); printCollenction3(list3); printCollenction3(list4); printCollenction3(list5); } // 编写几个方法: public static void printCollenction1(List<?> c){ // 支持任意泛型类型 for (Object o :c) { System.out.println(o); } } public static void printCollenction2(List<? extends X> c){// 支持 X类以及X 类的子类,规定了泛型的上限 for (Object o :c) { System.out.println(o); } } public static void printCollenction3(List<? super Z> c){ // 支持 Z类以及Z 类的父类,不限于直接父类,规定了泛型的下限 包括 Object 类 for (Object o :c) { System.out.println(o); } } } class X{ } class Y extends X{ } class Z extends Y{ }

5. JUnit 单元类测试框架:

关于java JUnit 测试类的使用我就为大家准备了IDEA操作截图
      

那首先让我们先来了解一下什么是 JUnit 测试框架呢:

平时我们调用方法都是:

public class GenericTest05 { public static void main(String[] args) { test1(); } public static void test1(){ System.out.println("调用成功!!!"); } }

而且该方法必须是静态方法才能被调用成功。


讯享网

那来看看有了Junit 时:

 

有了JUnit 我们可以单独调用一个方法,并且它可以是非静态方法。

这样就可以大大减少我们在测试时对 main方法的修改,下面为大家展示 如何生成JUnit 测试框架:

1. 首先在要测试的方法前面写上 @Test

2. 然后点击报错灯(当然你也可以快捷键进入)选择将" JUnit 5.70”添加到类路径中,因为我已经配置过过了,因此在这里就没有显示,当然JUnit 4也是可以的,但现在更推荐使用JUnit 5.7,跟上技术的更新嘛。

3. 然后点击确定,稍微等待一下他进行配置完成以后就可以了,配置一次就可以了,以后如果还需要使用的话,输入 @Test 回车即可生成 

 好了,通过以上对泛型的学习呢,让我们来看看一道关于泛型较为系统的题吧:

讯享网package fanxing.com; import org.junit.jupiter.api.Test; import java.util.*; // 泛型练习以及 JUnit 测试框架 / * 要求: * 定义泛型类DAD<T> ,在其中定义一个Map成员变量,Map键为String类型,值为T类型 * 分别创建以下方法: *1. public void save(String id,T entity) 保存T类型对象到 Map 中 * 2. public T get(String id) 从Map 中取出id 对应的对象 *3. public void update(String id,T entity) 替换map 中key 对应的 Value * 4. public List<T> list() 返回map 中的所有T对象并存入 List集合,ArrayList * 5. public void delete(String id){ // 删除id 对应的对象 * *定义一个 User类该类有: * private int id; * private int age; * private String name; * * 创建DAD对象,分别调用save、get、 update、list、delete 方法操作User 对象 *使用JUnit 单元测试类进行测试 */ public class GenericTest05 { public static void main(String[] args) { } @Test public void testList(){ DAD<User> dao = new DAD<>(); // 添加 dao.save("001",new User(2002,19,"tom")); dao.save("002",new User(2001,20,"jact")); dao.save("003",new User(2003,18,"john")); List<User> list=dao.list();//输出看看T(User) 对象 System.out.println(list); // 将"003" 改为 dao.update("003",new User(2000,21,"风煞")); list=dao.list(); System.out.println(list); // 删除 ”001“ dao.delete("001"); list=dao.list(); System.out.println(list); // 单独获取"003" System.out.println(dao.get("003")); // 好了其他方法我就不一一演示了 } } class User{ private int id; private int age; private String name; public User(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "\nUser{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } } class DAD<T>{ private Map<String,T> map = new HashMap<>(); public void save(String id,T entity){// 保存T类型对象到 Map 中 map.put(id, entity); } public T get(String id){// 从Map 中取出id 对应的对象 return map.get(id); } public void update(String id,T entity){// 替换map 中key 对应的 Value if(map.containsKey(id)){// 先判断是否存在该对象 map.put(id,entity);// 若存在添加即替换 } else System.out.println("不存在需要替换的对象"); } public List<T> list(){// 返回map 中的所有T对象并存入 List集合,ArrayList // 遍历Map List<T> list=new ArrayList<>(); Set<Map.Entry<String, T>> entries = map.entrySet(); Iterator<Map.Entry<String, T>> iterator = entries.iterator(); while (iterator.hasNext()) { Map.Entry<String, T> next = iterator.next(); list.add(next.getValue()); } return list; } public void delete(String id){ // 删除id 对应的对象 if(map.containsKey(id)){ map.remove(id); } else System.out.println("不存在需要删除的对象"); } }

谢谢大家,有问题欢迎评论哦!!!

小讯
上一篇 2025-01-09 13:16
下一篇 2025-04-03 19:29

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/58188.html