注解与反射

注解

1.什么是注解

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。

Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

2.常用的注解

@Deprecated  -- @Deprecated 所标注内容,不再被建议使用。
@SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
@Override    -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
//元注解
@Documented  -- @Documented 所标注内容,可以出现在javadoc中。
@Inherited   -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
@Retention   -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定AnnotationRetentionPolicy属性。
@Target      -- @Target只能被用来标注“Annotation类型”,而且它被用来指定AnnotationElementType属性。

3.自定义注解

// Target 表示我们的注解可以用在哪些地方,TYPE:类、接口(包括注解类型)或枚举声明
@Target(value = {ElementType.TYPE, ElementType.METHOD})
// Retention 表示我们的注解保留多长时间 runtime>class>sources
@Retention(value = RetentionPolicy.RUNTIME)
// Documented 是否将我们的注解生成在java Doc中
@Documented
// Inherited 子类可以继承父类的注解
@Inherited
public @interface MyAnnotation {
    // 注解的参数:参数类型+参数名();
    // 注解可以显式赋值,如果没有默认值,我们必须给注解赋值
    // 如果只有一个参数,一般参数名为value,使用注解时可以不写value,默认给value赋值
    String name() default "";
    // 如果默认值为-1,代表不存在
    int id() default -1;
}

public class Test {
    @MyAnnotation(name="李泽玉")
    public void test() {

    }
}

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口

反射

Reflection(反射)是java被视为动态语言的关键,反射机制允许程序在执行期取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

正常方式:引入需要的“包类”名称->通过new实例化->取得实例化对象

反射方式:实例化对象->getClass()方法->得到完整的“包类”名称

1.Class类的常用方法

public static Class<?> forName(String className)//传入完整的“包.类”名称实例化Class对象
public Object newInstance() //根据Class定义的类实例化对象
public Constructor[] getContructors() //得到一个类的全部的构造方法
public Field[] getDeclaredFields()//得到本类中单独定义的全部属性
public Field[] getFields()//得到本类继承而来的全部属性
public Method[] getMethods()//得到一个类的全部方法
public Method getMethod(String name,Class..parameterType)//返回一个Method对象,并设置一个方法中的所有参数类型
public Class[] getInterfaces() //得到一个类中锁实现的全部接口
public String getName() //得到一个类完整的“包.类”名称
public Package getPackage() //得到一个类的包
public Class getSuperclass() //得到一个类的父类
public Class<?> getComponentType() //返回表示数组类型的Class
public boolean isArray() //判断此class是否是一个数组

测试通过反射获取类的对象

/**
 * Created by nanfeng on 2021/08/04
 */
public class Test {

    public static void main(String[] args) throws ClassNotFoundException {

        // 一个类在内存中只有一个Class对象
        //一个类被加载后,类的整个结构都会被封装在Class对象中

        User user = new Student();
        System.out.println("这个人是:" + user.name);

        //方式一:通过forName获取类的class对象
        Class c1 = Class.forName("Student");
        System.out.println(c1.hashCode());

        //方式二:通过对象获得
        Class c2 = user.getClass();
        System.out.println(c2.hashCode());

        //方式三:通过类名.class获得
        Class<Student> c3 = Student.class;
        System.out.println(c3.hashCode());

        /**
         * 结果:
         * 这个人是:学生
         * 1163157884
         * 1163157884
         * 1163157884
         */

        //获得父类类型
        Class c4 = c1.getSuperclass();
        System.out.println(c4);
    }

}

class User{
    protected String name;
    private int id;
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }

    public User(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public User() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        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;
    }
}

class Student extends User {
    public Student() {
        this.name = "学生";
    }
}
class Teacher extends User {
    public Teacher() {
        this.name = "老师";
    }
}

2.类的加载与ClassLoader的理解

在这里插入图片描述

3.什么时候会发生类的初始化

  • 类的主动引用(一定会发生类的初始化)
    • 当JVM虚拟机启动,先初始化main方法所在的类
    • new 一个类的对象
    • 调用类的静态成员(final常量除外)和静态方法
    • 使用java.lang.reflect包的方法对类进行反射调用
    • 当初始化一个类,如果其父类没有被初始化,则会先初始化他的父类
  • 类的被动引用(不会发生类的初始化)
    • 当访问一个静态域时,只有真正申明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化。
    • 通过数组定义类引用,不会触发此类的初始化。
    • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

4.类加载器

具体请参考狂神说jvm入门教学:https://www.bilibili.com/video/BV1iJ411d7jS

笔记请参考:https://blog.csdn.net/weixin_42248256/article/details/114582083

5.获取运行时类的完整结构

