泛型1

泛型1

image-20230903184820611

1.什么是泛型?

所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值或参数的类型。这个类型参数将在使用时(例如,继承或实现这个接口、创建对象或调用方法时)确定(即传入实际的类型参数,也称为类型实参)。

2.在集合中使用泛型之前可能存在的问题

问题1:类型不安全。因为add()的参数是0bject类型,意味着任何类型的对象都可以添加成功

问题2:需要使用强转操作,繁琐。还有可能导致ClassCastException异常。

    public void test1(){
        ArrayList<Integer> list = new ArrayList<>();
        list.add(25);
        list.add(55);
        list.add(74);
        list.add(94);

//        list.add("hh");编译报错,保证类型的安全
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            //因为添加的都是Integer类型,避免了强转操作
            Integer next = iterator.next();
            System.out.println(next);
        }

    }

3.在集合、比较器中使用泛型(重点)见代码。

    //泛型在Map中使用的例子
    public void test2(){
        HashMap<String, Integer> map = new HashMap<>();//类型推断
        map.put("ww",45);
        map.put("rr",47);
        map.put("bb",88);

        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entries.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Integer> next = iterator.next();
            String key = next.getKey();
            Integer value = next.getValue();
            System.out.println(key+"---->"+value);
        }
    }

4.使用说明

集合框架在声明接口和其实现类时,使用了泛型(jdk5.0),在实例化集合对象时,如果没有使用泛型,则认为操作的是0bject类型的数据。
如果使用了泛型,则需要指明泛型的具体类型。一旦指明了泛型的具体类型,则在集合的相关的方法中,凡是使用类的泛型类型

package com.xin.fanxing.demo01;
//MyDate类包含:
//private成员变量year ,month , day;并为每一个属性定义getter,setter方法;
public class MyDate {
    private int year;
    private int month;
    private int day;

    public MyDate() {
    }

    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 year+"年"+month+"月"+day+"日";
    }
}
===========
    package com.xin.fanxing.demo01;



/*
定义一个Employee姆
该类包含: private成员变量name , age , birthday,其中 birthday 为 MgDate 类的对象;并为每一个属性定义getter,setter方法;
并重写toString方法输出name,age,birthday

 */
public class Employee implements Comparable<Employee>{
    private String name;
    private int age;
    private MyDate brithday;

    public Employee() {
    }

    public Employee(String name, int age, MyDate brithday) {
        this.name = name;
        this.age = age;
        this.brithday = brithday;
    }

    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 getBrithday() {
        return brithday;
    }

    public void setBrithday(MyDate brithday) {
        this.brithday = brithday;
    }
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", brithday=" + brithday +
                '}';
    }

    /**
     * 按照name从低到高排序
     * @param o the object to be compared.
     * @return
     */
    @Override
    public int compareTo(Employee o) {
        return this.name.compareTo(o.name);
    }
}
============
    package com.xin.fanxing.demo01;

import junit.framework.TestCase;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

public class EmployeeTest extends TestCase {

    //需求1:使Employee实现 Comparable接口,并按name排序
   public void test(){
       TreeSet<Employee> set = new TreeSet<>();

       Employee e1 = new Employee("ss", 15, new MyDate(1999, 7, 8));
       Employee e2 = new Employee("ee", 64, new MyDate(1945, 5, 3));
       Employee e3 = new Employee("tt", 22, new MyDate(1939, 3, 8));
       Employee e4 = new Employee("gg", 43, new MyDate(1955, 7, 9));

       set.add(e1);
       set.add(e2);
       set.add(e3);
       set.add(e4);

       //遍历
       Iterator<Employee> iterator = set.iterator();
       while (iterator.hasNext()){
           System.out.println(iterator.next());
       }
   }

   //需求2:创建TreeSet时传入Comparator对象,按生日日期的先后排序。
    public void test2(){
        Comparator<Employee> comparator = new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                int yearDistance=o1.getBrithday().getYear()-o2.getBrithday().getYear();
                if (yearDistance!=0){
                    return yearDistance;
                }
                int monthDistance=o1.getBrithday().getMonth()-o2.getBrithday().getMonth();
                if (monthDistance!=0){
                    return monthDistance;
                }
                return o1.getBrithday().getDay()-o2.getBrithday().getDay();
            }
        };
        TreeSet<Employee> set = new TreeSet<>(comparator);
        Employee e1 = new Employee("ss", 15, new MyDate(1999, 7, 8));
        Employee e2 = new Employee("ee", 64, new MyDate(1945, 5, 3));
        Employee e3 = new Employee("tt", 22, new MyDate(1945, 3, 8));
        Employee e4 = new Employee("gg", 43, new MyDate(1955, 7, 9));

        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);

        //遍历
        Iterator<Employee> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

}


