杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)

简介: 杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)

一.泛型简介

  1. 把类型参数化,也就是将操作类型指定为一个参数,这种参数类型可以用在类,接口和方法的创建中,分别称为泛型类,泛型接口,泛型方法

二.代码实例

  1. 测试:在未规定类型的List里面add了String和Integer两种类型
package com.wfzn.iot.utils;
import java.util.ArrayList;
import java.util.List;
public class CommTest {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add("CSDN");
        list.add("朱勇豪");
        list.add(29);
        for (int i = 0; i < list.size(); i++) {
            String str = (String) list.get(i);
            System.out.println("泛型测试,str = " + str);
        }
    }
}
结果:
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
泛型测试,str = CSDN
  at com.wfzn.iot.utils.CommTest.main(CommTest.java:14)
泛型测试,str = 朱勇豪
Process finished with exit code 1

此时运行出错,类型不匹配,所以这时加上List,规定允许加入的类型,直接编译不通过,这就是泛型的优点之一,保证安全

三.优缺点

(1) 类型安全

使得类型错误在编译期间就被发现

(2) 消除强制类型转换

(3) 更高的效率

避免了拆箱和装箱

(4) 潜在的性能收益

四.常见泛型中字母的含义: 类<字母>

  1. T 代表类型
  2. K V 分别代表键值对中的key value
  3. E 代表Element
  4. ?表示不确定的类型

五.注意事项

  1. 定义一个泛型类时在<>中定义形式类型参数 例如:class A<K,V> 其中的K,V代表类型
  2. 实例化泛型对象是一定要指定类型,前后都要(其实后面不指定就是默认和前面一致) Generic genericInteger = new Generic(123456);
  3. 泛型必须为引用数据类型,不能为基本数据类型
  4. 不可定义泛型数组
  5. static 方法中不可以用泛型,泛型变量也不可用static修饰
  6. 泛型只在编译器有效
package com.wfzn.iot.utils;
import io.swagger.models.auth.In;
import java.util.ArrayList;
import java.util.List;
public class CommTest {
    public static void main(String[] args) {
        List<String> listStr = new ArrayList<String>();
        List<Integer> listInt = new ArrayList<Integer>();
        System.out.println(listInt.getClass());
        System.out.println(listStr.getClass());
        System.out.println(listStr.getClass().equals(listInt.getClass()));
    }
}
结果
class java.util.ArrayList
class java.util.ArrayList
true
Process finished with exit code 0

六、泛型的使用

泛型类,泛型方法, 泛型接口)

  1. 泛型类
package com.wfzn.iot.utils;
import lombok.Data;
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T> {
    //key这个成员变量的类型为T,T的类型由外部指定
    private T key;
    //泛型构造方法形参key的类型也为T,T的类型由外部指定
    public Generic(T key){
        this.key = key;
    }
    //泛型方法getKey的返回值类型为T,T的类型由外部指定
    private T getKey(){
        return key;
    }
    public static void main(String[] args) {
        //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
        //传入的实参类型需与泛型的类型参数类型相同,即为Integer.
        Generic<Integer> genericInteger = new Generic<>(123456);
        //传入的实参类型需与泛型的类型参数类型相同,即为String.
        Generic<String> genericString = new Generic<>("朱勇豪");
        System.out.println("泛型测试,key is "+genericInteger.getKey());
        System.out.println("泛型测试,key is "+genericString.getKey());
//可以随便传
        Generic generic = new Generic("111111");
        Generic generic1 = new Generic(4444);
        Generic generic2 = new Generic(55.55);
        Generic generic3 = new Generic(false);
        System.out.println(generic.getKey());
        System.out.println(generic1.getKey());
        System.out.println(generic2.getKey());
        System.out.println(generic3.getKey());
    }
}
结果
泛型测试,key is 123456
泛型测试,key is 朱勇豪
111111
4444
55.55
false
Process finished with exit code 0
  1. 泛型接口
