reflect&annotation

自己快速了解到的反射和注解,存在很多理解不对的地方,日后深入了解后再回头修改。发在这里相当于一个云端存储方式了=。=

定义:

类User

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

    public User(){

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

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

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

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getId() {
        return id;
    }

    public int getAge() {
        return age;
    }

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

c1 c2等指的是class对象

1 反射

目前对反射的一个模糊理解,通过反射可以得到一个class类的一个样板,拿着这个样板一样的东西,可以访问这个类里的任何东西:属性、方法、构造方法,哪怕是用private修饰的也可以取到;

有了class的反射,也可以进行创建对象、调用方法各种操作

1.1 如何获取类的反射

  • 方式1: Class.forName(包名+类名)

    Class c1 = Class.forName("com.qing.reflection.User");
    
  • 方式2:通过对象获得

    Person person = new Student();
    Class c1 = person.getClass();
    
  • 方式3:类名.class

    Class c4 = Student.class;
    
  • 方式4:基本类型的包装类型的Type属性

    Class<Double> type = Double.TYPE;
    
  • 方式5:获得父类的类型

Class c5 = c1.getSuperclass();
System.out.println(c5);

1.2 获取类的名称、属性、方法

名称:

System.out.println(c1.getName()); //包名+类名            System.out.println(c1.getSimpleName());  //获得类的简单名字 

运行结果

com.qing.reflection.User
User

属性

获得public的属性

//获得类的属性
Field[] fields = c1.getFields();  //这种方式只能获得public的属性
for(Field field:fields){
    System.out.println(field);
}
System.out.println("-----------------------------------");

获得所有的属性


//getDeclaredFields(); 可以获得类的所有属性  private 、 public
Field[] declaredFields = c1.getDeclaredFields();
for (Field declaredField : declaredFields) {
    System.out.println(declaredField);
}

指定方式获取类的属性


Field name1 = c1.getDeclaredField("name");
System.out.println(name1);

分别对应的打印结果

private java.lang.String com.qing.reflection.User.name
private int com.qing.reflection.User.id
private int com.qing.reflection.User.age
-----------------------------------
private java.lang.String com.qing.reflection.User.name

方法

获得类的方法

Method[] methods = c1.getMethods(); //获得本类以及父类的所有方法
for (Method method : methods) {
    System.out.println("getMethods():"+method);
}

输出结果

getMethods():public java.lang.String com.qing.reflection.User.toString()
getMethods():public java.lang.String com.qing.reflection.User.getName()
getMethods():public int com.qing.reflection.User.getId()
getMethods():public void com.qing.reflection.User.setName(java.lang.String)
getMethods():public int com.qing.reflection.User.getAge()
getMethods():public void com.qing.reflection.User.setId(int)
getMethods():public void com.qing.reflection.User.setAge(int)
getMethods():public final void java.lang.Object.wait() throws java.lang.InterruptedException
getMethods():public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
getMethods():public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
getMethods():public boolean java.lang.Object.equals(java.lang.Object)
getMethods():public native int java.lang.Object.hashCode()
getMethods():public final native java.lang.Class java.lang.Object.getClass()
getMethods():public final native void java.lang.Object.notify()
getMethods():public final native void java.lang.Object.notifyAll()

可以看到有父类Object对应的方法和自身的几个方法

只获得本类的所有方法
//c1.getDeclaredMethods(); 只获得本类的所有方法
Method[] declaredMethods = c1.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
    System.out.println("getDeclaredMethods(): "+declaredMethod);
}

输出结果

getDeclaredMethods(): public java.lang.String com.qing.reflection.User.toString()
getDeclaredMethods(): public java.lang.String com.qing.reflection.User.getName()
getDeclaredMethods(): public int com.qing.reflection.User.getId()
getDeclaredMethods(): public void com.qing.reflection.User.setName(java.lang.String)
getDeclaredMethods(): public int com.qing.reflection.User.getAge()
getDeclaredMethods(): public void com.qing.reflection.User.setId(int)
getDeclaredMethods(): public void com.qing.reflection.User.setAge(int)
获得指定方法
//获得指定方法
Method getName = c1.getMethod("getName", null);
System.out.println(getName);
Method setName = c1.getMethod("setName", String.class);
System.out.println(setName);
//获得指定的方法时,输入方法名字,以及方法需要的参数类型,参数类型是参数对应的class对象

获取指定方法时,如果方法有参数就传入参数类型对应的class

输出结果:

public java.lang.String com.qing.reflection.User.getName()
public void com.qing.reflection.User.setName(java.lang.String)
获取构造方法
System.out.println("-----------------------------------");
//获得构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
    System.out.println(constructor);
}

Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
    System.out.println(declaredConstructor);
}

//获取指定的constructor
Constructor cstor2 = c1.getConstructor(String.class, int.class, int.class);
System.out.println(cstor2);
Constructor cstor3 = c1.getConstructor();
System.out.println(cstor3);