02-自定义泛型

1.自定义泛型类\接口

1.1格式

class A{
}
interface B<T1,T2>{}

  • subOrder1 extends Order<>,T为Object
  • subOrder2 extends Order,T为Integer

以上都不是泛型类


以下都是泛型类

  • subOrder3 extends Order
  • subOrder4 extends Order,相当于父类泛型确定,子类有2个泛型
  • subOrder4 <E,T>extends Order
package com.xin.fanxing.demo02;
//泛型类
public class Order<T>{
    //声明了类的泛型参数以后,就可以在类的内部使用此泛型参数。

    T t;
    int id;

    public Order() {
    }

    public Order(T t, int id) {
        this.t = t;
        this.id = id;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Order{" +
                "t=" + t +
                ", id=" + id +
                '}';
    }
}
=====
        //测试自定义的泛型类
    public void test1(){
        //实例化时,就可以指明类的泛型参数的类型
        //泛型参数在指明时,是不可以使用基本数据类型的!但是可以使用包装类替代基本数据类型。
        //在实例化时,可以指明类的泛型参数的具体类型!一旦指明了泛型的类型,则在泛型类中凡是使用泛型
        // 参数的位置,都替换为指定的类型。

        Order<Integer> order1 = new Order<>();
        order1.setT(56);
        Integer t = order1.getT();
        System.out.println(order1);
        Order<String> order2 = new Order<>();
    }
    public void test2(){
        Order<String> order = new Order<>();
        subOrder1<Double> order1 = new subOrder1<>();
        Integer t = order1.getT();//subOrder1<T> extends Order<Integer>
        //子类泛型确定并不能改变父类,er父类可以决定子类
        String t1 = order.getT();
    }

1.2使用说明

  1. 我们在声明完自定义泛型类以后,可以在类的内部(比如:属性、方法、构造器中)使用类的泛型。
  2. 我们在创建自定义泛型类的对象时,可以指明泛型参数类型。一旦指明,内部凡是使用类的泛型参数的位置,都具体化为指定的类的泛型类型。
  3. 如果在创建自定义泛型类的对象时,没有指明泛型参数类型,那么泛型将被擦除,泛型对应的类型均按照Object处理,但不等价于Object。

-经验:

  1. 泛型要使用一路都用。要不用,一路都不要用。
  2. 泛型的指定中必须使用引用数据类型。不能使用基本数据类型,此时只能使用包装类替换。
  3. 除创建泛型类对象外,子类继承泛型类时、实现类实现泛型接口时,也可以确定泛型结构中的泛型参数。如果我们在给泛型类提供子类时,子类也不确定泛型的类型,则可以继续使用泛型参数。
    我们还可以在现有的父类的泛型参数的基础上,新增泛型参数。

1.3 注意点

  1. 泛型类可能有多个参数,此时应将多个参数一起放在尖括号内。比如:<E1,E2,E3>
  2. JDK7.0开始,泛型的简化操作:ArrayList flist = new ArrayList<>();
  3. 如果泛型结构是一个接口或抽象类,则不可创建泛型类的对象。
  4. 不能使用new E[]。但是可以:E[] elements = (E[])new 0bject[capacity];参考:ArrayList源码中声明: 0bject[] elementData,而非泛型参数类型数组。
  5. 在类/接口上声明的泛型,在本类或本接口中即代表某种类型,但不可以在静态方法中使用类的泛型
  6. 异常类不能是带泛型的。

2.自定义泛型方法

2.1问题:在泛型类的方法中,使用了类的泛型参数。那么此方法是泛型方法吗?

2.2格式
汉限修饰符返回值类型方法名(形参列表){

//通常在形参列表返回值类型的位置会出现泛型参数T

    //自定义泛型方法
    public <E>E method(E e){
        return null;
    }
    ///定义泛型方法,将E[]数组元素添加到对应类型的ArrayList中,并返回
    public <E>ArrayList<E> copyArrayToList(E[] arr){
        ArrayList<E> list = new ArrayList<>();
        for (E e :
                arr) {
            list.add(e);
        }
        return list;
    }
====
        //测试泛型方法的使用
    public void test3(){
        Order<String> order1 = new Order<>();
        Integer[] arr = {1, 5, 8, 4, 6};
        ArrayList<Integer> list = order1.copyArrayToList(arr);
        for (Integer integer : list) {
            System.out.println(integer);
        }

    }
package com.xin.fanxing.demo02;

import java.sql.Date;

public class Customer {
    int id;
    String name;
    Date brith;
}
====
    package com.xin.fanxing.demo02;


/*

ORM思想(object relational mapping)
数据库中的一个表 与Java中的一个类对应表中的一条记录与Java类的一个对象对应
表中的一个字段(或列)与Java类的一个属性(或字段)对应

 */
public class DAO<T> {

    //增
    public void insert(T bean){
        //通过相应的sql语句,将bean对象的属性值写入到数据表中。
    }
    //删
    public T delete(int id){
        //略
        return null;
    }
    // 改
    public void update(int id,T bean){
        //略
    }
    // 查
    public T query(int id){
        //略
        return null;
    }
        //定义泛型方法
    public <E> E getValue(String s){
        return null;
    }
}
=========
        public void test4(){
        DAO<String> dao = new DAO<>();
        String query = dao.query(123);
        Integer value = dao.getValue("485");
        System.out.println(value);
    }
package com.xin.fanxing.demo02;

import java.util.Objects;

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;
        return id == user.id && age == user.age && Objects.equals(name, user.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, age, name);
    }
}
=====
    package com.xin.fanxing.demo02;

