Java——反射及注解

反射:框架设计的灵魂



概念

将类的各个组成部分封装为其他对象。

优点

1.可以在程序运行过程中,操作Class对象
2.可以解耦,提高程序的可扩展性

获取Class对象的方式

/*
            获取Class对象的三种方式
            1.Class.forName("全类名");
            2.类名.class;
            3.对象名.getClass();
         */
        //1.Class.forName()
        Class cls1 = Class.forName("包名.类名");
        
        //2.类名.class
        Class cls2 = Person.class;
        
        //3.对象名.getClass()
        Person p = new Person();
        Class cls3 = p.getClass();

tips:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的对象都是同一个。


Class对象功能

1.获取成员变量

Field:成员变量
	操作: 
		1.设置值
			void set(Object obj , Object value)
		2.获取值
			get(Object obj)
		3.忽略访问权限修饰符的安全检查(暴力反射)
			setAccessible(true)
public static void main(String[] args) throws Exception {

        //获取public修饰的成员变量
        getField();
        
        System.out.println("-----------------------------------------");
        
        //获取所有成员变量
        getDeclaredField();
    }

    /**
     * 1.1 获取所有public修饰的成员变量
     *         对象名.getFields();
     *         对象名.getField(变量名);
     */
    public static void getField() throws Exception {
        Person p = new Person();
        //获取类对象
        Class personClass = Person.class;

        // (1)--getFields()
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        // (2)--getField
        Field a = personClass.getField("a");
        //获取public修饰的成员变量的值
        Object value = a.get(p);
        System.out.println(value);//null
        a.set(p,"迪丽热巴");
        System.out.println(p);//Person{name='null', age=0, a='迪丽热巴', b='null', c='null'}
    }

    /**
     * 1.2 获取所有成员变量
     *        对象名.getDeclaredFields();
     *        对象名.getDeclaredField(变量名);
     */
    public static void getDeclaredField() throws Exception {
        Person p = new Person();
        //获取类对象
        Class personClass = Person.class;

        // (1)--getDeclaredFields()
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
        // (2)--getDeclaredField()
        Field name = personClass.getDeclaredField("name");
        //忽略访问权限修饰的安全检查(暴力反射)
        name.setAccessible(true);
        //然后给非public修的变量设值
        name.set(p,"佟丽娅");
        Object value = name.get(p);
        System.out.println(value);
    }

Person类

public class Person {

    private String name;
    private int age;
    public String a;
    protected String b;
    String c;

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

    public Person() {
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                ", c='" + c + '\'' +
                '}';
    }
    
	public void play(String game) {
        System.out.println("我想打" + game);
    }

	public void play() {
		System.out.pringln("play...");
	}
}

2.获取构造方法

Constructor:构造方法
	创建对象
		T newInstance(Object... initargs)
    public static void getConstructor() throws Exception {
        //获取类对象
        Class personClass = Person.class;

        //获取无参构造方法
        Constructor constructor1 = personClass.getConstructor();
        System.out.println(constructor1);
        //获取有参构造方法
        Constructor constructor2 = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor2);

        //创建对象
        //通过构造方法
        Object person1 = constructor1.newInstance();
        System.out.println(person1);
    }

3.获取成员方法

Method:方法对象
	执行方法:
		Object invoke(Object obj , Object...args)
	获取方法名称:
		String getName();
/*
	获取public修饰的成员方法
	若想获取全部成员方法,使用getDeclaredMethod();(同1.获取成员变量)
*/
public static void getMethod() throws Exception {
        Person p =new Person();
        //获取类对象
        Class personClass = Person.class;

        //1.获取指定成员方法
        Method methodPlay = personClass.getMethod("play", String.class);
        //执行方法并传参
        methodPlay.invoke(p,"cod16");

        //2.获取全部public修饰的成员方法(包含父类中方法)
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            //获取成员方法名称
            String name = method.getName();
            System.out.println(name);
            System.out.println(method);
        }
    }

4.获取类名

