反射与注解

一、反射

1. 反射概述(Class/Field/Method/Constructor)

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java基础篇:反射机制详解
实际上,我们创建的每一个类也都是对象,即类本身是java.lang.Class类的实例对象。这个实例对象称之为类对象,也就是Class对象。

通俗的说,所有的类都可以通过Class类进行反射操作,可以视Class类为类的母类,其包含所有类的实例方法,实例对象等。

2. 获取Class类的对象

我们要向通过反射去使用一个类,首先我们要获取到该类的字节码文件对象,也就是类型为Class类型的对象,可以通过以下三种方法来获取Class类型的对象。

  1. 使用class属性来获取该类对应的Class对象。比如:Student.class将会返回Student类对应的Class对象
  2. 调用对象的getClass()方法,返回该对象所属类的对应的Class对象(该方法是Object类中的方法,返回该对象所属类对应的Class对象)
  3. 使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径。
Class.forName()(常用)
Hero.class
new Hero().getClass()

3. 反射获取构造方法并使用

Class类中用于获取构造方法的方法

Constructor<?> [] getConstructors():返回所有公共构造方法对象的数组
Constructor<?> []getDeclaredConstructors():返回所有构造方法对象的数组
Constructor []getConstructor(Class<?>…parameterTypes):返回单个公共构造方法对象
Constructor[] getDeclaredConstructor(Class<?>…parameterTypes):返回单个构造方法对象

代码示例:

import java.util.Date;

public class Student {
    private int age;
    public String name;
    public static Date time;

    public Student(){}

    public Student(String name){
        this.name = name;
        System.out.println ("name:"+name);
    }

    public Student(String name,int age){
        System.out.println ("name:"+name+","+"age:"+age);
    }

    private Student(int age){
        System.out.println ("age:"+age);
    }
}

package com.Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
        Class<?> c1 = Class.forName ( "com.Reflect.Student" );//代表Student类在内存中的字节码对象
        System.out.println ( c1 );
        System.out.println ( "----------" );
        Constructor<?> cons = c1.getConstructor ( String.class );//得到Student类的构造方法,可以创建对象
        Object obj = cons.newInstance ( "bob" );//创建实例对象
        System.out.println ( obj );

        Class<Student> c2 = Student.class;
        System.out.println ( c2 == c1 );
        Constructor<Student> dc = c2.getDeclaredConstructor ( String.class );
        dc.setAccessible ( true );//暴力反射
        dc.newInstance ( "dvv" );

        System.out.println ("---------------");
        Constructor<?>[] dc2 = c2.getDeclaredConstructors (  );
        for (Constructor con :dc2){
            System.out.println (con);
        }

        System.out.println ("----------");

        Student obj1 = dc.newInstance ( "david" );
        System.out.println (obj1);

        Student s1 = new Student ();
        Class<? extends Student> c3 = s1.getClass ();//
        System.out.println ( c3 == c2 );
    }
}

class com.Reflect.Student
----------
name:bob
com.Reflect.Student@38af3868
true
name:dvv
---------------
private com.Reflect.Student(int)
public com.Reflect.Student(java.lang.String,int)
public com.Reflect.Student(java.lang.String)
public com.Reflect.Student()
----------
name:david
com.Reflect.Student@1218025c
true

4. 获取成员方法并调用

Method[] getMethod():返回所有公共成员方法对象的数组,包括继承的 
Method[] getDeclareMethod():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name,Class<?>...parameter Types):返回单个公共成员方法对象
Method getDeclareMethod(String name,Class<?>...parameter Types):返回单个成员方法对象
Method类中调用成员方法的方法
Object invoke(Object obj,Object...args):调用obj对象的成员方法,参数是args,返回值是Object类型

demo:

package com.Reflect;

import java.util.Date;

public class Student {
    private int age;
    public String name;
    public static Date time;

    public Student(){}

    public Student(String name){
        this.name = name;
        System.out.println ("name:"+name);
    }

    public Student(String name,int age){
        System.out.println ("name:"+name+","+"age:"+age);
    }

    private Student(int age){
        System.out.println ("age:"+age);
    }

    public void m1(){}

    public void m2(String name){
        System.out.println (name );
    }

    public void m3(String name,int age){
        System.out.println (name+":"+age);
    }

    public void m4(Date d){
        System.out.println (d);
    }

    public static void m5(){
        System.out.println ("m5");
    }

    public static void m6(String[] strs){
        System.out.println (strs.length);
    }

    public static void main(String[] args) {
        System.out.println ("main");
    }
}