输出结果:

public com.qing.reflection.User()
public com.qing.reflection.User(java.lang.String,int,int)
    
public com.qing.reflection.User()
public com.qing.reflection.User(java.lang.String,int,int)
    
public com.qing.reflection.User(java.lang.String,int,int)
public com.qing.reflection.User()

和上面的调用方式没有什么区别,参数传递、不同方法类型声明的区别

1.3 反射操作-----对象、方法、属性

创建对象:

newInstance:
//获得class对象
Class  c1 = Class.forName("com.qing.reflection.User");
//构造一个对象
User user =(User) c1.newInstance();
System.out.println(user);
构造器方式:
//通过构造器创建对象, 这种方式是真滴变态
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User) constructor.newInstance("wtq", 1, 18);
        
       

方法调用:

 //通过反射调取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user2,"qingshen");
        System.out.println(user2.getName());
        //这也太离谱了,得到Class对象,获取该Class对象中的方法如setName,方法的对象
        //setName 再调用invoke 指定某个具体的实例,对这个实例进行操作
        //setName.invoke(user2,"qingshen");等价于 user2.setName("qingshen");
        //但是setName可以操作所有的实例
//--------------------------------------------------------------------------
      

属性操作:

//通过反射操作属性
        User user4 =(User) c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //因为name属性是私有的,这样访问会产生非法访问异常
        name.setAccessible(true); //这样就可以破坏属性的private修饰限定,也就是破坏封装性,关闭安全检测
        name.set(user4,"guangqi");
        System.out.println(user4);
    }

name.setAccessible(true); //这样就可以破坏属性的private修饰限定,也就是破坏封装性,关闭安全检测

输出结果:

User{name='null', id=0, age=0}
User{name='wtq', id=1, age=18}
18
qingshen
User{name='guangqi', id=0, age=0}


1.4反射的性能

通过反射的方式调用并执行方法,性能是不如常规的方式,setAccessible(true); 可以提升反射的性能

package com.qing.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

//分析性能问题
public class Test10 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
        test01();//2ms
        test02();//1224ms
        test03();//796ms
        //关闭检测setAccessible=true 可以提高反射的效率

    }
    //普通方式调用
    public static void test01(){
        User user = new User();
        long starTime = System.currentTimeMillis();
        for(int i=0;i<1000000000;i++){
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime-starTime)+"ms");
    }

    //反射方式调用
    public static void test02() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class c1 = Class.forName("com.qing.reflection.User");
        Method getName = c1.getDeclaredMethod("getName", null);
        User user =(User) c1.newInstance();
        long starTime = System.currentTimeMillis();
        for(int i=0;i<1000000000;i++){
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime-starTime)+"ms");
    }
    //反射方式+setAccessible=true
    public static void test03() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class c1 = Class.forName("com.qing.reflection.User");
        Method getName = c1.getDeclaredMethod("getName", null);
        User user =(User) c1.newInstance();
        getName.setAccessible(true);

        long starTime = System.currentTimeMillis();
        for(int i=0;i<1000000000;i++){
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime-starTime)+"ms");
    }
}

1.5 通过反射获取方法的泛型类型的参数

方法的定义

public void test01(Map<String,User> map, List<User> list){
    System.out.println("test01");
}
public Map<String,User> test02(){
    System.out.println("test02");
    return null;
}

方法泛型参数:


    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test11.class.getMethod("test01", Map.class, List.class);
        Type[] gPTypes = method.getGenericParameterTypes();
        for (Type gPType : gPTypes) {
            if(gPType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) gPType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        System.out.println("------------------------------");

  1. 先通过method获取泛型类型参数getGenericParameterTypes()
  2. 再判断gPType instanceof ParameterizedType
  3. 强转为ParameterizedType,获取实际的泛型类型getActualTypeArguments()
  4. 遍历返回的Type[] actualTypeArguments

输出结果:

class java.lang.String
class com.qing.reflection.User
class com.qing.reflection.User
------------------------------
对应:test01(Map<String,User> map, List<User> list)

方法泛型返回类型:

    //通过反射获取返回值的泛型
    method = Test11.class.getMethod("test02",null);
    Type gPType1 = method.getGenericReturnType();

        if(gPType1 instanceof ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) gPType1).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }

}

和上面不一样的地方就是调用method.getGenericReturnType();

输出结果:

class java.lang.String
class com.qing.reflection.User

2注解

不精确的理解:注释是写给人看的,注解是写给程序的;虽然代码程序都是给人看的,但是注释里的内容,完全不会影响到程序的执行,而注解可以

1.常见的注解

@Override重写

@Override
    public String toString() {
        return super.toString();
    }

@Deprecated

表示此方法已废弃、暂时可用,但以后此类或方法都不会再更新、后期可能会删除,建议后来人不要调用此方法

