反射、注解笔记

反射

Reflection(反射)是被视为动态语言的关键

  • 反射机制允许程序在执行期获得任何类的内部信息
  • 并能直接操作任意对象的内部属性及方法(操作字节码)。

加载完类之后,在堆内存的方法区中就产生了一个class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射

关于java.lang.Class类的理解

类的加载过程:

  • 程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。
  • 接着我们使用java.exe命令对Class文件进行解释运行。相当于将某个字节码文件加载到内存中,此过程就称为类的加载
  • 加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例

在这里插入图片描述

获取Class

创建Class的四种方式

//方式1  通过运行时类的属性
Class<User> userClass=User.class;
Class s = String.class;

//方式2  通过运行时类的对象,调用 getClass方法
User u=new User();
Class userClass2=u.getClass();


//方式3  通过forName静态方法
Class c1= Class.forName("java.lang.String");
Class userClass3 = Class.forName("com.jie.pojo.User");


//方式4  使用类的加载器 (了解即可)
ClassLoader classLoader=reflectionTest.class.getClassLoader();
Class userClass4=classLoader.loadClass("com.jie.pojo.User");
System.out.println(userClass4);
  • 无论是通过类还是对象创建的Class,都是指向的同一个字节码文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YIfbRfOE-1620218177125)(img\8.png)]

public static void main(String[] args) throws ClassNotFoundException {
    Class s1= Class.forName("java.lang.String");
    Class s2 = "asd".getClass();
    System.out.println(s1==s2);//true
}

实例化对象

使用反射创建对象

Class<Date> dateClass = Date.class;
//反射调用 无参构造函数 创建对象
Date now = dateClass.newInstance();
System.out.println(now);

通过IO流 读取配置文件,创建对象

  • 例如项目中resources(也可以在src目录下)目录下有mybatis.properties文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJYv2X3V-1620218177127)(img\9.png)]

  • 首先需要使用到

    String path = Thread.currentThread().getContextClassLoader()
        .getResource("mybatis.properties")
        .getPath();
    

    path为编译后tartget文件夹的路径

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uXF31g3C-1620218177128)(img\10.png)]

  • 读取文件位置后即可通过反射,实例化对象

  • 优点:适用于寻找各种场景,脱离了idea也能使用

代码

String path = Thread.currentThread().getContextClassLoader()
        .getResource("mybatis.properties")
        .getPath();
System.out.println(path);
FileReader fileReader = new FileReader(path);
Properties properties=new Properties();
//读取
properties.load(fileReader);
//通过反射 实例化对象
Class date = forName(properties.getProperty("class"));
System.out.println(date.newInstance());

第二种简单方法

  • 文件必须在项目的src 或者 resources目录下
  • 必须是**.properties**结尾的文件
//读取文件
ResourceBundle mybatis = ResourceBundle.getBundle("mybatis");
//读取key
String _class = mybatis.getString("class");
Class date = forName(_class);
//实例化对象
System.out.println(date.newInstance());

属性 Field

获取属性

  • java.lang.reflect.Field:代表字节码中的属性字节码
  • 可以通过Class获取属性
  • Filed类即代表一个属性,里面包含这个属性的 权限、类型、名字;

Pojo如下:

public class User  {
    private int id=1;
    boolean isBoy;
    protected int salary;
    public String name="sad";
}

通过Class获取public属性

//获取public属性数组
Field[] fields = userClass.getFields();
System.out.println(fields.length); //1

//获取public属性 某个属性
Field salary = userClass.getField("salary");   //因为 salary不为public  所以error
System.out.println(salary.getName());

获取任何权限的属性

//获取属性数组(不受权限限制)
Field[] fields = userClass.getDeclaredFields();
System.out.println(fields.length); //4
//获取指定的某个属性
Field salary = userClass.getDeclaredField("salary");
System.out.println(salary.getName());

可以通过Field类获取 类名、类型、修饰符

//获取属性的名字
System.out.println(salary.getName());

//获取属性的返回值
Class<?> type = salary.getType();
System.out.println(type.getName());