package com.Reflect;

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

public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> c1 = Class.forName ( "com.Reflect.Student" );
        Object obj = (Student)c1.newInstance ();
        Method m1 = c1.getMethod ( "m1", null );
        m1.invoke ( obj,null );

        Class<Student> c2 = Student.class;
        Student ins = c2.newInstance ();
        Method m2 = c2.getMethod ( "m2", String.class );
        m2.invoke ( ins,"bob" );

        Method m3 = c2.getDeclaredMethod ( "m3",String.class,int.class );
        m3.invoke ( ins,"david",10 );
    }
}

二、注解

2.1 创建注解

定义注解与定义接口有点类似,都用了interface,不过注解前多了@。
此外,包含两个元注解@Target和@Retention,这两个注解专门用于定义注解本身。@Target表示注解的目标,@Override的目标是方法(ElementType.METHOD)。ElementType是一个枚举,主要可选值包含:
在这里插入图片描述

demo

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class InheritDemo {
    @Inherited

    @Retention ( RetentionPolicy.RUNTIME )
    static @interface Test{
    }
    @Test
    static class Base{}
    static class Child extends Base{}

    public static void main(String[] args) {
        System.out.println (Child.class.isAnnotationPresent ( Test.class ));
    }
}
运行结果:
true

2.2 查看注解信息

主要考虑@Retrntion为RetentionPolicy.RUNTIME的注解,利用反射机制在运行时进行查看和利用这些信息

    //获取所有的注解
    public Annotation[] getAnnotations();
    //获取所有本元素上直接声明的注释,忽略inherited来的
    public Annotation[] getDeclaredAnnotations();
    //获取指定类型的注解,没有返回null
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass);
    //判断是否有指定类型的注解
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);

    public interface Annotation{
        boolean equals(Object obj);
        int hashCode();
        String toString();
        //返回真正的注解类型
        Class<?extends Annotation> annotationType();
    }
    
    //对于Method和Contructor,它们都有方法参数,而参数也可以注解,都有方法:
    public Annotation[] getParameterAnnotations();

demo

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

public class MethodAnnotations {
    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    static @interface QueryParam {
        String value();
    }

    @Target(ElementType.PARAMETER)
    @Retention(RetentionPolicy.RUNTIME)
    static @interface DefaultValue {
        String value() default " ";
    }

    public void hello(@QueryParam("action") String action,
                      @QueryParam("sort") @DefaultValue("asc") String sort) {
        //..
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Class<MethodAnnotations> cls = MethodAnnotations.class;
        Method method = cls.getMethod ( "hello", String.class, String.class );
        Annotation[][] annts = method.getParameterAnnotations ();
        for (int i = 0; i < annts.length; i++) {
            System.out.println ( "annotation for parameter" + (i + 1) );
            Annotation[] anntArr = annts[i];
            for (Annotation annt : anntArr) {
                if (annt instanceof QueryParam) {
                    QueryParam qp = (QueryParam) annt;
                    System.out.println ( qp.annotationType ()
                            .getSimpleName () + ":" + qp.value () );
                } else if (annt instanceof DefaultValue) {
                    DefaultValue dv = (DefaultValue) annt;
                    System.out.println ( dv.annotationType ()
                            .getSimpleName () + ":" + dv.value () );
                }
            }
        }
    }
}
//输出结果
annotation for parameter1
QueryParam:action
annotation for parameter2
QueryParam:sort
DefaultValue:asc

https://blog.csdn.net/javazejian/article/details/71860633

三、 类加载

3.1 定义

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过类的加载,类的连接,类的初始化这三个步骤对类进行初始化,如果不出现意外,JVM将会连续完成这三个步骤。

类的加载
就是指将class文件读入内存,并为之创建一个java.lang.Class对象
任何类被使用时,系统都会为之建立一个java.lang.Class对象

3.2 类加载器

作用
负责将.class文件加载到内存中,并为之生成对应的java.lang.Class对象

ClassLoader是负责加载类的对象

demo:

public class ClassLoaderDemo {
    public static void main(String[] args) {
//        static ClassLoader getSystemClassLoader();返回用于委派的类型类加载器
        ClassLoader c = ClassLoader.getSystemClassLoader ();
        System.out.println (c);

//        ClassLoader getParent ();返回父类加载器进行委派
        ClassLoader c1 = c.getParent ();
        System.out.println (c1);

        ClassLoader c2 = c1.getParent ();
        System.out.println (c2);//null

    }
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值