1.泛型接口
package com.wfzn.iot.utils;
/**
 * @author Zhuyh
 * @date 2021-11-04 11:06
 */
public interface Generator<T> {
    public T next();
}
2.未指定类型的实现类
package com.wfzn.iot.utils;
public class GeneratorImpl<T> implements Generator<T> {
    @Override
    public T next() {
        return null;
    }
}
3.指定参数的实现类    
package com.wfzn.iot.utils;
import java.util.Random;
public class GeneratorParamImpl<T> implements Generator<String> {
    String[] strings = new String[]{"a", "bc", "defg"};
    @Override
    public String next() {
        Random random = new Random();
        System.out.print(strings[random.nextInt(3)]+" ");
        return strings[random.nextInt(3)];
    }
    public static void main(String[] args) {
        final GeneratorParamImpl<String> stringGeneratorParam = new GeneratorParamImpl<>();
        for (int i = 0; i < 100; i++) {
            stringGeneratorParam.next();
        }
    }
}
结果: a defg a bc bc bc defg bc bc defg 
  1. 泛型通配符
    情况

    解决方式:通配符
package com.wfzn.iot.utils;
public class Test {
    public static void main(String[] args) {
        final Generic<Integer> generic = new Generic<Integer>(123);
        final Generic<Number> generic2 = new Generic<Number>(123456);
        getValue(generic);
        getValue(generic2);
    }
    private static void getValue(Generic<?> generic){
        System.out.println(generic.getKey());
    }
}
结果
123
123456
  1. 泛型方法
    泛型类:是在实例化的时候指定类型
    泛型方法:是在调用方法时指定类型
package com.wfzn.iot.utils;
public class Test {
    public static void main(String[] args) {
        try {
            Object CSDN = genericMethod(Class.forName("com.wfzn.iot.utils.Generic"));
            System.out.println(CSDN);
            Object OSCHINA = genericMethod(Class.forName("com.wfzn.iot.utils.GeneratorImpl"));
            System.out.println(OSCHINA);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * 泛型方法的基本介绍
     * @param tClass 传入的泛型实参
     * @return T 返回值为T类型
     * 说明:
     *     1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
     *     2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
     *     3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
     *     4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
     */
    public static <T> T genericMethod(Class<T> tClass)throws InstantiationException,IllegalAccessException{
        return tClass.newInstance();
    }
}
结果:
就是你
com.wfzn.iot.utils.Generic@707f7052
还是你
com.wfzn.iot.utils.GeneratorImpl@11028347
附加:
Generic类
public class Generic<T> {
    public Generic(){}
    static {
        System.out.println("就是你,好像不是你");
     } 
  }
GeneratorImpl类
public class GeneratorImpl<T> implements Generator<T> {
    public GeneratorImpl(){
    }
    static {
        System.out.println("还是你");
    }
    @Override
    public T next() {
        return null;
    }
}

泛型方法与可变参数

package com.wfzn.iot.utils;
public class Test {
    //静态方法中使用泛型,必须要将泛型定义在方法上。
    public static <T> void printMsg(T...args){
        for(T t:args){
            System.out.println("泛型测试,it is "+t);
        }
    }
    
    public static void main(String[] args) {
        printMsg("1111",2222,"朱勇豪","0.00",55.55);
    }
}
结果:
泛型测试,it is 1111
泛型测试,it is 2222
泛型测试,it is 朱勇豪
泛型测试,it is 0.00
泛型测试,it is 55.55

七、泛型上下边界

  1. 设定通配符上限
    比如我现在想接受一个List集合它只能操作类型为【float,double,int等】,直接使用通配符是不行的
package com.wfzn.iot.utils;
import java.util.ArrayList;
import java.util.List;
public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> integers = new ArrayList<>();
        ArrayList<Double> doubles = new ArrayList<>();
        ArrayList<String> strings = new ArrayList<>();
        test(doubles);
        test(integers);
        test1(doubles);
        test1(integers);
        //设置了list上限为Number时就不能存String
        test(strings);
//        test1(strings);
    }
    public static void test(List<?> list) {
        System.out.println(list.getClass());
    }
    public static void test1(List<? extends Number> list) {
        System.out.println(list.getClass().getName());
    }
}
  1. 设定通配符下限(比较少见)
