当前位置: 首页 > news >正文

Java笔记029-泛型

泛型

泛型的理解和好处

看一个需求

  1. 请编写程序,在ArrayList中,添加3个Dog对象

  1. Dog对象含有name和age,并输出name和age(要求使用getXxx)

先用传统的方法来解决->引出泛型

package com15.generic;import java.util.ArrayList;/*** @author 甲柒* @version 1.0* @title Generic01* @package com15.generic* @time 2023/3/1 16:41*/
@SuppressWarnings({"all"})
public class Generic01 {public static void main(String[] args) {ArrayList arrayList = new ArrayList();arrayList.add(new Dog("旺财", 10));arrayList.add(new Dog("小黑", 1));arrayList.add(new Dog("大黄", 8));//假如不小心加入了一只猫arrayList.add(new Cat("招财猫", 16));//23行抛出异常ClassCastException//遍历for (Object o : arrayList) {Dog dog = (Dog) o;//向下转型Object -> DogSystem.out.println(dog.getName() + "-" + dog.getAge());}}
}//1. 请编写程序,在ArrayList中,添加3个Dog对象
//2. Dog对象含有name和age,并输出name和age(要求使用getXxx)
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;}
}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;}
}

使用传统方法的问题分析

  1. 不能对加入到集合ArrayList中的数据类型进行约束(不安全)

  1. 遍历的时候,需要进行类型转换,如果集合中数据量较大,对效率有影响

用泛型来解决上面的问题

ArrayList<Dog> arrayList = new ArrayList<Dog>();

package com15.generic;import java.util.ArrayList;/*** @author 甲柒* @version 1.0* @title Generic02* @package com15.generic* @time 2023/3/1 16:57*/
@SuppressWarnings({"all"})
public class Generic02 {public static void main(String[] args) {//传统方法解决=>使用泛型//解读//1.当ArrayList<Dog>表示存放放到ArrayList集合中的元素是Dog类型//2.如果编译器发现添加的类型,不满足要求,就会报错//3.在遍历的时候,可以直接取出Dog类型而不是Object//4.public class ArrayList<E> {} E称为泛型,那么Dog->EArrayList<Dog> arrayList = new ArrayList<Dog>();arrayList.add(new Dog("旺财", 10));arrayList.add(new Dog("小黑", 1));arrayList.add(new Dog("大黄", 8));//假如不小心加入了一只猫
//        arrayList.add(new Cat("招财猫", 16));//抛出异常ClassCastException//遍历System.out.println("====使用泛型====");for (Dog o : arrayList) {System.out.println(o.getName() + "-" + o.getAge());}}
}//1. 请编写程序,在ArrayList中,添加3个Dog对象
//2. Dog对象含有name和age,并输出name和age(要求使用getXxx)
//3.使用泛型解决问题
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;}
}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;}
}

泛型的好处

  1. 编译时,检查添加元素的类型,提高了安全性

  1. 减少了类型转换的次数,提高了效率

不使用泛型

Dog-加入->Object-取出->Dog//放入到ArrayList会先转成Object,再取出时,还需要转换成Dog

使用泛型

Dog->Dog->Dog//放入时,和取出时,不需要类型转换,提高效率

  1. 不再提示编译警告

泛型的介绍

int a = 10;

理解:泛(广泛)型(类型)=>Integer, String, Dog

  1. 泛型又称参数化模型,是JDK5.0出现的新特性,解决数据类型的安全性问题

  1. 在类声明或实例化时只要指定好需要的具体的类型即可

  1. Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮

  1. 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数模型

