每日一狗(田园犬西瓜瓜)
反射机制无所不能
执行效率低下
Java中提供的自省机制。
反射:动态获取类的信息一种动态调用对象的方法称为Java的反射Reflection机制。
反射提供了封装程序集、模块和类型的对象。
在Java运行环境中,对于任意一个类的对象,可以通过反射获取这个类的信息,对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
类的加载流程
new A();
的时候,会触发JVM加载A.class文件类的加载本质上都是通过类加载器组件来负责完成的,Java的类加载器是通过双亲委托机制
反射的本质就是得到Class对象后,反向获取A对象的各种信息
破坏了封装性
反编译
IDE工具的提示
一些框架需要知道你定义的东西都有啥
反射最重要的用途就是开发各种通用框架。比如很多框架Spring都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象
MyBatis持久层框架 Spring业务层框架 SpringMVC表现层框架
package com.yang2;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test01 {
public static void main(String[] args) {
Class clz = A1.class;
// 获取属性
Field[] fs = clz.getDeclaredFields();
for (Field f : fs) {
System.out.println(f);
}
// 获取方法
Method[] ms = clz.getDeclaredMethods();
for (Method m : ms) {
System.out.println(m);
}
// 获取构造器
Constructor[] cs = clz.getConstructors();
for (Constructor c : cs) {
System.out.println(c);
}
}
}
class A1 {
private Long id;
private String name;
public A1() {
}
public A1(Long id, String name) {
this.id = id;
this.name = name;
}
public void pp() {
}
}
/*
private java.lang.Long com.yang2.A1.id
private java.lang.String com.yang2.A1.name
public void com.yang2.A1.pp()
public com.yang2.A1()
public com.yang2.A1(java.lang.Long,java.lang.String)
*/
getName()
:获取类的名字,例如java.util.DategetFields()
:获取类中public类型的属性,自定义或者从父类种继承getDeclaredFields()
:获取类的所有属性(包括public、protected、default、private),只能获取到当前类种定义,不能获取父类继承的getMethods()
:获取类中public类型的方法getDeclaredMethods()
:获取类的所有方法getMethod(String name,Class[] parameterTypes)
:获取类的指定方法,name:指定方法的名字,parameterType:指定方法的参数类型getConstrutors()
:获取类中public类型的构造方法getDeclaredConstructors()
:获取类中所有的构造方法getConstrutor(Class[] parameterTypes)
:获取类的指定构造方法,parameterTypes:指定构造方法的参数类型getDeclaredConstructor
newInstance()
:通过类的public不带参数的构造方法创建该类的一个对象;注:在访问私有属性和私有方法时,需要对访问的私有属性或方法设置setAccessible(true)使被反射的类抑制java的访问检查机制。否则会报IllegalAccessException异常。
这里需要注意的是A1.class不会执行静态代码块
package com.yang3;
public class Test01 {
public static void main(String[] args) throws Exception {
// 1、 使用Class.forName()
Class<?> clz = Class.forName("com.yang3.A1"); // 静态代码块会被执行
System.out.println(clz);
// 2、 使用.class
Class<?> clz2 = A1.class; // 不会执行加载静态代码块
System.out.println(clz2);
// 3、使用getClass方法
A1 a1 = new A1();
Class<?> clz3 = a1.getClass();
System.out.println(clz3);
System.out.println(clz3 == clz);
System.out.println(clz3 == clz2);
// 4、 使用类加载器获取Class对象
}
}
class A1 {
private static Long id;
static {
id = 50L;
System.out.println(id);
}
}
针对包装类还可以获取其对应的原生数据类型
Class<Integer> clz = Integer.TYPE;
System.out.println(clz); // int
package com.test;
import java.lang.reflect.Constructor;
import java.util.Date;
public class Test01 {
public static void main(String[] args) throws Exception {
Class<?> clz = Date.class;
// 获取无参的构造方法
Constructor<?> con = clz.getConstructor();
// 调用无参的构造方法
Object dd = con.newInstance();
System.out.println(dd); // Thu Sep 15 20:59:53 CST 2022
// 获取带参构造器 public Date(long date) {
con = clz.getConstructor(long.class);
// 调用带参构造器
dd = con.newInstance(1000);
System.out.println(dd); // Thu Jan 01 08:00:01 CST 1970
}
}
使用反射机制生成对象的步骤
String getName()
获取属性名int getModifiers()
获取属性限定词编号Object get(Object obj)
获取指定对象的指定属性值Class> getType()
获取属性的类型Modifier.toString(f.getModifiers())
可以将指定限定编号转换为String类型供提高可读性public void setAccessible(boolean flag)
设定属性访问权限public void set(Object obj, Object value)
为obj对象的指定属性设定为value可见getFields和getDeclaredFields区别:
getFields
返回的是申明为public的属性,包括父类中定义getDeclaredFields
返回的是指定类定义的所有定义的属性,不包括父类的
package com.yang3;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Test04 {
public static void main(String[] args) throws Exception, IllegalAccessException {
A4 a = new A4();
Class<?> clz = a.getClass();
// 获取公共属性
Field[] fs = clz.getFields();
for (Field f : fs) {
System.out.println("属性名" + f.getName() + "属性类型" + f.getType() + "属性的类型" + f.getGenericType() + "限定词"
+ f.getModifiers() + "存储值" + f.get(a));
}
fs = clz.getDeclaredFields();
for (Field f : fs) {
f.setAccessible(true);
System.out.println("属性名" + f.getName() + "属性类型" + f.getType() + "属性的类型" + f.getGenericType() + "限定词"
+ f.getModifiers() + "限定词修饰符" + Modifier.toString(f.getModifiers()) + "存储值" + f.get(a));
}
}
}
interface IA41 {
public String IA41 = "IA41";
}
abstract class A41 implements IA41 {
public String A41 = "A41";
}
class A4 extends A41 {
private static final String type = "A4";
public volatile String name = "测试名";
private Long id;
}
/*
属性名name属性类型class java.lang.String属性的类型class java.lang.String限定词65存储值测试名
属性名A41属性类型class java.lang.String属性的类型class java.lang.String限定词1存储值A41
属性名IA41属性类型class java.lang.String属性的类型class java.lang.String限定词25存储值IA41
属性名type属性类型class java.lang.String属性的类型class java.lang.String限定词26限定词修饰符private static final存储值A4
属性名name属性类型class java.lang.String属性的类型class java.lang.String限定词65限定词修饰符public volatile存储值测试名
属性名id属性类型class java.lang.Long属性的类型class java.lang.Long限定词2限定词修饰符private存储值null
*/
package com.yang3;
import java.lang.reflect.Field;
public class Test03 {
public static void main(String[] args) throws Exception {
A3 obj = new A3();
Class<?> clz = obj.getClass();
Field[] fs = clz.getDeclaredFields();
for (Field f : fs) {
System.out.println(f);
}
// 设定编号
Field f1 = clz.getDeclaredField("id");
f1.setAccessible(true);
f1.set(obj, 99L);
// 设定姓名
Field f2 = clz.getDeclaredField("name");
f2.setAccessible(true);
f2.set(obj, "test");
System.out.println(obj);
}
}
class A3 {
private Long id;
private String name;
@Override
public String toString() {
return "A3 [id=" + id + ", name=" + name + "]";
}
}
public Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共public Method getMethod(String name, Class>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法public Method getDeclaredMethod(String name, Class>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法public Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法在JDK中,主要由以下类实现Java反射机制:
Class类:代表一个类
Field类:代表类的成员变量(属性)
Method类:代表类的方法
Constructor类:代表类的构造方法
Array类:提供了动态创建数组,以及访问数组元素的静态方法;(这个就是Java实现数组的方法)
以上类中,Class类在java.lang包,其余位于java.lang.reflect包。
java.lang.Object类(所有类的超类)定义了getClass()方法,任意一个Java对象都可以通过此方法获
得它的class。
一种说明信息,编译器在编译的时候会忽略这些说明信息
// 行内注释
/*
* 多行注释
*/
/**
一种特殊的注释,会在编译期对指定程序做一些事情
一般来说命名规则与接口一致
定义注解的注解
@Documented //类和方法的Annotation在缺省情况下是不出现在javadoc中的。如果使用@Documented修饰该 Annotation,则表示它可以出现在javadoc中。定义时@Documented可有可无;若没有定义,则Annotation不会出现在javadoc中。
@Target(ElementType.TYPE) //指定Annotation的类型属性。@Target(ElementType.TYPE)就是指定该Annotation的类型是ElementType.TYPE。这就意味着,MyAnnotation1是来修饰"类、接口(包括注释类型)或枚举声明"的注解。定义Annotation时,@Target可有可无。若有@Target则该Annotation只能用于它所指定的地方;若没有@Target,则该Annotation可以用于任何地方。
@Retention(RetentionPolicy.RUNTIME)//RetentionPolicy是注解的策略属性,而@Retention的作用,就是指定Annotation的策略属性。RetentionPolicy.RUNTIME意思就是指定编译器会将注解信息保留在.class 文件中,并且能被虚拟机读取。定义时@Retention可有可无。若没有@Retention则默认RetentionPolicy.CLASS
//@interface表示它实现了java.lang.annotation.Annotation接口,即该注解就是一个Annotation。定义时@interface是必须的。
注意:它和通常的实现接口的方法不同。Annotation接口的实现细节都由编译器完成。通过@interface定义注解后,该注解不能继承其他的注解或接口。
public @interface MyAnnotation {
//设置属性,如果只有一个value属性情况下可以省略value名称不写;如果有多个属性,且多个属
//性没有默认值,则value名称是不能省略的
String[] value() default "unknown";
}