反射

反射

Java反射机制:是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制,很多优秀的开源框架都是通过反射完成的。

获取Class对象:

  • 第一种通过类名.Class,例如:Class cl=User.Class;
  • 第二种通过对象名.getClass,例如 User u=new User(); Class cl=u.getClass();
  • 第三种通过Class.forName()方式,例如Class cl=Class.forName(com.shsxt.Demo.User);

反射中获取修饰符的方法-------getModifiers()

 //获取Class对象
 //com.ysh.demo.pratise12.User表示哪个包下哪个类
 Class cl=Class.forName("com.ysh.demo.pratise12.User");
 //获取属性名为name的属性
 Field field=cl.getDeclaredField("name"); 
//获取修饰符
int n=field.getModifiers();
//将获取到的修饰符转为字符串
System.out.println(Modifier.toString());

通过构造器来创建一个类的对象

package com.ysh.demo.review08;
import java.lang.reflect.*;
public class ClassTest01 {
    public static void main(String[] args) throws Exception{
        //获取Class对象
        //com.ysh.demo.pratise12.User表示哪个包下哪个类
        Class<User> cl=User.class;
        //指定构造函数
        //调用带有一个参数且参数类型为int型的构造函数
        Constructor cons1=cl.getConstructor(int.class);
        User user1=(User)cons1.newInstance(1);
        System.out.println(user1);
        //调用带有两个参数且参数类型顺序为(String,int)的构造函数
        Constructor cons2=cl.getConstructor(String.class,int.class);
        //调用哪个构造函数必须在newInstance()方法中传入相对应的实参
        User user2=(User)cons2.newInstance("yang",19);
        System.out.println(user2);
    }
}
class User {
    private String name;
    private String id;
    private int age;
    public User(){

    }


    public User(String name) {
        this.name = name;
    }

    public User(int age) {
        this.age = age;
    }

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

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

    public String getName() {
        return name;
    }

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

    public String getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    private void test1(){
        System.out.println("hello");
    }
    private static void test2(){
        System.out.println("world");
    }
    public static void test3(){
        System.out.println("hello1");
    }

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

通过反射来获取一个类的属性

package com.ysh.demo.review08.one;

import java.lang.reflect.Field;

public class ClassTest02 {
    public static void main(String[] args) throws Exception {
        //构建Class对象
        Class<User> cl=User.class;
        //获取属性数组
        Field[] field=cl.getDeclaredFields();
        //获取指定属性名的属性,在这里我指定了名为name的属性
        Field field1=cl.getDeclaredField("name");
        User user=cl.getConstructor(String.class,String.class,int.class).newInstance("yang","123",12);
        //增强for遍历存储属性名的数组
        for (Field f:field){
            System.out.println(f);
        }
        //修改属性的值
        field1.set(user,"灰太狼");
        //获取属性的值
        field1.get(user);
         //获取属性名
        System.out.println(field1.getName());
        //获取属性的修饰符   Modifier.toString()是将字符变为字符串
        System.out.println(Modifier.toString(field1.getModifiers()));
    }
}
class User {
    private String name;
    private String id;
    private int age;
    public User(){

    }


    public User(String name) {
        this.name = name;
    }

    public User(int age) {
        this.age = age;
    }

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

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

    public String getName() {
        return name;
    }

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

    public String getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    private void test1(){
        System.out.println("hello");
    }
    private static void test2(){
        System.out.println("world");
    }
    public static void test3(){
        System.out.println("hello1");
    }

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

数组在反射中的应用(借助Array)

package com.ysh.demo.review08;

import java.lang.reflect.Array;

public class ArrayClassTest02 {
    public static void main(String[] args) {
        //创建一个数组,并给数组赋予长度
        Object obj=Array.newInstance(String.class,10);
        //判断是否是数组
        if(obj.getClass().isArray()){
            //输出数组的长度
            System.out.println(Array.getLength(obj));
        }
        Array.set(obj,0,"红太狼");
        System.out.println(Array.get(obj, 0));
    }
}

注解

注解的分类

  • 标记注解:一个没有成员定义的Annotation类型被称为标记注解;
  • 单值注解:只有一个值
  • 完整注解:拥有多个值

根据注解使用方法和用途分类:

