Java中的反射可以在程序运行期动态的获取程序信息。
关于反射,从下面的这段话仔细揣摩。
java.lang.reflect 库中包含类 Field、Method 和 Constructor(每一个都实现了 Member 接口)。这些类型的对象由 JVM 在运行时创建,以表示未知类中的对应成员。然后,可以使用 Constructor 创建新对象,get() 和 set() 方法读取和修改与 Field 对象关联的字段,invoke() 方法调用与 Method 对象关联的方法。此外,还可以调用便利方法 getFields()、getMethods()、getConstructors() 等,以返回表示字段、方法和构造函数的对象数组。(你可以通过在 JDK 文档中查找类 Class 来了解更多信息。)因此,匿名对象的类信息可以在运行时完全确定,编译时不需要知道任何信息。
这段文字摘自github
上面的 Java编程思想
依我个人而言,反射就是一种技术,从Java的角度看,这种技术可以在程序的运行期获得对象的类信息和属性信息,结合面向接口编程,相同的接口引用指向不同的对象,只要拿到对象就可以拿到类里面的成员变量和成员方法,拿到方法后可以调用方法,拿到字段后可以设置字段的值
反射代码
使用反射得到类的访问修饰符,包名,类名以及判断类的属性:
public static void main(String[] args) {
Class clazz = TempTest.class;
//获取访问修饰符
int modify = clazz.getModifiers();
System.out.println(Modifier.toString(modify));
//获取包名和全限定类名
Package p = clazz.getPackage();
String name = clazz.getName();
System.out.println("p : "+p+" \nname : "+name);
System.out.println("isInterface(): "+clazz.isInterface());
System.out.println("isEnum(): "+clazz.isEnum());
System.out.println("isAnnotation(): "+clazz.isAnnotation());
System.out.println("isArray(): "+clazz.isArray());
}
获取构造器对象,然后使用构造器对象创建实例
Class<?> clazz = Class.forName("com.llm.test.TempTest");
//使用Class对象创建对象(默认是使用的无参构造方法)
TempTest tem = (TempTest)clazz.newInstance();
Constructor<?>[] cons = clazz.getDeclaredConstructors();
for (int i = 0; i < cons.length; i++) {
System.out.println(cons[i]);
}
Constructor<?> constructor = clazz.getConstructor();
Object o = constructor.newInstance();
System.out.println(o);
使用反射操作对象的方法
public static void main(String[] args) throws Exception {
Class clazz = Student.class;
//利用默认空参实例化一个对象
Student stu = (Student)clazz.newInstance();
//公有方法
Method m = clazz.getMethod("sleep");
m.invoke(stu,null);
//私有方法
Method m2 = clazz.getDeclaredMethod("run");
m2.setAccessible(true); //不加的话报 IllegalAccessException
m2.invoke(stu,null);
//静态方法
Method m3 = clazz.getDeclaredMethod("play");
m3.invoke(null); //静态方法不需要对象就可以调用
}
static class Student{
public void sleep(){
System.out.println("sleep() ");
}
private void run(){
System.out.println("run() ");
}
public static void play(){
System.out.println("static::play() ");
}
}
反射操作成员变量
public static void main(String[] args) throws Exception {
Class clazz = Student.class;
Student stu = (Student)clazz.newInstance();
System.out.println("获取public属性,并设置值");
Field name = clazz.getField("name");
name.set(stu,"小李");
System.out.println(stu);
System.out.println("获取private属性,并设置值");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true); // 不加这一行会报 IllegalArgumentException
age.set(stu,20);
System.out.println(stu);
System.out.println("获取静态属性,并设置值");
Field password = clazz.getField("password");
password.set(stu,"123");
System.out.println(Student.password);
}
static class Student{
private int age;
public String name;
public static String password;
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static String getPassword() {
return password;
}
public static void setPassword(String password) {
Student.password = password;
}
}
反射配合注解使用
反射最常用的技术可能就是搭配注解来做一些功能了,使用反射,可以使标注指定注解的类实现一些特别的功能
在研究反射配置注解的操作之前,可以先看一看如何自定义注解
自定义注解里面的参数可以设置为:
(String,数组,枚举,基本数据类型,Class类型)
下面结合注解和反射,可以完成一个简单的属性注入
的功能
- 首先定义注解
MyAnnotation
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation {
String name();
int[] ages() default {0};
Gender man() default Gender.MAN;
int age();
Class clazz() default Integer.class;
}
enum Gender{
MAN,WOMAN
}
- 然后再创建一个类
Student
来测试操作:
public class Student {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@MyAnnotation(name = "张三",age = 19)
public void print(){
System.out.println("我的名字是: "+name+" 我的年龄是:"+age);
}
}
- 最后是使用反射的操作类:
public class AnnotationTest {
public static void main(String[] args) throws Exception {
Class clazz = Student.class;
//获取所有的方法
Method[] methods = clazz.getDeclaredMethods();
MyAnnotation annotation = null;
for (Method m :
methods) {
if (m.isAnnotationPresent(MyAnnotation.class)){
annotation = m.getAnnotation(MyAnnotation.class);
}
}
if (annotation == null){
System.err.println("没有找到目标注解:");
return;
}
int age = annotation.age();
String name = annotation.name();
System.out.println("使用实例化开始设置值,然后调用print()方法");
Student o = (Student)clazz.newInstance();
o.setAge(age);
o.setName(name);
o.print();
}
}
完成了上面这三步,就可以实现把注解上的参数注入到指定的对象的操作。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/202482.html