java泛型、反射与注解

通常我们在开发的时候会遇到各种相似的问题,这种问题如果不用一种方法解决的话,会造成代码冗余。

例如,我们在审批的时候,有些简单的流程只需要改变状态,我们可以有以下方法解决:

一、泛型类

public class UpdateEntityUtils<T,V extends IService<T>>{

    public T setStatus(V v,String id,String status){
        T t = v.getById(id);
        Class clazz = t.getClass();
        try{
            Method method = clazz.getDeclaredMethod("setStatus",String.class);
            method.setAccessible(true);
            method.invoke(t,status);
            return t;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }finally {
            return t;
        }
    }
}

这种在类名后面加上泛型的就是泛型类,实例化该类时需要传入对应的类型。

二、泛型方法

public class UpdateEntityUtils{

    public <T,V extends IService<T>> T setStatus(V v,String id,String status){
        T t = v.getById(id);
        Class clazz = t.getClass();
        try{
            Method method = clazz.getDeclaredMethod("setStatus",String.class);
            method.setAccessible(true);
            method.invoke(t,status);
            return t;
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }finally {
            return t;
        }
    }
}

这种在方法的返回值前面加上泛型的就是泛型方法,而泛型方法可以传入任何满足的类型。

三、泛型类和泛型方法的使用区别

1、IService

public interface IService<T> {

    /**
     * 根据ID返回实体
     * @param id
     * @return
     */
    T getById(String id);
}

2、StudentServiceImpl

public class StudentServiceImpl implements IService<Student> {
    @Override
    public Student getById(String id) {
        Student student = new Student();
        student.setStudentName("student");
        student.setStudentNo("666");
        student.setStatus("studying");
        return student;
    }
}

3、TeacherServiceImpl

public class TeacherServiceImpl implements IService<Teacher> {
    @Override
    public Teacher getById(String id) {
        Teacher teacher = new Teacher();
        teacher.setTeacherName("teacher");
        teacher.setTeacherNo("888");
        teacher.setStatus("teaching");
        return teacher;
    }
}

Main(泛型类)

public class Main {
    public static void main(String[] args) {
        StudentServiceImpl studentService = new StudentServiceImpl();
        TeacherServiceImpl teacherService = new TeacherServiceImpl();
        UpdateEntityUtils<Student,StudentServiceImpl> studentUtils = new UpdateEntityUtils<>();
        studentUtils.setStatus(studentService,"666","playing");
        UpdateEntityUtils<Teacher,TeacherServiceImpl> teacherUtils = new UpdateEntityUtils<>();
        teacherUtils.setStatus(teacherService,"888","playing");
    }
}

如果使用泛型类的的话,里面的方法(非泛型方法)对只能对特定的类使用。

如果要改变不同实体类的状态的话,需要实例话多次。


Main(泛型方法)

public class Main {
    public static void main(String[] args) {
        StudentServiceImpl studentService = new StudentServiceImpl();
        TeacherServiceImpl teacherService = new TeacherServiceImpl();
        UpdateEntityUtils updateEntityUtils = new UpdateEntityUtils();
        updateEntityUtils.setStatus(studentService,"666","playing");
        updateEntityUtils.setStatus(teacherService,"888","playing");
    }
}

如果使用泛型方法的话,类只需要实例化一次即可,可以通过泛型方法改变不同实体类的状态。

 四、泛型类和泛型方法总结

泛型类更偏向于对类其中的方法(非泛型方法)做出一种限制,泛型方法则没得这种限制,泛型类中也可以有泛型方法。

类名后面加上泛型的就是泛型类,方法的返回值前面加上泛型的就是泛型方法。

五、泛型通配符

我们在定义泛型类,泛型方法时会碰见很多不同的通配符,如 T,E,K,V 等等。

本质上这些个都是通配符,没啥区别,只不过是编码时的一种约定俗成的东西。

比如上述代码中的 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行。

泛型通配符可分为两类,上界通配符和下界通配符:

上界通配符:用 extends 关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。

下界通配符:用 super 进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型。

六、?和T的区别

比如上面的例子,我们使用了 <T,V extends IService<T>>,然后通过V调用了getById方法。

而如果我们使用<T,? extends IService<T>>,实际上这是行不通的,因为不能 ? 一个变量出来。

T表示一种确定的类型,而?表示不在意该类型是什么,也不会用到它。

7、Class<?>和Class<T>的区别

如果不是在抽象类里面,Class<T> tClass会报错,但是Class<?> aClass 不会。

因为T代表一种类型,而?可以代表任何类型,另外Class是一个泛型类,但是他的构造方法都是私有的。

八、反射

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性。

九、注解概念

 我们在日常开发中,经常会用到各种注解,可能我们已经习以为常了,但是你是否注意到它是如何生效的呢。

Ⅰ、注解的格式

public @interface AnnotationName {
    //属性列表
    public String name();
    public String code();
    public String msg();
}

Ⅱ、注解能使用的类型

①、八大基本数据类型(boolean,byte,char,short,int,long,float,double)

②、String

③、String和八大基本类型的一维数组

④、Class

⑤、枚举

⑥、其他的注解

Ⅲ、注解的分类

注解大致可分为三类:自定义注解、JDK内置注解、第三方框架提供的注解。

要想注解起作用必然有三步曲:定义注解,使用注解,然后读取注解。

通常我们在使用第三方框架提供的注解时,往往只能看到前两步,却不知道它在哪儿读取注解。

每个注解都像是一个标签,贴在类、方法上或者字段上,以表示它的特征。

十、总结

许多优秀的框架都是泛型、反射和注解一起使用的,它们封装好我们就可以使用了。

他们编写的注解解析器我们通常看不到,但是一定是存在的,因为看不到,所以我们用起来会感觉很美观。

他们和我们编写的注解解析器其实差不多,只是我们编写的代码少,可以很快追溯到根源。

反正我们记住要使注解起作用,必然存在注解解析器。

posted @ 2021-04-01 09:24  M-Anonymous  阅读(252)  评论(0编辑  收藏  举报