@Deprecated
public static void test(){
    System.out.println("@Deprecated");
}

@SuppressWarnings(“all”)

镇压一切警告,比如上面使用Deprecated 方法的警告

//镇压警告
@SuppressWarnings("all")
public void test02(){
    List list = new ArrayList();
}

2.自定义的注解

@Target

//target作用是限定注解的作用域,TYPE--类  METHOD--方法
@Target(value= {ElementType.METHOD,ElementType.TYPE})

@Retention

//@Retention表示我们的注解在什么地方还有效
//runtime>class>sources
@Retention(value = RetentionPolicy.RUNTIME) //注解只有一个值时,value可带可不带

@Documented

//@Documented表示是否将我们的注解生成在JAVAdoc中
@Documented

@Inherited

//@Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
}

3. 注解中的参数

@MyAnnotation2

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface  MyAnnotation2{
    //注解的参数:参数类型 + 参数名 ()
    String name() default ""; //这里设置了name的默认值为NULL
    int age() default 0;
    int id() default -1; //如果默认值为-1,代表不存在
    String[] schools() default {"东北大学"};
}

使用:

//注解可以显式赋值,没有默认值,我们必须给注解赋值
@MyAnnotation2(name="wtq",schools = {"NEU"}) //注解没有赋值顺序
public void test(){

}

@MyAnnotation3


    @MyAnnotation3("wtq")
    public void test2(){
    }

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    String value(); //当注解只有一个参数时,如果想省略参数名赋值,参数的名称必须是value
    //否则必须加上参数名  比如name=
}

3注解与反射

package com.qing.reflection;

import java.lang.annotation.*;
import java.lang.reflect.Field;

//练习反射注解
public class Test12 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.qing.reflection.student2");
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获取注解value的值
        TableQing tableQing=(TableQing) c1.getAnnotation(TableQing.class);
        String value = tableQing.value();
        System.out.println(value);
        //获取类的指定注解
        //FieldQing fieldQing =(FieldQing) c1.getAnnotation(FieldQing.class);
        Field name = c1.getDeclaredField("name");

        Field[] declaredFields = c1.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            FieldQing annotation2 = declaredField.getAnnotation(FieldQing.class);
            System.out.println(annotation2.columnName());
            System.out.println(annotation2.type());
            System.out.println(annotation2.length());
            System.out.println("------------------");
        }
        FieldQing annotation = name.getAnnotation(FieldQing.class);

    }
}
@TableQing("db_student")
class student2{
    @FieldQing(columnName = "db_id",type ="int",length = 10)
    private int id;

    @FieldQing(columnName = "db_age",type ="int",length = 10)
    private int age;

    @FieldQing(columnName = "db_name",type ="varchar",length = 3)
    private String name;
    public student2(){

    }
    public student2(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableQing{
    String value();
}

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

以数据库为例

类名注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableQing{
    String value();
}

属性注解:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldQing{
    String columnName(); //列名
    String type(); //属性
    int length();//长度
}

反射获取注解:

标注注解的类:

@TableQing("db_student")
class student2{
    @FieldQing(columnName = "db_id",type ="int",length = 10)
    private int id;

    @FieldQing(columnName = "db_age",type ="int",length = 10)
    private int age;

    @FieldQing(columnName = "db_name",type ="varchar",length = 3)
    private String name;
    public student2(){

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

自定义的注解:

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

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldQing{
    String columnName();
    String type();
    int length();
}
getAnnotations();
Class c1 = Class.forName("com.qing.reflection.student2");
//通过反射获取注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
    System.out.println(annotation);
}
获取注解的value值:
//获取注解value的值
TableQing tableQing=(TableQing) c1.getAnnotation(TableQing.class);
String value = tableQing.value();
System.out.println(value);
获取指定的注解:
Field name = c1.getDeclaredField("name");

遍历某个指定类型的所有注解:

Field[] declaredFields = c1.getDeclaredFields();
for (Field declaredField : declaredFields) {
    FieldQing annotation2 = declaredField.getAnnotation(FieldQing.class);
    System.out.println(annotation2.columnName());
    System.out.println(annotation2.type());
    System.out.println(annotation2.length());
    System.out.println("------------------");
}

输出结果

@com.qing.reflection.TableQing(value=db_student)
db_student
db_id
int
10
------------------
db_age
int
10
------------------
db_name
varchar
3
------------------


小结:

  1. 反射得到class
  2. 调用getAnnotation(),从输出结果看只能得到类的注解,属性的注解没有获取到
  3. class.getAnnotation(注解.class) 可以获取指定类型的注解
  4. 获取属性注解需要先调用getDeclaredFields();
  5. 属性注解的参数获取:declaredField.getAnnotation(FieldQing.class);
  6. annotation2+注解参数名

只要是想获取注解参数,就要先获取注解类型的对象,通过这个对象得到注解中的参数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值