//传递进来的只能是Type或Type的父类
<? super Type>

八、泛型应用

抽象BaseDao

package com.wfzn.iot.utils;
import cn.hutool.db.Session;
import java.lang.reflect.ParameterizedType;
public abstract class BaseDao<T> {
    private Session session;
    private Class clazz;
    public BaseDao() {
        Class clazz = this.getClass();
        ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass();
        clazz = (Class) pt.getActualTypeArguments()[0];
        System.out.println(clazz);
    }
        public void add(T t){
            System.out.println(t+",增加");
        }
        public T find(String id){
            System.out.println("查找"+id);
            Worker worker = null;
            return (T)worker;
        }
        public void update(T t){
            System.out.println(t+",更新");
        }
        public void delete(String id){
            System.out.println("删除"+id);
        }
}

Worker实体类

package com.wfzn.iot.utils;
import cn.hutool.db.Session;
import java.lang.reflect.ParameterizedType;
public abstract class BaseDao<T> {
    private Session session;
    private Class clazz;
    public BaseDao() {
        Class clazz = this.getClass();
        ParameterizedType pt = (ParameterizedType) clazz.getGenericSuperclass();
        clazz = (Class) pt.getActualTypeArguments()[0];
        System.out.println(clazz);
    }
        public void add(T t){
            System.out.println(t+",增加");
        }
        public T find(String id){
            System.out.println("查找"+id);
            Worker worker = null;
            return (T)worker;
        }
        public void update(T t){
            System.out.println(t+",更新");
        }
        public void delete(String id){
            System.out.println("删除"+id);
        }
}

WorkerDao继承BaseDao

package com.wfzn.iot.utils;
public class WorkerDao extends BaseDao<Worker> {
    private static WorkerDao instance = new WorkerDao();
    @Override
    public void add(Worker worker) {
        super.add(worker);
    }
    @Override
    public Worker find(String id) {
        return super.find(id);
    }
    @Override
    public void update(Worker worker) {
        super.update(worker);
    }
    @Override
    public void delete(String id) {
        super.delete(id);
    }
    public static void main(String[] args) {
        Worker worker = new Worker();
        worker.setId(1);
        worker.setName("朱勇豪");
        WorkerDao.instance.add(worker);
        WorkerDao.instance.find("");
        WorkerDao.instance.update(worker);
        WorkerDao.instance.delete("");
    }
}
    

结果

附加:

TeacherDao 继承 BaseDao