package com15.generic;/*** @author 甲柒* @version 1.0* @title Generic03* @package com15.generic* @time 2023/3/1 18:30*/
public class Generic03 {public static void main(String[] args) {//注意:特别强调,E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型Person<String> person = new Person<>("甲柒");person.show();//String/*解读class Person<E>{String s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型public Person(String s) {//E也可以是参数类型this.s = s;}public String f(){//返回类型使用Ereturn s;}}*/Person<Integer> person1 = new Person<Integer>(100);person1.show();//Integer/*class Person{Integer s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型public Person(Integer s) {//E也可以是参数类型this.s = s;}public Integer f(){//返回类型使用Ereturn s;}}*/}
}//泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型
//,或者是某个方法的返回值的类型,或者是参数模型
class Person<E> {E s;//E表示s的数据类型,该数据类型在定义Person对象的时候指定,即在编译期间,就确定E是什么类型public Person(E s) {//E也可以是参数类型this.s = s;}public E f() {//返回类型使用Ereturn s;}public void show() {System.out.println(s.getClass());}
}

泛型的语法

泛型的声明

intterface接口<T>{}和class类<K, V>{}

//比如:List,ArrayList

说明:

  1. 其中,T,K,V不代表值,而是表示类型

  1. 任意字母都可以,常用T表示,是Type的缩写

泛型的实例化

要在类名后面指定类型参数的值(类型),如:

  1. List<String> strList = new ArrayList<String>();

  1. Iterator<Customer> iterator = customers.iterator();

泛型语法和使用

泛型使用举例

举例说明,泛型在HashSet,HashMap的使用情况

练习:

  1. 创建3个学生对象

  1. 放入到HashSet中学生对象

  1. 放入到HashMap中,要求Key是String name,Value就是学生对象

  1. 使用两种方式遍历

package com15.generic;import java.util.*;/*** @author 甲柒* @version 1.0* @title GenericExercise* @package com15.generic* @time 2023/3/1 20:11*/
public class GenericExercise {public static void main(String[] args) {//HashSet<Student> hashSet = new HashSet<Student>();hashSet.add(new Student("tom", 16));hashSet.add(new Student("jerry", 6));hashSet.add(new Student("tom", 18));hashSet.add(new Student("mike", 32));//遍历System.out.println("++++++增强for遍历hashSet中的对象+++++");for (Student student : hashSet) {System.out.println(student);}//使用泛型后,下面的语句就报错
//        hashSet.add(300);System.out.println("++++++while遍历hashSet中的对象+++++");Iterator<Student> iterator = hashSet.iterator();while (iterator.hasNext()) {Student student = iterator.next();System.out.println(student);}//2.使用泛型方式给HashMap放入3个对象HashMap<String, Student> hashMap = new HashMap<String, Student>();hashMap.put("tom", new Student("tom", 30));hashMap.put("smith", new Student("smith", 22));hashMap.put("甲柒", new Student("甲柒", 30));hashMap.put("價柒", new Student("價柒", 30));//迭代器Entry/*public Set<Map.Entry<K,V>> entrySet() {Set<Map.Entry<K,V>> es;return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;}*/Set<Map.Entry<String, Student>> entries = hashMap.entrySet();Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator();System.out.println("========遍历iterator1中的对象========");while (iterator1.hasNext()) {Map.Entry<String, Student> entry = iterator1.next();System.out.println(entry.getKey() + "-" + entry.getValue());}}
}//        1. 创建3个学生对象
//        2. 放入到HashSet中学生对象
//        3. 放入到HashMap中,要求Key是String name,Value就是学生对象
//        4. 使用两种方式遍历
class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

泛型使用的注意事项和细节

  1. interface List<T>{},public class HashSet<E>{}.....

说明:T,E只能是引用类型,不能是基本数据类型

判断下列语句是否正确

List<Integer> list = new ArrayList<Integer>();//ok
List<int> list2 = new ArrayList<int>();//错误
  1. 在指定泛型具体类型后,可以传入该类型或者其子类型