  • JDK内置系统注解
  • 元注解
  • 自定义注解

内置注解

@Override:限定重写父类方法,若想要重写父类的一个方法时,需 要使用该注解告知编译器我们正在重写一个方法。如此 一来,当父类的方法被删除或修改了,编译器会提示错 误信息;或者该方法不是重写也会提示错误。

@Deprecated:标记已过时,当我们想要让编译器知道一个方法已经被 弃用(deprecate)时,应该使用这个注解。

@SuppressWarnings:抑制编译器警告,该注解仅仅告知编译器,忽略它们产 生了特殊警告。

元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4 个标准的meta-annotation类型,它们被用来提供对其 它 annotation类型作说明。Java5.0定义的元注解有四个,这些类型和它们所支持的类在java.lang.annotation 包中可以找到。

元注解—@Target:

用于描述注解的使用范围(即:被描述的注解可以用在 什么地方)。表示支持注解的程序元素的种类,一些可能的值有TYPE, METHOD(方法), CONSTRUCTOR, FIELD(属性)等等。如 果Target元注解不存在,那么该注解就可以使用在任何 程序元素之上。

元注解—@Retention:

表示需要在什么级别保存该注释信息,用于描述注解的 生命周期(即:被描述的注解在什么范围内有效)表示 注解类型保留时间的长短。取值(RetentionPoicy)有:

  • SOURCE:在源文件中有效(即源文件保留)
  • CLASS:在class文件中有效(即class保留)
  • RUNTIME:在运行时有效(即运行时保留)
元注解—@Document

表示使用该注解的元素应被javadoc或类似工具文档化, 它应用于类型声明,类型声明的注解会影响客户端对注 解元素的使用。如果一个类型声明添加了Documented注 解,那么它的注解会成为被注解元素的公共API的一部 分,@Documented是一个标记注解。

元注解—@Inherited:

表示一个注解类型会被自动继承,如果用户在类声明的 时候查询注解类型,同时类声明中也没有这个类型的注 解,那么注解类型会自动查询该类的父类,这个过程将 会不停地重复,直到该类型的注解被找到为止,或是到 达类结构的顶层(Object)。

自定义注解

@interface::用来声明一个注解。注解类里的每一个方法 实际上是声明了一个配置参数。方法的名称就是参数的 名称,返回值类型就是参数的类型。可以通过default来 声明参数的默认值。

自定义注解的格式:

@interface用来声明一个注解,其中的每一个方法实际上 是声明了一个配置参数。方法的名称就是参数的名称, 返回值类型就是参数的类型(返回值类型只能是基本类 型、Class、String、enum)。可以通过default来声明参 数的默认值。

注解参数注意事项

  • 修饰符:只能用public或默认(defalut)这两个访问权限修饰符,默认为defalut;
  • 注解中的方法的返回值,作为注解参数,只支持以下数据类型:
    • 基本数据类型 (int,float,boolean,byte,double,char,long,shor t);
    • String类型;
    • Class类型;
    • enum类型;
    • Annotation类型;
    • 以及 以上所有类型的数组

参数:注解中的方法不能存在参数

默认值:可以包含默认值,使用defalut来声明默认值

代码实例:

自定义注解代码:
package com.ysh.demo.pratise12;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Idertified {
    int value() default 0;
    String name() default "null";

}

对自定义注解的基本使用:
package com.ysh.demo.pratise12;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class AnnotationTest {
    @Idertified
    static int age;
    @Idertified
    String name;
    int id;

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

    //
    @Idertified(value = 1)
    public static void test1(int a){
        System.out.println("hello");
    }
    @Idertified(value = 0)
    public static void test2(){
        System.out.println("world");
    }

    public static void main(String[] args) throws Exception {
        //获取Class对象,因为Class是一切的源头
        //根据哪个类需要反射,构建其Class对象
        Class<AnnotationTest> an=AnnotationTest.class;
        //实例化AnnotationTest对象
        AnnotationTest a=an.getConstructor().newInstance();
        //获取指定的方法,并且传入向对应的参数Class<?>... parameterTypes
        Method method4 = an.getDeclaredMethod("test1", int.class);
        //获取所有的方法将所有的方法存储在一个数组中
        Method []methods = an.getDeclaredMethods();
        //增强for遍历
        for (Method method:methods){
            System.out.println(method);
            //判断方法是否含有Idertified的注解
            if (method.isAnnotationPresent(Idertified.class)){
                //得到该方法上的注释内容,即得到注释接口对象
                Idertified id=method.getDeclaredAnnotation(Idertified.class);
                //通过对象获得对应属性的属性值
                int num = id.value();
                System.out.println(num);
                if (num==0){
                    /*
                      第一种方法:通过对象调用方法
                     */
                    method.invoke(a);
                    /*
                      第二种方法:通过类调用静态方法
                      即:method.invoke(null)
                     */
                }
            }

        }

        //获取属性数组
        Field[] field = an.getDeclaredFields();
        for (Field f:field){
            //对属性数组进行筛选,即将有注解的属性筛选出来
            if (f.isAnnotationPresent(Idertified.class)){
                //如果属性是String类型的,即给该属性赋值
                if (f.getType()==String.class){
                    f.set(a,"你真的很帅");
                }
                //如果属性是int类型,即给该属性赋值
                if (f.getType()==int.class){
                    f.set(null,1);
                }
                System.out.println(a.toString());
            }
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值