import java.util.*;

public class DAO1<T>{
    Map<String,T> map;

    {
        map=new HashMap<String,T>();
    }
    /**
     * //保存T类型的对象到Map成员变量中
     * @param id
     * @param entity
     */
    public void save(String id,T entity){
       if (!map.containsKey(id))
        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();

        ArrayList<T> list = new ArrayList<>();
        list.addAll(values);

        //方式2
        ArrayList<T> list1 = new ArrayList<>(values);
        return list;
    }
    /**
     * 删除指定id 对象
     */
    public void  delete(String id){
        map.remove(id);
    }
}
=====
    package com.xin.fanxing.demo02;

import java.util.List;

public class DAOTest {
    public static void main(String[] args) {
        DAO1<User> dao = new DAO1<>();
        dao.save("1001",new User(1,23,"dddd"));
        dao.save("1002",new User(2,44,"ffff"));

        dao.update("1002",new User(3,24,"ggg"));

        List<User> list = dao.list();

        for (User user : list) {
            System.out.println(user);
        }

    }
}


03-泛型在继承上的体现.

1.类SuperA是类A的父类,则G与6的关系:G和G是并列的两个类,没有任何子父类的关系
比如: ArrayList<0bject> 、ArrayList没有关系

2、类SuperA是类A的父类或接口,SuperA<6>与A<6>的关系:SuperA与A<6>有继承或实现的关系。即A的实例可以赋值给SuperA类型的引用(或变量)I
比如:List 与ArrayList


04-通配符的使用.

1.通配符:?

2.使用说明:

3.读写数据的特点(以集合ArrayList<?>为例说明)

  • 读取数据:允许的,读取的值的类型为0bject类型
  • 写入数据:不允许的。特例:写入null值。
    //?的使用
    public void test1(){
        List<?> list=null;
        List<Object> list1=null;
        List<String> list2=null;

        list=list1;
        list=list2;
    }

    public void test2(){
        List<?> list=null;
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("aa");
        list=list1;

        //读取
        Object o = list.get(0);
        System.out.println(o);

        //不能写入,除了null
     //   list.add("ll");
        list.add(null);
    }

4.有限制条件的通配符

    /*
    测试:有限制条件的通配符的使用
    ? extends A
    ? super A
     */
    public void test3() {
        List<? extends Father> list = null;
        List<Object> list1 = null;
        List<Father> list2 = null;
        List<Son> list3 = null;

        //  list=list1;
        list = list2;
        list = list3;
    }

    public void test4() {
        List<? super Father> list = null;
        List<Object> list1 = null;
        List<Father> list2 = null;
        List<Son> list3 = null;

        list = list1;
        list = list2;
       // list = list3;
    }

5.有限制条件的统配符的读写操作(难、了解)

技巧:开发中,遇到了带限制条件的通配符,在赋值时,如果没报错,那就正常使用。
如果报错了,知道不能这样写。改改!

public void test5(){
        List<? extends Father> list = null;
        ArrayList<Father> list1 = new ArrayList<>();
        list1.add(new Father());
        list=list1;
        //读取数据
        Father father = list.get(0);
        //不能写入数据
        list.add(null);
       // list.add(new Father());
       // list.add(new Son());
    }

    public void test6(){
        List<? super Father> list = null;
        ArrayList<Father> list1 = new ArrayList<>();
        list1.add(new Father());
        list=list1;
        //读取数据
        Object o = list.get(0);

        //写入数据:可以将Father及其子类的对象添加进来
        list.add(null);
        //list.add(new Object());
        list.add(new Father());
        list.add(new Son());
    }
posted @   新至所向  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示