Java高级编程——泛型
目录
一、为什么要有泛型
1.为什么要有泛型(Generic)
2.泛型的概念
二、在集合中使用泛型
上代码
package com.tyl.java;
import org.junit.Test;
import java.util.*;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.java
* @Project:workidea
* @Filename: GenericTest
* @create 2023-06-07 11:52
*
* 泛型的使用
* 1.jdk5.0新增的特性
*
* 2.在集合中使用泛型:
* 总结:
* 2.1.集合接口或集合类在jdk5.0时都修改为带泛型的结构。
* 2.2.在实例化集合类时,可以指明具体的泛型类型
* 2.3.指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型
* 比如:add(E e) --> 实例化以后:add(Integer e)
* 2.4. 注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,用包装类代替。
* 2.5. 如果实例化时,没有指明泛型的类型。默认类型为ava.Lang.Object类型。
*
* 3.如何自定义泛型结构:泛型类、泛型接口:泛型方法 见:GenericTest1.java
*/
public class GenericTest {
//在集合中使用泛型之前的情况:
@Test
public void test1(){
ArrayList list = new ArrayList();
//需求:存放学生的成绩
list.add(77);
list.add(88);
list.add(99);
list.add(66);
//问题一:类型不安全
// list.add("tyl");
for(Object score : list){
//问题二:强转时,可能出现CLassCastException
int stuScore = (Integer) score;
System.out.println(stuScore);
}
}
//在集合中使用泛型的情况:以ArrayList为例
@Test
public void test2(){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(77);
list.add(99);
list.add(55);
list.add(55);
list.add(66);
//编译时,就会进行类型检查,保证数据的安全
// list.add("tom");
// 方式一:
// for(Integer score : list){
// //避免了强转操作
// int stuScore = score;
// System.out.println(stuScore);
// }
// 方式二:
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
int stuScore = iterator.next();
System.out.println(stuScore);
}
}
//在集合中使用泛型的情况:以HashMap为例
@Test
public void test3(){
// Map<String, Integer> map = new HashMap<String, Integer>();
//jdk7新特性:类型推断
Map<String, Integer> map = new HashMap<>();
map.put("tom", 87);
map.put("wc", 87);
map.put("tyl", 99);
// 泛型的嵌套
Set<Map.Entry<String, Integer>> entry = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
while (iterator.hasNext()){
Map.Entry<String, Integer> e = iterator.next();
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key + "....." + value);
}
}
}
三、自定义泛型结构
1.自定义泛型结构
2.泛型类、泛型接口
2.1.泛型类
2.2.泛型方法
上代码
package com.tyl.java;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.java
* @Project:workidea
* @Filename: GenericTest1
* @create 2023-06-07 18:10
*
* 如何自定义泛型结构:泛型类、泛型接口:泛型方法
*
* 1.关于自定义泛型类、泛型接口:
*/
public class GenericTest1 {
@Test
public void test1(){
// 如果定义了泛型类,实例化没有指明类的泛型,则认为此,泛型类型为Object类型
// 要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。
Order order = new Order();
order.setOrderT(123);
order.setOrderT("abc");
//建议:实例化时指明类的泛型
Order<String> order1 = new Order<>("orderAA", 1001, "order:AA");
order1.setOrderT("AA:jjjjjj");
}
@Test
public void test2(){
subOrder sub1 = new subOrder();
// 由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型
sub1.setOrderT(1122);
subOrder1<String> sub2 = new subOrder1<>();
sub2.setOrderT("odsdsdsdad.....");
}
@Test
public void test3(){
ArrayList<String> list1 = null;
ArrayList<Integer> list2 = new ArrayList<Integer>();
// 泛型不同的引用不能相互赋值
// list1 = list2;
}
//测试泛型方法
@Test
public void test4(){
Order<String> order = new Order<>();
Integer[] arr = new Integer[]{1,2,3,4};
// 泛型方法在调用时,指明泛型参数的类型。
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);
}
}
四、泛型在继承上的体现
五、 通配符的使用
注意点
有限制的通配符
上代码
package com.tyl.java2;
import org.junit.Test;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.java2
* @Project:workidea
* @Filename: GenericTest3
* @create 2023-06-09 13:30
*
* 1.泛型在继承方面的体现
*
* 2.通配符的使用
*/
public class GenericTest3 {
/*
泛型在继承方面的体现
类A是B的父类,G<A>和G<B>二者不具备子父类关系,二者是并列关系。
补充:类A是类B的父类,A<G>是B<G>的父类
*/
@Test
public void test1(){
Object obj = null;
String str = null;
obj = str;
Object[] arr1 = null;
String[] arr2 = null;
arr1 = arr2;
List<Object> list1 = null;
List<String> list2 = new ArrayList<String>();
//此时的饥ist1和ist2的类型不具有子父类关系
//编译不通过
// list1 = list2;
/*
反证法:
假设List1=List2;
List1.add(123); 导致混入String的数据。出错。
*/
show1(list1);
show(list2);
}
public void show(List<String> list){
}
public void show1(List<Object> list){
}
@Test
public void test2(){
AbstractList<String> list1 = null;
List<String> list2 = null;
ArrayList<String> list3 = null;
list2 = list3;
list1 = list3;
List<Object> list4 = new ArrayList<>();
}
/*
2.通配符的使用
通配符:?
类A是都的父类,G<A>和G<B>是没有关系的,二者共同的父类是:G<?>
*/
@Test
public void test3(){
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
// print(list1);
// print(list2);
ArrayList<String> list3 = new ArrayList<>();
list3.add("aa");
list3.add("bb");
list3.add("cc");
list = list3;
//添加(写入):对于List<?>就不能向其内部添加数据。
//除了添加nuLL之外。
// list.add("DD");
// list.add("?");
list.add(null);
// 获取(读取):允许读取数据,读取的数据类型为Object。
Object o = list.get(0);
System.out.println(o);
// print(list);
}
public void print(List<?> list){
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
}
/*
3.有限制的通配符
? extends A: G<?extends A>可以作为G<A>和G<B>的父类,其中B是A的子类
? super A: G<? super A>可以作为G<A>和G<B>的父类,其中B是A的父类
*/
@Test
public void test4(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<>();
List<Person> list4 = new ArrayList<>();
List<Object> list5 = new ArrayList<>();
list1 = list3;
list1 = list4;
// list1 = list5;
// list2 = list3;
list2 = list4;
list2 = list5;
//读取数据,
list1 = list3;
list1 = list4;
Person p1 = list1.get(0);
list2 = list4;
Object obj = list2.get(0);
//写入数据
// list1.add(new Student());
list2.add(new Person());
list2.add(new Student());
}
}
六、泛型应用举例
1.泛型嵌套
2.实验
2.1 自定义泛型类的使用
package com.tyl.exer1;
import java.util.*;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.exer1
* @Project:workidea
* @Filename: DAO
* @create 2023-06-12 17:43
*
* 定义个泛型类 DAO<T>,在其中定义一个 Map 成员变量,Map 的键为 String 类型,值为 T 类型。
* 分别创建以下方法:
* public void save(String id,T entity): 保存 T 类型的对象到 Map 成员变量中
* public T get(String id):从 map 中获取 id 对应的对象
* public void update(String id,T entity):替换 map 中 key 为 id 的内容,改为 entity 对象
* public List<T> list():返回 map 中存放的所有 T 对象
* public void delete(String id):删除指定 id 对象
*/
public class DAO<T> {
private Map<String, T> map = new HashMap<>();
//保存 T 类型的对象到 Map 成员变量中
public void save(String id, T entity){
map.put(id,entity);
}
// 从 map 中获取 id 对应的对象
public T get(String id){
return map.get(id);
}
//替换 map 中 key 为 id 的内容, 改为 entity 对象
public void update(String id,T entity){
if(map.containsKey(id)){
map.put(id,entity);
}
}
// 返回 map 中存放的所有 T 对象
public List<T> list(){
// 错误的
// Collection<T> values = map.values();
// return (List<T>) values;
//正确的
ArrayList<T> list = new ArrayList<>();
Collection<T> values = map.values();
for (T t : values){
list.add(t);
}
return list;
}
// 删除指定 id 对象
public void delete(String id){
map.remove(id);
}
}
package com.tyl.exer1;
import java.util.Objects;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.exer1
* @Project:workidea
* @Filename: User
* @create 2023-06-12 17:57
*
* 定义一个 User 类:
* 该类包含:private 成员变量(int 类型) id,age;(String 类型)name。
*/
public class User {
private int id;
private int age;
private String name;
public User() {
}
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 "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (id != user.id) return false;
if (age != user.age) return false;
return Objects.equals(name, user.name);
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + age;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
}
package com.tyl.exer1;
import java.util.List;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.exer1
* @Project:workidea
* @Filename: DAOTest
* @create 2023-06-12 17:59
*
* 定义一个测试类:
* 创建 DAO类的对象, 分别调用其 save、get、update、list、delete 方法来操作 User 对象,
* 使用 Junit 单元测试类进行测试。
*/
public class DAOTest {
public static void main(String[] args) {
DAO<User> dao = new DAO<>();
dao.save("1001", new User(1001, 22, "tyl"));
dao.save("1002", new User(1002, 18, "wc"));
dao.save("1003", new User(1003, 21, "aaa"));
dao.update("1003",new User(1003, 30, "ccc"));
dao.delete("1003");
List<User> list = dao.list();
// System.out.println(list);
list.forEach(System.out::println);
}
}
2.2 集合中使用泛型
package com.tyl.exer;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.exer
* @Project:workidea
* @Filename: Employee
* @create 2023-05-31 22:48
*
* 该类包含:private 成员变量 name,age,birthday,其中 birthday 为MyDate 类的对象;
* 并为每一个属性定义 getter, setter 方法;
* 并重写 toString 方法输出 name, age, birthday
*/
public class Employee implements Comparable<Employee>{
private String name;
private int age;
private MyDate birthday;
public Employee() {
}
public Employee(String name, int age, MyDate birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
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;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
}
@Override
public int compareTo(Employee o) {
return this.name.compareTo(o.name);
}
// 没有指明泛型时的写法
//1). 使 Employee 实现 Comparable 接口,并按 name 排序
// @Override
// public int compareTo(Object o) {
// if(o instanceof Employee){
// Employee e = (Employee) o;
// return this.name.compareTo(e.name);
// }
return 0;
// throw new RuntimeException("输入的数据类型不一致");
// }
}
package com.tyl.exer;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.exer
* @Project:workidea
* @Filename: MyDate
* @create 2023-05-31 22:48
*
* MyDate 类包含:
* private 成员变量 year,month,day;并为每一个属性定义 getter, setter
* 方法;
*/
public class MyDate implements Comparable<MyDate>{
private int year;
private int monthr;
private int day;
public MyDate() {
}
public MyDate(int year, int monthr, int day) {
this.year = year;
this.monthr = monthr;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonthr() {
return monthr;
}
public void setMonthr(int monthr) {
this.monthr = monthr;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", monthr=" + monthr +
", day=" + day +
'}';
}
// @Override
// public int compareTo(Object o) {
// if(o instanceof MyDate){
// MyDate m = (MyDate) o;
//
// //年
// int minusYear = this.getYear() - m.getYear();
// if(minusYear != 0){
// return minusYear;
// }
//
// //月
// int minusMonth = this.getMonthr() - m.getMonthr();
// if(minusMonth != 0){
// return minusMonth;
// }
//
// //日
// return this.getDay() - m.getDay();
// }
return 0;
// throw new RuntimeException("输入的数据类型不一致");
// }
@Override
public int compareTo(MyDate m) {
//年
int minusYear = this.getYear() - m.getYear();
if(minusYear != 0){
return minusYear;
}
//月
int minusMonth = this.getMonthr() - m.getMonthr();
if(minusMonth != 0){
return minusMonth;
}
//日
return this.getDay() - m.getDay();
}
}
package com.tyl.exer;
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
/**
* @author tyl 邮箱:tyl202061@gmail.com
* @Package:com.tyl.exer
* @Project:workidea
* @Filename: EmployeeTest
* @create 2023-05-31 22:49
* <p>
* 创建该类的 5个对象,并把这些对象放入 TreeSet 集合中(下一章:TreeSet 需使用泛型来定义)
* 分别按以下两种方式对集合中的元素进行排序,并遍历输出:
* 1). 使 Employee 实现 Comparable 接口,并按 name 排序
* 2). 创建 TreeSet 时传入 Comparator 对象,按生日日期的先后排序。
*/
public class EmployeeTest {
// 按生日日期的先后排序。
@Test
public void test2() {
TreeSet<Employee> set = new TreeSet<>(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
MyDate b1 = o1.getBirthday();
MyDate b2 = o2.getBirthday();
//方式二:
return b1.compareTo(b2);
}
});
Employee e1 = new Employee("liudehua", 55, new MyDate(1995, 5, 4));
Employee e2 = new Employee("zahngxueyuo", 43, new MyDate(1965, 5, 4));
Employee e3 = new Employee("guofucheng", 44, new MyDate(1965, 5, 9));
Employee e4 = new Employee("liming", 51, new MyDate(1978, 8, 12));
Employee e5 = new Employee("liangcahowei", 21, new MyDate(1955, 12, 4));
set.add(e1);
set.add(e2);
set.add(e3);
set.add(e4);
set.add(e5);
Iterator<Employee> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
//问题一:使用自然排序
@Test
public void test1() {
TreeSet<Employee> set = new TreeSet<>();
Employee e1 = new Employee("liudehua", 55, new MyDate(1995, 5, 4));
Employee e2 = new Employee("zahngxueyuo", 43, new MyDate(1965, 5, 4));
Employee e3 = new Employee("guofucheng", 44, new MyDate(1965, 5, 9));
Employee e4 = new Employee("liming", 51, new MyDate(1978, 8, 12));
Employee e5 = new Employee("liangcahowei", 21, new MyDate(1955, 12, 4));
set.add(e1);
set.add(e2);
set.add(e3);
set.add(e4);
set.add(e5);
Iterator<Employee> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
听得听迷糊,需要在以后的学习中反复练习才能体会到精髓!!!!