public static void getClassName() {
	//获取类对象
	Class personClass = Person.class;

	//获取类名
	String className = personClass.getName;
	System.out.println(className);
}

案例

需求:写一个反射类,在不改变该类的任何代码的前提下,可以帮我们创建该类的对象并执行其中的任意方法
	步骤:
		1.将需要创建对象的全类名和需要执行的方法定义在配置文件中
		2.在程序中加载读取配置文件
		3.使用反射来加载类文件进内存
		4.创建对象
		5.执行方法
public static void main(String[] args) throws Exception {
        //1.加载配置文件
        //1.1创建Properties对象(把硬盘中存储的文件读取到集合中使用)
        Properties prop = new Properties();//Properties是HashTable的子类
        //1.2获取配置文件
        ClassLoader classLoader = ReflectTest.class.getClassLoader();//通过类对象获取类加载器()
        InputStream resource = classLoader.getResourceAsStream("prop.properties");//类加载器找到配置文件返回IO流
        //1.3加载配置文件
        prop.load(resource);

        //2.获取配置文件中定义的数据
        String className = prop.getProperty("className");
        String methodName = prop.getProperty("methodName");

        //3.获取类对象
        Class cls = Class.forName(className);

        //4.创建对象
        Object obj = cls.getDeclaredConstructor().newInstance();
        //5.获取方法对象
        Method method = cls.getMethod(methodName);
        //6.执行方法
        method.invoke(obj);
    }

配置文件(prop.properties)

tips:路径在src/main/resources下,不然找不到
className=包名.Person
methodName=play


注解

注解:说明程序的,给计算机看的。
注释:用文字描述程序的,给人看的。

定义

注解(Annotation),也叫元数据,一种代码级别的说明。
是JDk1.5引入的新特性。

作用分类

1.编写文档:通过代码里标识的注解生成doc文档
2.代码分析:通过代码里标识的注解对代码进行解析(使用反射)
3.编译检查:通过代码里标识的注解让编译器能够实现基本的代码检查(Override)

JDK中预定义的注解

1.@Override
2.@Deprecated:代表已过时
3.@SuppressWarnings:压制警告

自定义注解

格式与本质

//格式
public @interface MyAnno {}
//注解本质上就是接口
publi interface MyAnno extends java.lang.annotation.Annotation {}

反编译

元注解

用于描述注解的注解
	@Target:描述注解能够作用的位置
	@Retention:描述注解被保留的阶段(source、class、runtime)
	@Docemented:描述注解是否被抽取到api文档中
	@Inherited:描述注解是否被子类继承
@Target(ElementType.TYPE)//作用于类上
@Retention(RetentionPolicy.RUNTIME)//被描述的注解,会被保留到class字节码文件中,并被JVM读取到
public @interface MyAnno {
}

@Target(ElementType.METHOD)//作用于方法上
@Retention(RetentionPolicy.CLASS)//作用到字节码阶段
public @interface MyAnno {
}

@Target(ElementType.FIELD)//作用于成员变量上
@Retention(RetentionPolicy.SOURCE)//作用于源码阶段
public @interface MyAnno {
}

案例

使用注解完成上面反射篇中的案例

Prop.java

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Prop {

    String className();
    String methodName();

}

主方法

@Prop(className = "cn.annotation.Student",methodName = "sleep")
public class ReflectTest {

    public static void main(String[] args) throws Exception {
        //1.解析注解
        //1.1获取注解(接口)的实现类对象
        Prop prop = ReflectTest.class.getAnnotation(Prop.class);
        //1.2通过实现类对象获取返回的数据
        String className = prop.className();
        String methodName = prop.methodName();

        //同reflect\ReflectTest.java
        //2.获取类对象
        Class<?> cls = Class.forName(className);
        //3.创建对象
        Object obj = cls.getDeclaredConstructor().newInstance();
        //4.获取方法对象
        Method method = cls.getMethod(methodName);
        //5.执行方法
        method.invoke(obj);
    }

}

学生类

public class Student {

    public void sleep() {
        System.out.println("早睡早起身体倍儿棒~");
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值