//获取属性的权限
int modifiers = salary.getModifiers(); //2:private  default:0   4:protected  1:public
//转化成String
System.out.println(Modifier.toString(modifiers));

反编译

通过Class反编译出类的属性结构 (了解即可)

public static void main(String[] args) throws Exception {
    Class<?> c = forName("java.lang.String");
    StringBuilder s=new StringBuilder();
    s.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() + " {\n");
    //获取所有的属性
    Field[] fields = c.getDeclaredFields();
    for(Field f : fields){
        s.append("\t");
        s.append(Modifier.toString(f.getModifiers()));
        s.append(" ");
        s.append(f.getType().getSimpleName());
        s.append(" ");
        s.append(f.getName());
        s.append(";\n");
    }
    s.append("}");
    System.out.println(s);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mmBiNZnr-1620218177129)(img\11.png)]

访问对象的属性

Field salary = userClass.getDeclaredField("name");
//可以给public属性 关键字赋值
salary.set(user,"zcj");
//访问
System.out.println(salary.get(user));
  • 但如果是 除public外的其他的属性,会报错
Field salary = userClass.getDeclaredField("salary");
//打破属性的封装  即可访问类的私有属性
salary.setAccessible(true);
salary.set(user,2000);
System.out.println(salary.get(user));

方法 Method

  • java.lang.reflect.Method:代表字节码中的方法字节码
  • Method类中包含了这个类的修饰符、返回值、名字、参数等

userService类

public class UserService {    
    public boolean login(String name,String password){
        if (name.equals("admin")&&password.equals("123456")){
            System.out.println("登陆成功");
            return true;
        }else{
            System.out.println("登陆失败");
            return false;
        }
    }

    protected void logout(){
        System.out.println("安全退出");
    }
}

获取方法

Class userServiceClass=Class.forName("com.jie.service.UserService");

//获取该类的public方法  (包括类本身和继承的方法)
Method[] methods = userServiceClass.getMethods();

//获取该类的任何属性的 本类方法(不包括继承)
Method[] methods = userServiceClass.getDeclaredMethods();

获取指定放方法

  • 因为方法可以重载,只传入方法名无法获得指定方法
  • 所以还需要传入方法的参数
getMethod //获取public的方法  包括继承的方法
getDeclaredMethod  //获取全部属性的方法  但不包括继承的方法

//获取login方法
Method login = userServiceClass.getMethod("login",String.class,String.class);
//获取logout方法
Method logout = userServiceClass.getDeclaredMethod("logout");

访问属性

//获取方法的访问修饰符
String modifier = Modifier.toString(logout.getModifiers());
//获取返回类型
System.out.println(logout.getReturnType());
//获取方法的参数列表
Class<?>[] parameterTypes = logout.getParameterTypes();
for (Class c:parameterTypes){
    //输出返回值
    System.out.println(c.getSimpleName());
}

调用方法

//获取login方法
Method login = userServiceClass.getMethod("login",String.class,String.class);
//创建对象
Object o = userServiceClass.newInstance();
//利用反射 调用方法
login.invoke(o,"admin","123456");
  • 调用有参数的方法,需要传参

构造方法 Constructor

  • java.lang.reflect.Constructor:代表字节码中的构造方法字节码
  • 需要根据传入的参数,确定获取哪个构造函数
Class userClass = User.class;
//直接调用无参构造函数
Object user = userClass.newInstance();


//获取无参构造方法
Constructor constructor = userClass.getDeclaredConstructor();
Object o = constructor.newInstance();

//获取有参构造方法
Constructor constructor2 = userClass.getDeclaredConstructor(int.class, String.class);
Object o2 = constructor2.newInstance(1,"asd");

获取接口

//获取接口
Class[] interfaces = userClass.getInterfaces();
for (Class c:interfaces){
    System.out.println(c);
}

方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6RFd7q8j-1620218177132)(img\7.png)]

//创建运行时类
Class user_class= User.class;

//调用指定构造函数
Constructor constructor = user_class.getConstructor(int.class, String.class);
 User u= (User)constructor.newInstance(1,"zcj");

