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 关键字为抽象方法指定默认返回值

相关文章
|
8天前
|
Java C++
Java反射的简单使用
Java反射的简单使用
21 3
|
17天前
|
Java
【专栏】Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性
【4月更文挑战第27天】本文探讨了Java反射机制,该机制允许程序在运行时获取类信息、动态创建对象、调用方法和访问属性。反射通过Class、Constructor、Method和Field类实现。文中列举了反射的应用场景,如动态创建对象、调用方法、访问属性和处理注解,并提供了相关实例代码演示。
|
3天前
|
Java 开发框架 XML
JDK、JRE、Java SE、Java EE和Java ME有什么区别?
JDK、JRE、Java SE、Java EE和Java ME有什么区别?
|
8天前
|
SQL 存储 Java
【Java反射详解】
【Java反射详解】
11 1
|
12天前
|
Java
JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识
【5月更文挑战第2天】JAVA难点包括异常处理、多线程、泛型和反射,以及复杂的分布式系统知识。入坑JAVA因它的面向对象特性、平台无关性、强大的标准库和活跃的社区支持。
36 2
|
15天前
|
Java 索引
Java SE ____二维数组
Java SE ____二维数组
|
16天前
|
Java 测试技术
滚雪球学Java(24):Java反射
【4月更文挑战第13天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
23 0
滚雪球学Java(24):Java反射
|
20天前
|
Java
Java 反射
Java 反射
|
20天前
|
设计模式 Java 索引
由反射引出的Java动态代理与静态代理
由反射引出的Java动态代理与静态代理
15 0
|
20天前
|
存储 Java Shell
深入剖析Java中的反射,由浅入深,层层剥离!
深入剖析Java中的反射,由浅入深,层层剥离!
14 1