Java SE:反射超详解(三)

简介: Java SE:反射超详解(三)

6.2.2 方案二

步骤:

(1) 先获取这个类的CLass对象

(2) 先获取有参构造器对象

(3) 调用构造器对象的newInstance()方法来创建实例对象

代码演示如下:

public class testDemo {
    private String name;
    private int id;
    public testDemo(String name, int id) {
        this.name = name;
        this.id = id;
    }
    @Override
    public String toString() {
        return "testDemo{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}
Class c3=Class.forName("testP1.testDemo");
Constructor construct = c3.getDeclaredConstructor(String.class,int.class);
Object o1 = construct.newInstance("jack",12);
System.out.println(o1);

🔔如果构造器是非公共的,那么需要调用 构造器对象的setAccessible(true)

🚩结论:

为了后期很多的框架可以为你的类自动创建的对象更方便,请保留你这个类公共的无参构造。

6.3 动态的操作任意对象的任意属性

步骤:

(1) 获取类的CLass对象

(2) 通过CLass对象newInstance()

🔔前提条件是这个类有公共的无参构造

(3) 先获取id属性的Field对象

(4) 可选的,如果属性的权限修饰符允许,这一步可以不要

如果属性的权限修饰符不允许,可以加这步通过id属性对应的Field对象.setAccessible(true)

(5)操作id居性的值通过id属性对应的Field对象.get(实例对象)获取id属性的值通过id属性对应的Field对象.set(实例对象,值)设置id属性的值

代码演示如下:

package testP1;
public class Student {
    private String name;
    private int id;
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}

@Test
public void test02() throws Exception{
    //通过反射创建Student类的对象,通过反射给student类的对象的id和name属性赋值,并通过反射获取它们的值
    Class<?> aClass = Class.forName("testP1.Student");//获取模块Testmodule下的testP1.Student类的class对象
    Object stud = aClass.newInstance();//获取Student类的实例对象
    Field idField = aClass.getDeclaredField("id");//获取id属性的Field对象
    idField.setAccessible(true);//将Student类id属性的权限修饰符设为允许访问,之前是private,不允许访问
    System.out.println(idField.get(stud));//获取id属性的值  ==>  stud.id
    idField.set(stud,2);//给stud的id属性赋值  ==>  stud.id=2;
    System.out.println(idField.get(stud));
    System.out.println("----------------------------------");
    //给stud的name属性赋值
    Field nameField = aClass.getDeclaredField("name");//获取name属性的Field对象
    nameField.setAccessible(true);
    System.out.println(nameField.get(stud));
    nameField.set(stud,"张三");
    System.out.println(nameField.get(stud));
    System.out.println(stud);
}

6.4 在运行时动态的调用任意类的任意方法

步骤:

(1) 获取CLass对象

(2) 创建这个类的实例对象

🔔前提条件是这个类有公共的无参构造

(3) 先获取你要调用的方法的Method对象

(4) 调用方法

通过Method对象.invoke(实例对象,实参)

代码演示如下:

public class testMain {
    public int doubleValue(int a){
        return a*2;
    }
    public long doubleValue(long a){
        return a*2;
    }
}
@Test
public void test03() throws Exception{
    Class<?> aClass = Class.forName("testP1.testMain");//获取class对象
    Object testMain = aClass.newInstance();//获取testP1.testMain类的实例对象
    Method doubleValueMethod = aClass.getDeclaredMethod("doubleValue", int.class);
    /*
    如何唯一的确定某个类的方法?
    (1) 类: 通过cLazz对象确定是testMain类
    (2) 方法名: doubleValue
    (3) 形参列表:因为有可能doubleValue会有重载
    */
    Object returnValue = doubleValueMethod.invoke(testMain, 10);//获取返回值
    System.out.println(returnValue);
}
 @Test
    public void test04() throws Exception{
        Class<?> aClass = Class.forName("testP1.testMain");//获取class对象
        Object testMain = aClass.newInstance();//获取testP1.testMain类的实例对象
        Method doubleValueMethod = aClass.getDeclaredMethod("doubleValue", long.class);
        System.out.println(doubleValueMethod.invoke(testMain,20));
    }

6.5 通过反射操作某个类的静态变量和静态方法

🤮反射操作某个类的静态方法

步骤:

(1) 获取CLass对象

(2) 先获取你要调用的方法的Method对象

(3) 调用方法

通过Method对象.invoke(实例对象,实参)

🤮反射操作静态变量的步骥

(1) 获取CLass对象

(2)获取要换作/访问的静态变量的Field对象

(3)某个静态变量对应的FieLd对象.setAccessible(true);

(4)可以访问静态变量的值,或者给静态变量赋值某个静态变量对应的Field对象.get(null)就是获取静态变量的值某个静态变量对应的Field对象.set(null,值)就是设置静态变量的值

代码演示如下:

public class testMain {
    static int b=1;
    public static void getInfo(String info){
        System.out.println("testMain.method");
        System.out.println("info:"+info);
    }
    public int doubleValue(int a){
        return a*2;
    }
    public long doubleValue(long a){
        return a*2;
    }
}
@Test
public void test05() throws Exception{
    //通过反射调用testP1.testMain类的静态方法
    Class<?> aClass = Class.forName("testP1.testMain");//获取class对象
    Method getInfo = aClass.getDeclaredMethod("getInfo", String.class);
    getInfo.invoke(null,"java");//null 表示这里不需要testP1.testMain类的对象,它是静态方法;Java相当于getInfo方法的实参
    System.out.println("---------------------------------");
    //通过反射调用testP1.testMain类的静态变量
    Field bField = aClass.getDeclaredField("b");
    bField.setAccessible(true);
    System.out.println(bField.get(null));//null 表示这里不需要testP1.testMain类的对象,它是静态变量
    bField.set(null,10);
    System.out.println(bField.get(null));//null 表示这里不需要testP1.testMain类的对象,它是静态变量
}


七. 自定义注解与反射

7.1 注解

@Override: 标记某个重写的方法

@Deprecated: 标记某个类、方法已过时

@SuppressWarnings: 抑制警告

@Test: JUnit测试的标记

7.2 自定义注解

语法格式:

[修饰符] @interface 注解名 {

}

7.3 如何使用自定义注解

可以在类、方法、成员变量等上面加注解

7.4 自定义注解包含三个部分

7.4.1 声明

public @interface MyAnnotation {
}

7.4.2 使用

@MyAnnotation
public class MyClass {
}

7.4.3 读取

如果没有 读取部分,前面的代码就完全没用。

就好比说,

@Override

声明: public @interface Override {

}

使用: class Son extends Father{

@Override //注解的使用

public void method() {

System.out.println(“son .method”) ;

}

读取:

编译器会读取这个注解,会对方法进行格式检查

7.5 元注解

给注解加注释的注解

@Target : 用来解释/注释某个注解可以用在哪里可以用

注解的位置一共有10个。

ELementType是一个枚举类型,每一个常量对象,代表一个注解可以使用的位置

ELementType.TYPE: 表示是类型上面

ELementType.FIELD: 表示是属性/字段/成员变量上面

@Retention: 用来解释/注释某个注解的生命周期

每一个注解的生命周期有3个阶段:

SOURCE: 源代码

CLASS: 字节码

RUNTIME: 运行时,内存中

@Documented: 用来解释/注释某个注解是不是可以被javadoc工具读取到API

@Inherited: 用来解释/注释某个注解是不是可以被子类继承

代码演示如下:

import java.lang.annotation.*;
@Inherited  //该元注解表明子定义注解可被子类继承
@Target(ElementType.TYPE)//a该自定过注解只能放在类类型上
@Retention(RetentionPolicy.RUNTIME)//代表它的生命周期是在运行时,只有这样,才能被反射读到
public @interface MyAnnotation {
    String getValue();
    //自定义的注解中只能写无参的抽象方法
    String info();
    //可以使用 default 关键字为抽象方法指定默认返回值
    /*
    抽象方法的返回值类型有限制:
   只能是八种基本数据类型、String类型、CLass类型、enum类型、Annotation类型、以上所有类型的数组
    */
}
@YourAnnotation
@MyAnnotation(getValue ="jack",info = "你好")
/*
@Override
public String getInfo(String str){
    return str
}
*/
public class MyClass {
}
public class MySub extends MyClass {
}
import java.lang.annotation.Annotation;
public class TestAnnotation {
    public static void main(String[] args) {
        Class  aClass=MyClass.class;
        //获取Annotation对象
        Annotation annotation = aClass.getAnnotation(MyAnnotation.class);
        System.out.println(annotation);
        MyAnnotation my=(MyAnnotation)annotation; //需要向下转型,才能调用MyAnnotation对象的抽象方法
        System.out.println(my.getValue());
        System.out.println(my.info());
        System.out.println("---------------------");
        Class  c1=MySub.class;
        //获取Annotation对象
        Annotation annotation1 = c1.getAnnotation(MyAnnotation.class);
        System.out.println(annotation1);
    }
}
public @interface YourAnnotation {
}

🔔注意:

1.抽象方法的返回值类型有限制:

只能是八种基本数据类型、String类型、CLass类型、enum类型、Annotation类型、以上所有类型的数组

2.自定义的注解中只能写无参的抽象方法,在无参的抽象方法中可以使用 default 关键字为抽象方法指定默认返回值

相关文章
|
2月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
395 1
|
5月前
|
设计模式 算法 Java
Java SE 与 Java EE 组件封装使用方法及实践指南
本指南详细介绍了Java SE与Java EE的核心技术使用方法及组件封装策略。涵盖集合框架、文件操作、Servlet、JPA、EJB和RESTful API的使用示例,提供通用工具类与基础组件封装建议,如集合工具类、文件工具类、基础Servlet、实体基类和服务基类等。同时,通过分层架构集成示例展示Servlet、EJB和JPA的协同工作,并总结组件封装的最佳实践,包括单一职责原则、接口抽象、依赖注入、事务管理和异常处理等。适合希望提升代码可维护性和扩展性的开发者参考。
187 0
|
Oracle Java 关系型数据库
Java(TM) Platform SE binary 已停止工作”的解决方法
Java(TM) Platform SE binary 已停止工作”的解决方法
1524 141
|
11月前
|
Java 数据库连接 Spring
反射-----浅解析(Java)
在java中,我们可以通过反射机制,知道任何一个类的成员变量(成员属性)和成员方法,也可以堆任何一个对象,调用这个对象的任何属性和方法,更进一步我们还可以修改部分信息和。
|
监控 Java
Java基础——反射
本文介绍了Java反射机制的基本概念和使用方法,包括`Class`类的使用、动态加载类、获取方法和成员变量信息、方法反射操作、以及通过反射了解集合泛型的本质。同时,文章还探讨了动态代理的概念及其应用,通过实例展示了如何利用动态代理实现面向切面编程(AOP),例如为方法执行添加性能监控。
144 5
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
237 9
Java——反射&枚举
|
Java
Java的反射
Java的反射。
129 2
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
190 2
|
IDE Java 编译器
java的反射与注解
java的反射与注解
101 0
下一篇
oss云网关配置