//获取无参构造函数
User u= userClass.newInstance();

//通过反射私有属性
Field id = user_class.getDeclaredField("id");
id.setAccessible(true);//通过暴力访问 取消的私有权限的限制
id.set(u,2);
System.out.println(u);

//获取指定方法
Method hello=user_class.getDeclaredMethod("hello");
hello.invoke(u); //运行

//调用私有方法
Method show=user_class.getDeclaredMethod("show", String.class);
show.setAccessible(true);
String a = (String) show.invoke(u, "我的id:");  //相当于u.show("我的id")



//获取全部方法 
Method[] methods = user_class.getMethods()
    
//获取共有方法
Field[] declaredFields = user_class.getDeclaredFields();



pojo测试代码

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;

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

    private String show(String s){
        return s+id;
    }

}

测试

@Test
public void test1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
    Class user_class= User.class;

    //通过反射创建对象
    Constructor constructor = user_class.getConstructor(int.class, String.class);
    User u= (User)constructor.newInstance(1,"zcj");
    System.out.println(u);

    //通过反射私有属性
    Field id = user_class.getDeclaredField("id");
    //通过暴力访问 取消的私有权限的限制
    id.setAccessible(true);
    id.set(u,2);
    System.out.println(u);

    //通过反射调用方法
    Method hello=user_class.getDeclaredMethod("hello");
    hello.invoke(u);

    //调用私有方法
    Method show=user_class.getDeclaredMethod("show", String.class);
    show.setAccessible(true);
    String a = (String) show.invoke(u, "我的id:");  //相当于u.show("我的id")
    System.out.println(a);

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JXv4hCBJ-1620218177133)(img\2.png)]

注解

元注解

  • 负责修饰注解

注解包含一下内容

  • @Target :表示注解的使用范围
  • @Retention :描述注解的生命周期Source<Class<Runtime
    • Source:表示该注解只被保存与java文件中
    • Class:表示该注解能被保存与 class文件
    • Runtime:表示该注解能被保存class文件中,并且被java反射读取
  • @Documented : 说明该注解被包含在javadoc中
  • @Inherited : 说明子类可以继承父类的该注解

元注解使用

//表示可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})  //表明该注解可以用在方法以及类上
//描述注解的生命周期(Source<class<Runtime)
@Retention(value = RetentionPolicy.RUNTIME)
//@Documented 生成在javadoc中
@Documented()
//@Inherited : 说明子类可以继承父类的该注解
@Inherited()
public @interface test {
    
}

注解内属性

  • 可以在注解中定义属性
  • 包括数组等
  • 当属性有且仅有一个value时, 赋值时可以忽略value的书写
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "Hello";
    String name();
    int []count();
}

JDK注解

  • @Override
    • 用于重写父类的方法 或者是写接口实现类时用到该注解。
  • @Deprecated
    • 用于表示该方法是一个过期的方法。
  • @suppressWarnings
    • 表示该方法在编译时自动忽略警告

获取注解信息

@Target({TYPE,METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default "Hello";
    String name();
    int []count();
}

如果注解在类上

Class<User> userClass = User.class;
//判断这个class上有没有这个注解
boolean annotationPresent = userClass.isAnnotationPresent(MyAnnotation.class);

if (userClass.isAnnotationPresent(MyAnnotation.class)){
    //获取类上的注解
    MyAnnotation myAnnotation = userClass.getAnnotation(MyAnnotation.class);
    //输出信息
    String value = myAnnotation.value();
    System.out.println(value);
    System.out.println(myAnnotation.name());
}

注解在方法上

@MyAnnotation(name = "zcj2",count = 1)
private void show(){
    
}
Class<User> userClass = User.class;
//首先需要获得方法
Method show = userClass.getDeclaredMethod("show");
//判断
if (show.isAnnotationPresent(MyAnnotation.class)){
    //得到注解
    MyAnnotation myAnnotation = show.getAnnotation(MyAnnotation.class);
    //输出信息
    String value = myAnnotation.value();
    System.out.println(value);
    System.out.println(myAnnotation.name());
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值