  1. 泛型使用形式

List<Integer> list1 = new ArrayList<Integer>();
List<Integer> list1 = new ArrayList<>();
  1. 如果这样写

List list3 = new ArrayList();//默认给他的泛型是[<E> E就是Object]

package com15.generic;import java.util.ArrayList;
import java.util.List;/*** @author 甲柒* @version 1.0* @title GenericDetail* @package com15.generic* @time 2023/3/1 21:10*/
@SuppressWarnings({"all"})
public class GenericDetail {public static void main(String[] args) {//1.给泛型指向数据类型是 要求 必须是 引用类型,// 不能是 基本数据类型(byte,short,int,long,char,boolean,float,double)List<Integer> list = new ArrayList<Integer>();//ok
//        List<int> list2 = new ArrayList<int>();//错误//2.说明//因为E指定了A类型,构造器传入了new A()//在给泛型指定具体类型后,可以传入该类型或者其子类型Pig<A> aPig = new Pig<A>(new A());aPig.f();Pig<A> aPig2 = new Pig<A>(new B());aPig2.f();//3.泛型的使用形式ArrayList<Integer> list1 = new ArrayList<Integer>();List<Integer> list2 = new ArrayList<Integer>();//在实际开发中,往往简写//编译器会进行类型推断,推荐使用下面写法ArrayList<Integer> list3 = new ArrayList<>();List<Integer> list4 = new ArrayList<>();ArrayList<Pig> pigs = new ArrayList<>();//4.如果是这样写 泛型默认是 ObjectArrayList arrayList = new ArrayList();//等价ArrayList<Object> arrayList = new ArrayList<>();arrayList.add("XX");/*public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;}*/Tiger tiger = new Tiger();}
}class Tiger<E> {E e;public Tiger() {}public Tiger(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());//运行类型}
}

泛型练习题

定义Employee类

  1. 该类包含:private成员变量name,sal,birthday,其中birthday为MyDate类的对象

  1. 为每一个属性定义getter,setter方法

  1. 重写toString方法输出name,sal,birthday

  1. MyDate类包含:private成员变量month,day,year;并为每一个属性定义getter,setter方法

