反射与注解

反射

通过某种机制,动态得到这个类的所有信息(属性,方法,构造方法),也可以动态的调用这个类所有的属性,方法,构造方法... 这种机制就是所谓的反射

反射的核心:类的镜子,类的字节码文件 对应的类:Class类

每一个类,它的Class类的对象,唯一一个,类的Class对象, 在这个类的字节码文件加载到内存时候,JVM就会为该类的字节码文件创建一个Class对象

与new对象不同

不确定的类、不确定的对象创建 在框架底层 使用反射

反射的使用

创建对象

  1. 得到某个类的Class对象

    1) 类名.class()

    Class<Student> clazz = Student.class; 

    2) 类的对象.getClass()

    Student stu = new Student();
    Class<? extends Student> clazz2 = stu.getClass();//Student本类 子类 上界  ?泛型通配符

    3)通过Class类的static方法:forName(类的全限定名:包名.类名)

    Class<?> clazz3 = Class.forName("com.fs.Student");

  2. 从这个Class对象获取某个类所有的属性,方法,构造方法

  3. 通过Class对象,调用属性,方法

    创建这个对象,类名是可变的String 如"Student","Dog"

    new Student() 不可变 固定

获取构造方法

方法,构造方法,属性,参数都可以看作是一个个对象

getConstructor() getConstructors()

<init>(int) 表示的构造方法

// NoSuchMethodException异常: 没有匹配的方法的异常

Constructor[] constructors = clazz.getConstructors(); //只能得到公开的构造方法 
​
Constructor c1 = clazz.getDeclaredConstructor(int.class,String.class);//得到所有的 不管是公开还是私有

指定参数类型的构造方法

.getModifiers() 得到访问修饰符 返回值int 0. 缺省的 1. public 2. private 4. protected

用构造方法创建对象 new 构造方法() 创建对象

反射方式创建对象:

1)通过Class类的newInstance(),底层调用本类的无参构造方法

  Student stu =  clazz.newInstance();   // new Student()

2)通过构造方法对象的Constructor类newInstance(Object obj)

Constructor<Student> c = clazz.getDeclaredConstructor(int.class);
c.Accessble(true);//如果调用的类的private修饰的属性无法访问,设置允许访问
Student stu = c.newInstance();

获取属性

Field

//获得所有的public修饰的属性(继承自父类的属性也能获得),private修饰的属性不能获得
Field [] fs = cls.getFields();
​
Field [] fs = cls.getDeclaredFields(); // 获得本类所有的属性
for(int i=0;i<fs.length;i++){
    System.out.println(fs[i]);
}
​
//获得指定的属性
Field f = cls.getDeclaredField("mastername");
//mastername属性为私有的,所以要先解除封装
f.setAccessible(true);
​
​
//修改指定的属性
Field f = cls.getDeclaredField("mastername");
f.setAccessible(true);
f.set(obj, "lisi");
System.out.println(f.get(obj));

获取方法

//获得所有的方法,包括继承自父类的方法,但只能是public 修饰的方法
Method[] ms =  cls.getMethods();
​
//获得本类所有的方法,不包括继承自父类的方法,但private 修饰的方法也能获得
Method[] ms =  cls.getDeclaredMethods();
​
noSuchMethodException 找不到方法异常
​
//方法的执行
//通过invoke调用方法,obj表示在哪个对象里调用方法,后续的参数都是方法的传入的参数
//invoke返回值:如果方法为void 返回值为null
String str = (String) ms.invoke(obj, "测试有参方法");
System.out.println("方法执行的结果:"+str);
​
I

getName() //获取全限定名 包名 +类名
getSimpleName() // 只得到类名

注解

// /** */ /**/ 注释:便于阅读代码,对代码的描述

注解(Annotation):对代码的描述,作为代码的形式保留

Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

注释类似于商品的标签,描述商品;注解类似于商品的条形码,方便后期结算。

注解的作用

  1. 生成文档

  2. 实现代替配置文件功能

  3. 在编译时进行格式检查 如 @Override 重写 方法名和参数必须相同

注解的本质:特殊的接口

声明注解:创建了一个特殊接口

使用注解: @注解名 (创建注解的一个对象)

注解的分类

内置注解

jdk提供的这个注解的声明,开发者直接使用

@Override检查重写

@Deprecated 标记这个方法已过时

@SupperssWarnings抑制生成警告信息

1900~1999 计算机元年 1970年

元注解

使用元注解,对自定义的注解进行声明,限制使用区域

1.@Documented-注解是否将包含在JavaDoc中

2.@Retention–什么时候使用该注解 Retention 保留期 存活时间

        自定义注解一定设置为runtime

RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

RetentionPolicy.SOURCE注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。

RetentionPolicy.CLASS注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。

