java反射

java反射机制

作用

Java通过反射机制,可以在程序运行时加载、探知和使用编译期间完全未知的类,并且可以生成相关类对象实例,从而可以调用其方法或则改变某个属性值。

概念

在Java中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为Java语言的反射机制。

api
  • Class类:反射的核心类,可以获取类的属性,方法等信息。
  • Field类:Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
  • Method类: Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
  • Constructor类: Java.lang.reflec包中的类,表示类的构造方法。
获取class对象

1.调用对象的getClass()方法

Person person=new Person();
class clazz=person.getClass();

2.调用某个类的class属性来获取该类对应的class对象

Class clazz=Person.class;

3.使用class类中的forName()静态方法;(性能最好)最常用

Class clazz=Class.forName("类的全路径")
创建对象

(注意,需要类拥有无参的构造函数)

当我们获取到所需类的Class对象后,可以用它来创建对象,创建对象的方法有两种:

//获取Person类的Class对象
Class clazz=Class.forName("reflection.Person"); 
/**
* 第一种方法创建对象
*/
//创建对象
Person p=(Person) clazz.newInstance();
//设置属性
p.setName("张三");
p.setAge(16);
p.setGender("男");
System.out.println(p.toString());
/**
* 第二种方法创建
*/
//获取构造方法
Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
//创建对象并设置属性
Person p1=(Person) c.newInstance("李四","男",20);
System.out.println(p1.toString());
查看类信息与方法
            //获取Person类的Class对象
            Class clazz=Class.forName("reflection.Person");

            //获取Person类的所有方法信息
            Method[] method=clazz.getDeclaredMethods();
            for(Method m:method){
                System.out.println(m.toString());
            }

            //获取Person类的所有成员属性信息
            Field[] field=clazz.getDeclaredFields();
            for(Field f:field){
                System.out.println(f.toString());
            }

            //获取Person类的所有构造方法信息
            Constructor[] constructor=clazz.getDeclaredConstructors();
            for(Constructor c:constructor){
                System.out.println(c.toString());
            }
operation generic(操作泛型)
public class Test {
    //定义两个带泛型的方法
    public void testA(Map<String,Person> map, List<Person> list){
        System.out.println("Test.testA()");
    }
    public Map<Integer,Person> testB(){
        System.out.println("Test.testB()");
        return null;
    }


    public static void main(String[] args) {
        try {
            //获得指定方法参数泛型信息
            Method m = Test.class.getMethod("testA",Map.class,List.class);
            Type[] t = m.getGenericParameterTypes();

            for (Type paramType : t) {
                System.out.println("#"+paramType);
                if(paramType instanceof ParameterizedType){
                    //获取泛型中的具体信息
                    Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();
                    for (Type genericType : genericTypes) {
                        System.out.println("泛型类型:"+genericType);
                    }
                }
            }

            //获得指定方法返回值泛型信息
            Method m2 = Test.class.getMethod("testB");
            Type returnType = m2.getGenericReturnType();
            if(returnType instanceof ParameterizedType){
                Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();

                for (Type genericType : genericTypes) {
                    System.out.println("返回值,泛型类型:"+genericType);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/**
输出结果
#java.util.Map<java.lang.String, com.example.demo.validator.spring.Person>
泛型类型:class java.lang.String
泛型类型:class com.example.demo.validator.spring.Person
#java.util.List<com.example.demo.validator.spring.Person>
泛型类型:class com.example.demo.validator.spring.Person
返回值,泛型类型:class java.lang.Integer
返回值,泛型类型:class com.example.demo.validator.spring.Person
*/
operation annotation

注解处理器类库(java.lang.reflect.AnnotatedElement)

Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素,该接口主要有如下几个实现类:

  • Class:类定义 - Constructor:构造器定义
  • Field:类的成员变量定义
  • Method:类的方法定义
  • Package:类的包定义

java.lang.reflect 包下主要包含一些实现反射功能的工具类,实际上,java.lang.reflect 包所有提供的反射API扩充了读取运行时Annotation信息的能力。当一个Annotation类型被定义为运行时的Annotation后,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个方法来访问Annotation信息:

方法1: T getAnnotation(Class annotationClass): 返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
方法2:Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
方法3:boolean is AnnotationPresent(Class< ?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

/***********注解声明***************/

/**
 * 水果名称注解

 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}

/**
 * 水果颜色注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    /**
     * 颜色枚举
     */
    public enum Color {
        BULE, RED, GREEN
    };

    /**
     * 颜色属性
     */
    Color fruitColor() default Color.GREEN;

}

/**
 * 水果供应者注解
 * 
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
    /**
     * 供应商编号
     */
    public int id() default -1;

    /**
     * 供应商名称
     */
    public String name() default "";

    /**
     * 供应商地址
     */
    public String address() default "";
}
/*********** 注解使用 ***************/

public class Apple {

    @FruitName("Apple")
    private String appleName;

    @FruitColor(fruitColor = Color.RED)
    private String appleColor;

    @FruitProvider(id = 1, name = "陕西红富士集团", address = "陕西省西安市延安路89号红富士大厦")
    private String appleProvider;

    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }

    public String getAppleColor() {
        return appleColor;
    }

    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }

    public String getAppleName() {
        return appleName;
    }

    public void setAppleProvider(String appleProvider) {
        this.appleProvider = appleProvider;
    }

    public String getAppleProvider() {
        return appleProvider;
    }

    public void displayName() {
        System.out.println("水果的名字是:苹果");
    }
}
/*********** 注解处理器 ***************/

public class FruitInfoUtil {
    public static void getFruitInfo(Class<?> clazz) {

        String strFruitName = " 水果名称:";
        String strFruitColor = " 水果颜色:";
        String strFruitProvicer = "供应商信息:";

        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.isAnnotationPresent(FruitName.class)) {
                FruitName fruitName = (FruitName) field
                        .getAnnotation(FruitName.class);
                strFruitName = strFruitName + fruitName.value();
                System.out.println(strFruitName);
            } else if (field.isAnnotationPresent(FruitColor.class)) {
                FruitColor fruitColor = (FruitColor) field
                        .getAnnotation(FruitColor.class);
                strFruitColor = strFruitColor
                        + fruitColor.fruitColor().toString();
                System.out.println(strFruitColor);
            } else if (field.isAnnotationPresent(FruitProvider.class)) {
                FruitProvider fruitProvider = (FruitProvider) field
                        .getAnnotation(FruitProvider.class);
                strFruitProvicer = " 供应商编号:" + fruitProvider.id() + " 供应商名称:"
                        + fruitProvider.name() + " 供应商地址:"
                        + fruitProvider.address();
                System.out.println(strFruitProvicer);
            }
        }
    }
}
/***********main方法***************/
public class FruitRun {


    public static void main(String[] args) {

        FruitInfoUtil.getFruitInfo(Apple.class);

    }

}

/***********输出结果***************/
 水果名称:Apple
 水果颜色:RED
 供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值