  1. 创建该类的3个对象,并把这些对象放入ArrayList集合中(ArrayList需要使用泛型来定义),对集合中的元素进行排序,并遍历输出:

排序方式:调用ArrayList的sort方法,传入Comparator对象[使用泛型],先按照name排序,如果name相同,则按生日日期的先后排序。[即:定制排序]

package com15.generic;import java.util.ArrayList;
import java.util.Comparator;/*** @author 甲柒* @version 1.0* @title GenericExercise02* @package com15.generic* @time 2023/3/5 18:22*/
//@SuppressWarnings({"all"})
public class GenericExercise02 {public static void main(String[] args) {Employee employee1 = new Employee("tom", 3000.00, new MyDate(1988, 9, 27));Employee employee2 = new Employee("tom", 2700.00, new MyDate(1969, 9, 6));Employee employee3 = new Employee("甲柒", 6900.00, new MyDate(2000, 12, 30));ArrayList<Employee> employees = new ArrayList<>();employees.add(employee1);employees.add(employee2);employees.add(employee3);System.out.println("employees=" + employees);System.out.println("====对员工进行排序====");employees.sort(new Comparator<Employee>() {@Overridepublic int compare(Employee o1, Employee o2) {//先按照name排序,如果name相同,则按照生日日期的先后排序。[即:定制排序]//先对传入的参数进行验证if (!(o1 instanceof Employee && o2 instanceof Employee)) {System.out.println("类型不正确!!!!");return 0;}//比较nameint i = o1.getName().compareTo(o2.getName());if (i != 0) {return i;}//下面是对birthday的比较,因此,最好把下面这段比较,放在MyDate类中//封装后,将来的可维护性,复用性就大大增强了
//                //如果name相同就继续比较,就比较birthday - year
//                int yearMinus = o1.getBirthday().getYear() - o2.getBirthday().getYear();
//                if (yearMinus != 0) {
//                    return yearMinus;
//                }
//                //如果year相同就继续比较,就比较birthday - month
//                int monthMinus = o1.getBirthday().getMonth() - o2.getBirthday().getMonth();
//                if (monthMinus != 0) {
//                    return monthMinus;
//                }
//                //如果month相同就继续比较,就比较birthday - day
//
//                return o1.getBirthday().getDay() - o2.getBirthday().getDay();return o1.getBirthday().compareTo(o2.getBirthday());}});System.out.println("=====排序后的结果=====");System.out.println(employees);}
}//定义Employee类
//1. 该类包含:private成员变量name,sal,birthday,
// 其中birthday为MyDate类的对象
//2. 为每一个属性定义getter,setter方法
//3. 重写toString方法输出name,sal,birthday
//4. MyDate类包含:private成员变量month,day,year;
// 并为每一个属性定义getter,setter方法
//5. 创建该类的3个对象,并把这些对象放入ArrayList集合中
// (ArrayList需要使用泛型来定义),对集合中的元素进行排序,并遍历输出:
//排序方式:调用ArrayList的sort方法,传入Comparator对象[使用泛型],
// 先按照name排序,如果name相同,则按生日日期的先后排序。[即:定制排序]
class Employee {private String name;private double sal;private MyDate birthday;public Employee(String name, double sal, MyDate birthday) {this.name = name;this.sal = sal;this.birthday = birthday;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSal() {return sal;}public void setSal(double sal) {this.sal = sal;}public MyDate getBirthday() {return birthday;}public void setBirthday(MyDate birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "\nEmployee{" +"name=" + name +", sal=" + sal +", birthday=" + birthday +'}';}
}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;}@Overridepublic String toString() {return year + "-" + month + "-" + day;}@Overridepublic int compareTo(MyDate o) {//把year-month-day比较放在这里//如果name相同就继续比较,就比较birthday - yearint yearMinus = year - o.getYear();if (yearMinus != 0) {return yearMinus;}//如果year相同就继续比较,就比较birthday - monthint monthMinus = month - o.getMonth();if (monthMinus != 0) {return monthMinus;}//如果month相同就继续比较,就比较birthday - dayreturn day - o.getDay();}
}

自定义泛型

自定义泛型类

基本语法

class 类名<T, R> {//...
//成员
}

注意细节

  1. 普通成员可以使用泛型(属性、方法)

  1. 使用泛型的数组,不能初始化

  1. 静态方法中不能使用类的泛型

  1. 泛型类的类型,是在创建对象时确定的(因为创建对形象时,需要指定确定类型)

  1. 如果在创建对象时,没有指定类型,默认位Object

package com15.customgeneric;import java.util.Arrays;/*** @author 甲柒* @version 1.0* @title CustomGeneric_* @package com15.customgeneric* @time 2023/3/5 23:01*/
@SuppressWarnings({"all"})
public class CustomGeneric_ {public static void main(String[] args) {//T=Double,R=String,M=IntegerTiger<Double, String, Integer> john = new Tiger<>("john");john.setT(10.98);//ok
//        john.setT("abc");//错误,类型不对System.out.println(john);Tiger tiger = new Tiger("john~~~");//ok,T默认为Object  (T=Object,R=Object,M=Object)tiger.setT("yy");//ok,因为T默认为Object,"yy"为String类型 是 Object子类System.out.println("tiger=" + tiger);}
}//解读
//1.Tiger后面泛型,所以把Tiger就称为自定义泛型类
//2.T,R,M泛型的标识符,一般是单个大写字母
//3.泛型标识符可以有多个
//4.普通成员可以使用泛型(属性、方法)
//5.使用泛型的数组,不能初始化
//6.静态方法中不能使用类的泛型
class Tiger<T, R, M> {String name;T t;//属性使用到泛型R r;M m;//因为数组在new不能确定T的类型,就无法在内存开空间
//    T[] ts = new T[8];T[] ts;//因为静态是和类相关的,在类加载时,对象还没有创建//所以,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化
//    static R r2;//错误R r3;//okpublic Tiger(String name) {this.name = name;}public Tiger(T t, R r, M m) {//构造器使用泛型this.t = t;this.r = r;this.m = m;}public Tiger(String name, T t, R r, M m) {//构造器使用泛型this.name = name;this.t = t;this.r = r;this.m = m;}public void m1(M m) {//ok}
//    public static void m2(M m) {//错误
//    }public String getName() {return name;}public void setName(String name) {this.name = name;}public T getT() {return t;}public void setT(T t) {this.t = t;}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;}@Overridepublic String toString() {return "Tiger{" +"name='" + name + '\'' +", t=" + t +", r=" + r +", m=" + m +", ts=" + Arrays.toString(ts) +", r3=" + r3 +'}';}
}

自定义泛型接口

基本语法

interface 接口名 <T, R....>{
}

注意细节

  1. 接口中,静态成员也不能使用泛型(这个和泛型类规定一样)

  1. 泛型接口的类型,在继承接口或者实现接口时确定

  1. 没有指定类型,默认为Object

package com15.customgeneric;/*** 泛型接口使用的说明* 1.在接口中,静态成员也不能使用泛型* 2.泛型接口的类型,在继承接口或者实现接口时确定* 3.没有指定类型,默认为Object** @param <U>* @param <R>*/
interface IUsb<U, R> {int n = 10;//U name;//不能这样使用//普通方法中,可以使用接口泛型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;}
}//在继承接口 指定泛型接口的类型
interface IA extends IUsb<String, Double> {}//当我们去实现IA接口时,因为IA在继承IUsu接口时,指定了U为String R为Double
//在实现IUsu接口的方法时,使用String替换U,是Double替换R
class AA implements IA {@Overridepublic Double get(String s) {return null;}@Overridepublic void hi(Double aDouble) {}@Overridepublic void run(Double r1, Double r2, String u1, String u2) {}
}//实现接口时,直接指定泛型接口的类型
//给U指定Integer给R指定了Float
//所以,当我们实现IUsb方法时,会使用Integer替换U,使用Float替换R
class BB implements IUsb<Integer, Float> {@Overridepublic Float get(Integer integer) {return null;}@Overridepublic void hi(Float aFloat) {}@Overridepublic void run(Float r1, Float r2, Integer u1, Integer u2) {}
}//没有指定类型,默认为Object
//建议直接写成class CC implements IUsb<Object, Object>
class CC implements IUsb {//等价class CC implements IUsb<Object, Object>@Overridepublic Object get(Object o) {return null;}@Overridepublic void hi(Object o) {}@Overridepublic void run(Object r1, Object r2, Object u1, Object u2) {}
}/*** @author 甲柒* @version 1.0* @title CustomInterfaceGeneric* @package com15.customgeneric* @time 2023/3/10 9:21*/
public class CustomInterfaceGeneric {public static void main(String[] args) {}
}

自定义泛型方法

基本语法

修饰符 <T, R...>返回类型 方法名(参数列表) {
}

注意细节

  1. 泛型方法,可以定义在普通类中,也可以定义在泛型类中

  1. 当泛型方法被调用时,类型会确定

  1. public void eat(E e) {},修饰符后没有<T, R....> eat方法不是泛型方法,而是使用了泛型

应用案例

package com15.customgeneric;import java.util.ArrayList;/*** @author 甲柒* @version 1.0* @title CustomMethodGeneric* @package com15.customgeneric* @time 2023/3/10 9:54*/
public class CustomMethodGeneric {public static void main(String[] args) {Car car = new Car();car.fly("宝马", 1000);//当调用方法时,传入参数,编译器,就会确定类型System.out.println("=============");car.fly(3000, 1000.23);//当调用方法时,传入参数,编译器,就会确定类型System.out.println("=============");//测试//T->String,R->ArrayListFish<String, ArrayList> fish = new Fish<>();fish.hello(new ArrayList(), 1123.32f);}
}//1. 泛型方法,可以定义在普通类中,也可以定义在泛型类中
//2. 当泛型方法被调用时,类型会确定
//3. public void eat(E e) {},修饰符后没有<T, R....> eat方法不是泛型方法,而是使用了泛型
class Car {//普通类public void run() {//普通方法}//说明//1.<T, R>就是泛型//2.是提供给fly使用的public <T, R> void fly(T t, R r) {//泛型方法System.out.println(t.getClass());//自动装箱StringSystem.out.println(r.getClass());//自动装箱Integer}
}class Fish<T, R> {//泛型类public void run() {//普通方法}public <U, M> void eat(U u, M m) {//泛型方法}//说明//1.下面hi方法不是泛型方法//2.是hi方法使用了类声明的泛型public void hi(T t) {}//泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型public <K> void hello(R r, K k) {System.out.println(r.getClass());System.out.println(k.getClass());}
}

练习题

下面代码是否正确,如果有错误,修改正确,并说明输出什么

package com15.customgeneric;/*** @author 甲柒* @version 1.0* @title CustomMethodGenericExercise* @package com15.customgeneric* @time 2023/3/10 10:31*/
public class CustomMethodGenericExercise {public static void main(String[] args) {Apple<String, Integer, Double> apple = new Apple<>();apple.fly(10);//会被自动装箱 Integer 10 输出Integerapple.fly(new Dog());//Dog}
}class Apple<T, R, M> {//自定义泛型类public <E> void fly(E e) {//泛型方法System.out.println(e.getClass().getSimpleName());}//    public void eat(U u) {//错误,因为U没有声明
//    }public void run(M m) {}//ok
}class Dog {
}

泛型的继承和通配符

泛型的继承和通配符说明

  1. 泛型不具备继承性

List<Object> list = new ArrayList<String>();//错误
  1. <?>:支持任意泛型类型

  1. <? extrnds A>:支持A类以及A类的子类,规定了泛型的上线

  1. <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下线

案例

package com15.customgeneric;import java.util.ArrayList;
import java.util.List;/*** @author 甲柒* @version 1.0* @title GenericExtends* @package com15.customgeneric* @time 2023/3/11 8:54*/
public class GenericExtends {public static void main(String[] args) {Object o = new String("xx");//泛型没有继承性
//        List<Object> list = new ArrayList<String>();//错误//举例说明下面三个方法的使用ArrayList<Object> list1 = new ArrayList<>();ArrayList<String> list2 = new ArrayList<>();ArrayList<A> list3 = new ArrayList<>();ArrayList<B> list4 = new ArrayList<>();ArrayList<C> list5 = new ArrayList<>();//如果是 List<?> c 可以接受任意的泛型类型printCollection1(list1);printCollection1(list2);printCollection1(list3);printCollection1(list4);printCollection1(list5);//List<? extends A> c 表示 上限,可以接受A 或者A的子类
//        printCollection2(list1);//错误
//        printCollection2(list2);//错误printCollection2(list3);//okprintCollection2(list4);//okprintCollection2(list5);//ok//List<? super A> c 子类类名A:支持A类以及A类的父类,不限于直接父类,printCollection3(list1);//ok
//        printCollection3(list2);//错误printCollection3(list3);//ok
//        printCollection3(list4);//错误
//        printCollection3(list5);//错误}//方法//说明:List<?>表示 任意的泛型类型都可以接受public static void printCollection1(List<?> c) {for (Object object : c) {//通配符,取出时,就是ObjectSystem.out.println(object);}}//? extends A 表示 上限,可以接受A 或者A的子类public static void printCollection2(List<? extends A> c) {for (Object object : c) {System.out.println(object);}}//? super A 子类类名A:支持A类以及A类的父类,不限于直接父类,//规定了泛型的下线public static void printCollection3(List<? super A> c) {for (Object object : c) {System.out.println(object);}}}class A {}class B extends A {}class C extends B {}

JUnit

为什么需要JUnit

  1. 一个类有很多功能代码需要测试,为了测试,就需要写入到main方法中

  1. 如果有多个功能代码测试,就需要来回注销,切换很麻烦

  1. 如果可以直接运行一个方法,就方便很多,并且可以给出相关信息就好了->JUnit

package com15.junit_;import org.junit.jupiter.api.Test;/*** @author 甲柒* @version 1.0* @title JUnit_* @package com15.junit_* @time 2023/3/11 9:51*/
public class JUnit_ {public static void main(String[] args) {//传统方式//new JUnit_().m1();//new JUnit_().m2();}@Testpublic void m1() {System.out.println("m1方法被调用");}@Testpublic void m2() {System.out.println("m2方法被调用");}
}

相关文章:

Java笔记029-泛型

泛型泛型的理解和好处看一个需求请编写程序&#xff0c;在ArrayList中&#xff0c;添加3个Dog对象Dog对象含有name和age&#xff0c;并输出name和age(要求使用getXxx)先用传统的方法来解决->引出泛型package com15.generic;import java.util.ArrayList;/*** author 甲柒* ve…...

港科夜闻|香港科大与中国联通成立联合实验室,推动智慧社会研究发展

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、香港科大与中国联通成立联合实验室&#xff0c;推动智慧社会研究发展。香港科大与中国联通于3月9日签署两份协议以加强战略合作&#xff0c;并成立「香港科技大学 - 中国联通智慧社会联合实验室」&#xff0c;就香港科大建构…...

制作一个简单的信用卡验证表

下载:https://download.csdn.net/download/mo3408/87559584 效果图: 您可以从文章顶部附近的下载按钮获取该项目的完整代码。这些文件的概述如下所示: 我们需要将两个 .css 文件和两个 .js 文件包含在我们的 HTML 中。所有其他资源,例如 Bootstrap 框架、jQuery 和 Web 字…...

牛客小白月赛68

牛客小白月赛68A Tokitsukaze and New OperationB Tokitsukaze and Order Food DeliveryC Tokitsukaze and Average of SubstringD Tokitsukaze and Development TaskE Tokitsukaze and Colorful ChessboardF Tokitsukaze and New RenKinKama题目链接A Tokitsukaze and New Ope…...

【id:21】【20分】A. DS单链表--类实现

题目描述用C语言和类实现单链表&#xff0c;含头结点属性包括&#xff1a;data数据域、next指针域操作包括&#xff1a;插入、删除、查找注意&#xff1a;单链表不是数组&#xff0c;所以位置从1开始对应首结点&#xff0c;头结点不放数据类定义参考输入n第1行先输入n表示有n个…...

【实习_面试全程辅导分享】简历篇

🎋🎋哈喽,大家好,我是辰柒。快有一个月没有更新博文啦,那么这一个月不是在偷懒,而是在全心准备找实习的过程中。那么最终也是拿到了心仪的大厂offer——海康威视!!经过这次找实习的经历,我想就在校大学生找实习这件事情开设一个专栏,帮助大家在找实习的过程中减少焦…...

【学习笔记】CF1305 Kuroni and Antihype

想了一下&#xff0c;觉得还是发单篇的题解比较合理 怎么感觉这题之前做过 先抛开建边方式不管 这一步其实挺重要的&#xff0c;但是可能大多数人独立做这道题的时候都在想用位运算的性质&#xff0c;而没有想到分开考虑吧&#xff1f;&#xff0c;考虑新建000号节点&#xf…...

json-server单独使用或者在react中进行使用

json-serverjson-server使用教程修改json-server端口号启动1、全局安装json-server2、在根目录生成一个db.json3、启动 访问react中进行使用react中修改json-server启动端口号1、 第一步也是安装&#xff0c;和第一种一样2、在根路径下定义一个__json_server_mock__文件夹3、在…...

【6G 新技术】6G数据面介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…...

【AI绘图学习笔记】深度前馈网络(一)

有关深度前馈网络的部分知识&#xff0c;我们已经在吴恩达的机器学习课程中有过了解了&#xff0c;本章主要是对《深度学习》花书中第六章&#xff1a;深度前馈网络的总结笔记。我希望你在看到这一章的时候&#xff0c;能回忆起机器学习课程中的一些环节或者细节&#xff0c;这…...

目标检测笔记合集

目标检测笔记合集1. 必看的两篇目标检测论文2. 必速看的深度学习目标检测的论文集及概述2.1 一份Slide&#xff08;PPT)两张表格带你快速了解目标检测2.2 最新目标检测算法回顾2022笔记合集3.目标检测的应用与需求4.目标检测的定义与挑战5.目标检测损失函数的进展6.目标检测IOU…...

《计算机网络》期末复习笔记

文章目录一、一些英文名词的标签&#xff08;方便记忆&#xff09;二、OSI七层协议三、综合题3.0 知识点储备3.1 在Internet 网中&#xff0c;某计算机的IP 地址是11001010.01100000.00101100.01011000 &#xff0c;请回答下列问题3.2 假定发送方要发送的数据为10000101。采用C…...

linux下安装SonarQube

目录1. 准备安装环境2. 安装postgres数据库3. 安装SonarQube4. 使用SonarQube1. 准备安装环境 这里安装SonarQube的系统环境是Red Hat Enterprise Linux release 8.7 &#xff0c;然后将jdk的压缩包&#xff08;jdk-17.0.2_linux-x64_bin.tar.gz&#xff09;和sonarQube的压缩…...

MyBatis-Plus(狂神)

一.特点 无侵入&#xff1a;只做增强不做改变&#xff0c;引入它不会对现有工程产生影响&#xff0c;如丝般顺滑损耗小&#xff1a;启动即会自动注入基本 CURD&#xff0c;性能基本无损耗&#xff0c;直接面向对象操作强大的 CRUD 操作&#xff1a;内置通用 Mapper、通用 Serv…...

Python3实现写作

导语T_T没有科研梦想的人半夜过来水篇文章~~~让Python学会写写歌&#xff0c;创创作~~~纯属娱乐~~~改编自PyTorch官网的一个教程&#xff0c;不过我用TF写的&#xff0c;然后生成英文变成了生成中文~~~Lets Go~~~相关文件百度网盘下载链接: https://pan.baidu.com/s/1VUEFR82Cq…...

UEFI实战--------HII之uni文件

uni文件 HII的实现涉及到多种不同类型的文件&#xff0c;uni文件是其中最简单的一种&#xff0c;它用来存放各种语言的字符串以实现本地化。本节主要参考自《edk-ii-uni-specification.pdf》&#xff0c;后面简称为参考文档。 关于uni文件的作用&#xff0c;在参考文档中做了如…...

基于Spring Boot集成MyBatis-3.5.9操作数据库

记录&#xff1a;382场景&#xff1a;在Spring Boot 2.6.3中集成MyBatis 3.5.9操作数据库。实现MyBatis的查、增、改、删操作数据库示例。MyBatis官网&#xff1a;http://www.mybatis.org/MyBatis源码&#xff1a;https://github.com/mybatis/1.初始化准备1.1创建Maven工程使用…...

了解国外SEO负面压制的现状与应对策略!

随着全球化的发展&#xff0c;越来越多的企业和品牌开始将目光转向海外市场&#xff0c;而谷歌作为全球最大的搜索引擎之一&#xff0c;也成为了外贸企业最主要的搜索引擎之一。 然而&#xff0c;随着谷歌的不断发展&#xff0c;国外SEO负面压制的现状也愈发严峻&#xff0c;外…...

Yolov5-交通标志检测与识别

项目介绍 上一篇文章介绍了基于卷积神经网络的交通标志分类识别Python交通标志识别基于卷积神经网络的保姆级教程&#xff08;Tensorflow&#xff09;&#xff0c;并且最后实现了一个pyqt5的GUI界面&#xff0c;并且还制作了一个简单的Falsk前端网页实现了前后端的一个简单交互…...

Linux内核Thermal框架详解五、Thermal Core(4)

本文部分内容参考Linux Thermal 学习笔记 - 爱码网。特此致谢&#xff01; 接前一篇文章Linux内核Thermal框架详解四、Thermal Core&#xff08;3&#xff09; 三、相关源码及分析 2. thermal_register_governors 上一回说到这一段代码&#xff1a; for (__governor __gove…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...