3. @Target–注解用于什么地方 如果没有写,表示这个注解可以在任意地方使用

注解可以使用在 类、方法、属性 上

给注解的参数赋值

如果给注解定义的参数是数组类型,给数组类型赋值

赋一个值@Target(value = {ElementType.TYPE})描述类、接口或enum声明

赋多个值 @Target(value = {ElementType.TYPE,ElementType.METHOD})描述类、接口或enum声明和方法

4.@Inherited– 定义该注释和子类的关系 Inherited 继承 子类可以继承父类的注解

自定义注解

声明注解的语法:@interface 默认继承Annotation

参数成员访问修饰符只能为默认default或public 方法返回值

@Target(ElementType.FIELD)//可以用来修饰对象,属性
@Retention(RetentionPolicy.RUNTIME)//什么时候都不丢弃
@Documented//用于生成javadoc文档
public @interface 注解名{
    //成员:常量 
    //String value() defualt ="zhangsan"; 给参数赋值就是给方法的返回值
    String value();
    //如果没有设置default默认值,使用这个注解时一定要给参数赋值
    //如果设置了default,可以在使用时改变默认值
    //参数数据类型:八大数据类型,String,枚举,Class,注解类型,数组类型(12种)
    
}

通过接口自动生成Annotation的实现类

自定义注解,可以有参数,也可以没有。没有参数这个注解没有意义

必须代码解析注解它的功能,获取该注解的对象,只能使用反射来获取

创建一个类,在类中应用自定义的注解:

package AnnotationExample;
//商品类
public class Good {
    @Role("管理员")
    public void shangjia(){
        System.out.println("商品正在上架");
    }
    @Role("管理员")
    public void xiajia(){
        System.out.println("商品正在下架");
    }
    public void show(){
        System.out.println("商品正在展示");
    }
    @Role("顾客")
    public void buy(){
        System.out.println("商品正在购买");
    }
}

创建一个注解:

package AnnotationExample;
​
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
​
//角色的注解
//如果参数名为value 在注解上 单独给这个value参数赋值 省略 value=
//如果给多个参数赋值,不能省略
@Target(ElementType.METHOD) //只能在方法上面使用
@Retention(RetentionPolicy.RUNTIME)//运行时
public @interface Role {
  //  String role();//权限 管理员 顾客
    String value();
//String value() default "";
}

创建一个工具类用来处理注解:


​
package AnnotationExample;
​
import java.lang.reflect.Method;
import java.util.Scanner;
​
public class TestGood {
    public static void main(String[] args) throws Exception {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入您的角色");
        String role = input.next();
        System.out.println("请输入您要调用的方法");
        String methodName = input.next();
        Good good = new Good();
        //调用方法前 判断角色与方法上定义的角色是否匹配
        //如果不匹配,禁止访问
        //通过反射
        // 1、获取Good的Class
        Class<Good> clazz = Good.class;
        //2.获取指定方法名的对象
        Method method = clazz.getDeclaredMethod(methodName);
        //获取这个方法上需要的角色
​
        if (method.isAnnotationPresent(Role.class)){  //判断是否有@Role这个注解
            //获取方法上的注解对象
            Role annotation = method.getAnnotation(Role.class);
            //获取方法上的value参数
            String value = annotation.value();
            if (role.equals(value)){//判断是否匹配
                System.out.println("您有权限");
                method.invoke(good); //调用方法
            }else{
                System.out.println("您没有权限");
            }
        }else {//没有 直接执行
            System.out.println("没有这个注解");
        }
​
​
​
​
    }
}

补 记忆版

内置注解:Java已经提供的注解,叫做内置注解。

注解名称    注解作用
@Override 用于重写方法上面,可以避免子类重写方法时出错。
@Deprecated    标识某个方法已经过时了,后续不推荐使用该方法(但是可以使用,只是不建议)。
@SuppressWarnings   告诉编译器忽略指定的警告信息(这样代码里面就看不见那些黄色波浪线了)。
@FunctionalInterface  标记某个接口是函数式接口(Jdk1.8新增)。

元注解:用于对其他注解进行解释说明的,一般用于创建自定义注解时候,声明自定义注解的一些信息,例如:注解作用范围、注解能够保存到哪个阶段,注解是否需要包含到用户文档里面等等。

注解名称注解作用
@Documented标着这个注解是否包含在用户文档中(即:javadoc文档里面)。
@Target  标记这个注解能够作用在哪些成员上面,例如:类上面、属性上面、方法上面等等。
@Retention 标记这个注解能够保存到哪个阶段,有三个可选值:源码阶段、字节码阶段、运行阶段。
@Inherited  标记某个注解是继承自哪个注解类(注解默认是不继承任何类的)。

    
    
 
  
 
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值