提供User类及其属性和方法

package reflection;

/**
 * Created by nanfeng on 2021/08/05
 */
public class User{
    protected String name;
    private int id;
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }

    public User(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public User() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        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 static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {

        //获取类的信息

        Class c1 = Class.forName("reflection.User");

        //1.获取类的名字

        //获得包名 + 类名 reflection.User
        System.out.println(c1.getName());
        //获得类名  User
        System.out.println(c1.getSimpleName());

        //2.获得类的属性

        //只能找到public属性  “”
        Field[] fields = c1.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //找到全部的属性
        /**
         * protected java.lang.String reflection.User.name
         * private int reflection.User.id
         * private int reflection.User.age
         */
        fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //获得指定的属性

        //private int reflection.User.age
        System.out.println(c1.getDeclaredField("age"));

        //3.获得类的方法

        //获取本类及其父类全部的public方法
        /**
         * public java.lang.String reflection.User.toString()
         * public java.lang.String reflection.User.getName()
         * public int reflection.User.getId()
         * public void reflection.User.setName(java.lang.String)
         * public void reflection.User.setId(int)
         * public void reflection.User.setAge(int)
         * public int reflection.User.getAge()
         * public final void java.lang.Object.wait() throws java.lang.InterruptedException
         * public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
         * public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
         * public boolean java.lang.Object.equals(java.lang.Object)
         * public native int java.lang.Object.hashCode()
         * public final native java.lang.Class java.lang.Object.getClass()
         * public final native void java.lang.Object.notify()
         * public final native void java.lang.Object.notifyAll()
         */
        for (Method method : c1.getMethods()) {
            System.out.println(method);
        }

        //获取本类的所有方法
        /**
         * public java.lang.String reflection.User.toString()
         * public java.lang.String reflection.User.getName()
         * public int reflection.User.getId()
         * public void reflection.User.setName(java.lang.String)
         * public int reflection.User.getAge()
         * public void reflection.User.setAge(int)
         * public void reflection.User.setId(int)
         */
        for (Method method : c1.getDeclaredMethods()) {
            System.out.println(method);
        }

        //获得指定方法
        /**
         * public java.lang.String reflection.User.getName()
         * public void reflection.User.setName(java.lang.String)
         */
        System.out.println(c1.getMethod("getName", null));
        System.out.println(c1.getMethod("setName", String.class));

        //4.获取类的构造器

        /**
         * public reflection.User()
         * public reflection.User(java.lang.String,int,int)
         */
        for (Constructor constructor : c1.getDeclaredConstructors()) {
            System.out.println(constructor);
        }

    }

6.动态创建对象,通过反射

public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {

        //获取Class对象
        Class c1 = Class.forName("reflection.User");

        //1.构建一个对象

        //本质上是调用了类的无参构造器
        User user = (User) c1.newInstance();
        /**
         * User{name='null', id=0, age=0}
         */
        System.out.println(user);

        //2.通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User lizeyu = (User) constructor.newInstance("lizeyu", 100, 23);
        /**
         * User{name='lizeyu', id=100, age=23}
         */
        System.out.println(lizeyu);

        //3.通过反射调用方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //invoke:激活,(对象,“参数的值”)
        setName.invoke(lizeyu, "李泽玉");
        /**
         * User{name='李泽玉', id=100, age=23}
         */
        System.out.println(lizeyu);

        //4.通过反射操作属性
        Field name = c1.getDeclaredField("name");
        /**
         * 不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true)
         */
        name.setAccessible(true);
        
        name.set(lizeyu, "nanfeng");
        System.out.println(lizeyu);
    }

7.反射操作注解

定义一个类、两个注解

import java.lang.annotation.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by nanfeng on 2021/08/04
 */
public class Test {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<User> c1 = User.class;

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        /**
         * 结果:@Table(value=db_user)
         */
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得注解的value值
        Table table = c1.getAnnotation(Table.class);
        //结果:@包名 + Table(value=db_user)
        System.out.println(table.value());

        //获得属性指定的注解
        Field f = c1.getDeclaredField("name");
        Para annotation=  f.getAnnotation(Para.class);
        /**
         * name
         * 10
         * String
         */
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }
}

@Table("db_user")
class User{
    @Para(columnName = "name",type = "String",length = 10)
    private String name;
    @Para(columnName = "id",type = "int",length = 10)
    private int id;
    @Para(columnName = "age",type = "int",length = 10)
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }

    public User(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public User() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        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;
    }
}

//类名的注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}

//属性的注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Para {
    String columnName();
    String type();
    int length();
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nan feng

打赏一杯咖啡吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值