Java注解&反射

一.注解Annotation

1.什么是注解

注解是以“@注释名”在代码中存在。

代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相对应的处理。

减少了配置,大量减少了代码量,通过反射机制实现对这些元数据(为其他数据提供信息的数据)的访问。

在开发中使用也是比较常见的,比如:@Controller、@Param、@Data等,Java原生(标记&检查)有@Overried、@Deprecated、@Functional

2.基本内置注解

  • @Override 表示这个方法重写了父类的方法
  • @Deprecated 表示这个方法已经过期,不建议开发者使用
  • @SuppressWarnings 表示忽略警告信息

3.自定义注解

利用反射读取注解

public class Test3 {

    public static void main(String[] args) {
        try {
            // 1.反射
            Class clazz = Class.forName("com.annotation.Student");
            // 2.获得这个类的注解
            Annotation[] annotations = clazz.getAnnotations();
            for (Annotation annotation:annotations){
                System.out.println(annotation);
            }
            // 3.获得类的注解value的值
            TableKuang table = (TableKuang)clazz.getAnnotation(TableKuang.class);
            System.out.println(table.value());

            // 4.获得类指定注解的值
            Field name = clazz.getDeclaredField("name");
            FieldKuang fieldKuang = name.getAnnotation(FieldKuang.class);
            System.out.println(fieldKuang.columnName()+"-->"+fieldKuang.type()+"-->"+fieldKuang.length());


        } catch (ClassNotFoundException | NoSuchFieldException e) {
            e.printStackTrace();
        }
    }


}
@TableKuang("db_student")
class Student{

    @FieldKuang(columnName = "db_id",type="int",length = 10)
    private int id;
    @FieldKuang(columnName = "db_name",type="varchar",length = 10)
    private String name;
    @FieldKuang(columnName = "db_age",type="int",length = 3)
    private int age;

    ......
}

// 表名注解
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface TableKuang{
    String value();
}

// 属性注解
@Target(value = {ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface FieldKuang{
    String columnName(); // 列名
    String type(); // 类型
    int length();  // 长度
}

4.元注解

元注解的作用就是负责注解其他注解

@Tartget:用于描述注解的使用范围(Type修饰类、接口或枚举类型;Filed成员变量;Method方法;)

@Retention:表示生命周期(source<class<runtime)

@Inherited:表示子类可以继承父类的注解

@Ducumented:表示注解将被包含在javadoc中

 

二.反射

这里讲一下 「 运行时 」,.java文件经过javac编译变成.class文件,class文件会被JVM装载运行。

我记得在工作中,我有一个需求是主系统对用户表、部门表等增量变化的同时要求去增量同步子系统对应的用户表、部门表数据。增量同步的这个工具类就有用到了反射技术。一个好的工具就要兼容各种情况(用户、部门等)。

还有就是SpringMVC中在方法写上对象,传入的参数就会封装到对象上。

这些例子都有涉及到反射:约定大于配置,配置大于硬编码。

2.1 什么是反射

反射是Java被视为动态语言的关键,反射机制允许程序在执行期借助于反射API得到类的内部信息,并能直接操作任意对象的内部属性以及方法。

加载类之后,在堆内存的方法区就产生了一个Class类型的对象,这个对象就包含了完整的类的结构信息。

优点:可以实现动态创建对象和编译,体现出很大的灵活性。

缺点:对性能有影响,慢于直接执行相同的操作。

2.2 类的加载过程

2.2.1 加载

将class文件字节码内容加载到内存,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象

2.2.2 链接

将Java类的二进制代码合并到JVM的运行状态之中的过程

验证:确保加载的类信息符合JVM规范

准备:正式为类变量分配内存并设置类变量默认初始值的阶段(方法区)

解析:虚拟机常量池内的符号引用替换为直接引用的过程

2.2.3 初始化

执行类构造器方法的过程

当初始化一个类的时候,如果发现其父类还没有初始化,则需要先触发其父类的初始化

虚拟机会保证一个类的方法在多线程环境中被正确加锁和同步

 

2.3  类的加载器

类加载器的作用是将class文件字节码内容加载内存中,并将静态数据转换成方法数据结构,然后在堆中生成一个代表这个类的java.lang.class对象,作为方法区中类数据的访问入口

2.4  获取类对象

  • wistchen.getClass()
  • Class.forName("包名+类名")
  • Wistchen.class
  • ClassLoader classLoader = this.getClass().getClassLoader(); classLoader.loadClass(className);

2.5 类对象的常用方法

  • static ClassforName(String name) 返回指定类名name的class对象
  • Object newInstance() 调用缺省构造函数,返回Class对象的一个实例
  • getName() 返回此Class对象所表示的实体的名称
  • Class getSuperClass() 返回当前CLass对象的父类的Class对象
  • Class[] getinterfaces() 获取当前Class对象的接口
  • ClassLoader getClassLoader() 返回该类的类加载器
  • Constructor[] getConstructors() 返回一个包行某些Constructor对象的数组
  • Method getMethed(String name,Class T) 返回一个Method对象
  • Field getDeclaredFields() 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。 (注: 这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))
  • Field getField 只能获取public的,包括从父类继承来的字段。

2.5  创建对象

  • Class pClass = Class.forName(className); 类对象
  • Constructor c = pClass.getConstructor();构造器
  • c.newInstance() 通过构造器实例化

2.6  访问属性

public class TestReflection {
    public static void main(String[] args) {
        Hero hero = new Hero();
        hero.name = "garen";

        try{
            Field f1 = hero.getClass().getDeclaredField(("name"));
            f1.set(hero,"teemo");
            System.out.println(hero.name);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

class Hero{
    public String name; //为了访问属性,把name修改为public
    public float hp;
    public  int damage;
    public int id;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Hero(){

    }
    public Hero(String string) {
        name =string;
    }

    @Override
    public String toString() {
        return "Hero [name=" + name + "]";
    }
    public boolean isDead() {
        // TODO Auto-generated method stub
        return false;
    }
    public void attackHero(Hero h2) {
        System.out.println(this.name+ " 正在攻击 " + h2.getName());
    }
}

2.7 调用方法

public class TestReflection2 {
    public static void main(String[] args) {
        Hero1 hero1 = new Hero1();

        try{
           // 获取这个名字叫做setName,参数类型是String的方法
            Method m = hero1.getClass().getMethod("setName", String.class);
           // 对h对象,调用这个方法            
            m.invoke(hero1,"wistchen");
            System.out.println(hero1.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
class Hero1 {
    public String name;
    public float hp;
    public int damage;
    public int id;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Hero1(){

    }
    public Hero1(String string) {
        name =string;
    }

    @Override
    public String toString() {
        return "Hero1 [name=" + name + "]";
    }
    public boolean isDead() {
        // TODO Auto-generated method stub
        return false;
    }
    public void attackHero(Hero h2) {
        // TODO Auto-generated method stub

    }

}

 

学习参考来自:

  • B站狂神说
  • 公众号Java3y
  • HOW2J.CN

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值