package com.wfzn.iot.utils;
public class TeacherDao extends BaseDao<Teacher> {
    private static TeacherDao instance=new TeacherDao();
    @Override
    public void add(Teacher teacher) {
        super.add(teacher);
    }
    @Override
    public Teacher find(String id) {
        return super.find(id);
    }
    @Override
    public void update(Teacher teacher) {
        super.update(teacher);
    }
    @Override
    public void delete(String id) {
        super.delete(id);
    }
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setId(1);
        teacher.setName("朱勇豪");
        TeacherDao.instance.add(teacher);
        TeacherDao.instance.find("");
        TeacherDao.instance.update(teacher);
        TeacherDao.instance.delete("");
    }
}
相关文章
|
1天前
|
存储 监控 Java
《从头开始学java,一天一个知识点》之:数组入门:一维数组的定义与遍历
**你是否也经历过这些崩溃瞬间?** - 看了三天教程,连`i++`和`++i`的区别都说不清 - 面试时被追问&quot;`a==b`和`equals()`的区别&quot;,大脑突然空白 - 写出的代码总是莫名报NPE,却不知道问题出在哪个运算符 这个系列就是为你打造的Java「速效救心丸」!我们承诺:每天1分钟,地铁通勤、午休间隙即可完成学习;直击痛点,只讲高频考点和实际开发中的「坑位」;拒绝臃肿,没有冗长概念堆砌,每篇都有可运行的代码标本。明日预告:《多维数组与常见操作》。 通过实例讲解数组的核心认知、趣味场景应用、企业级开发规范及优化技巧,帮助你快速掌握Java数组的精髓。
42 23
|
7天前
|
运维 Java 程序员
Java中的异常处理方法
本文深入剖析Java异常处理机制,介绍可检查异常、运行时异常和错误的区别与处理方式。通过最佳实践方法,如使用合适的异常类型、声明精确异常、try-with-resources语句块、记录异常信息等,帮助开发者提高代码的可靠性、可读性和可维护性。良好的异常处理能保证程序稳定运行,避免资源泄漏和潜在问题。
|
7天前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
27 5
|
26天前
|
存储 安全 算法
Java容器及其常用方法汇总
Java Collections框架提供了丰富的接口和实现类,用于管理和操作集合数据。
Java容器及其常用方法汇总
|
1月前
|
存储 缓存 Java
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
95 3
java语言后台管理ruoyi后台管理框架-登录提示“无效的会话,或者会话已过期,请重新登录。”-扩展知识数据库中密码加密的方法-问题如何解决-以及如何重置若依后台管理框架admin密码-优雅草卓伊凡
|
26天前
|
Java API
java.time常用方法汇总
`java.time` API 是从 Java 8 开始引入的时间日期处理库,旨在替代老旧的 `java.util.Date` 和 `Calendar`。它提供了更简洁、强大和灵活的方式处理日期、时间、时区及时间间隔,支持全球化和时间计算需求。API 包含获取当前时间、创建指定时间、解析和格式化字符串、进行加减运算、比较时间、获取年月日时分秒、计算时间间隔、时区转换以及判断闰年等功能。示例代码展示了如何使用这些功能,极大简化了开发中的时间处理任务。
|
2月前
|
Java
Java快速入门之类、对象、方法
本文简要介绍了Java快速入门中的类、对象和方法。首先,解释了类和对象的概念,类是对象的抽象,对象是类的具体实例。接着,阐述了类的定义和组成,包括属性和行为,并展示了如何创建和使用对象。然后,讨论了成员变量与局部变量的区别,强调了封装的重要性,通过`private`关键字隐藏数据并提供`get/set`方法访问。最后,介绍了构造方法的定义和重载,以及标准类的制作规范,帮助初学者理解如何构建完整的Java类。
|
2月前
|
Java 程序员 调度
Java 高级面试技巧:yield() 与 sleep() 方法的使用场景和区别
本文详细解析了 Java 中 `Thread` 类的 `yield()` 和 `sleep()` 方法,解释了它们的作用、区别及为什么是静态方法。`yield()` 让当前线程释放 CPU 时间片,给其他同等优先级线程运行机会,但不保证暂停;`sleep()` 则让线程进入休眠状态,指定时间后继续执行。两者都是静态方法,因为它们影响线程调度机制而非单一线程行为。这些知识点在面试中常被提及,掌握它们有助于更好地应对多线程编程问题。
84 9
|
2月前
|
Java 调度 开发者
Java线程池ExecutorService学习和使用
通过学习和使用Java中的 `ExecutorService`,可以显著提升并发编程的效率和代码的可维护性。合理配置线程池参数,结合实际应用场景,可以实现高效、可靠的并发处理。希望本文提供的示例和思路能够帮助开发者深入理解并应用 `ExecutorService`,实现更高效的并发程序。
42 10
|
2月前
|
安全 Java 程序员
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
77 12

热门文章

最新文章