反射
反射
1.概念
反射:程序在运行时可以动态获取指定类的信息
利用反射机制,开发者可以在 JVM 运行期间做的事:
- 判断任意一个对象所属类
- 判断任意一个类中所有成员变量及方法
- 任意调用一个对象的方法
- 构造任意一个类的对象
Class类是反射的基础,我们要在程序运行期间获取一个类的相关信息,就需要Class类
2.获取Class对象
类名.classClass<Person> clazz = Person.class; 2.
对象.getClass()Person person = new Person(); Class clazz = person.getClass(); 3.``Class.forName(类的全路径名)`
Class clazz = Class.forName("com.study.test3.Person");
3.通过反射创建对象
通过反射创建对象的步骤:
- 获取构造参数
- 创建对象
(1)获取构造参数
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//获取Class对象
Class<User> clazz = (Class<User>)Class.forName("com.dream.reflect.User");
//获取无参构造
Constructor<User> constructor1 = clazz.getConstructor();
//获取带String和int类型参数的无参构造
Constructor<User> constructor2 = clazz.getConstructor(String.class, int.class);
//获取所有的构造方法(不包括私有的)
Constructor<?>[] constructorAll = clazz.getConstructors();
/*
方法名不带Declared 只能获取public修饰的方法
方法名带Declared 能获取所有权限修饰符修饰的方法
*/
//获取无参构造
Constructor<User> constructor3 = clazz.getDeclaredConstructor();
//获取带String类型参数的私有无参构造
Constructor<User> constructor4 = clazz.getDeclaredConstructor(String.class);
//获取所有的构造方法(包括私有的)
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
}
(2)创建对象
public class Dmeo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<User> clazz = (Class<User>)Class.forName("com.dream.reflect.User");
Constructor<User> constructor = clazz.getConstructor(String.class, int.class);
//创建类的对象
User user = constructor.newInstance("牟帆", 24);
System.out.println(user);
/*
获取私有的构造方法并访问
注意:
获取:必须使用带Declared的方法
访问:必须先开启访问权限
*/
Constructor<User> declaredConstructor = clazz.getDeclaredConstructor(String.class);
//开启访问权限
declaredConstructor.setAccessible(true);
User user1 = declaredConstructor.newInstance("冰儿");
System.out.println(user1);
}
}
4.通过反射获取类的属性
Filed的获取
getField(String name):获取指定名称的属性对象
getFields():获取所有的属性对象
getDeclaredField(String name):获取任意权限的指定名称的属性对象
getDeclaredFields():获取任意权限的所有的属性对象
Filed的操作
set(Object obj, Object value):将指定的值赋值给指定对象的指定属性
``set(java对象, 属性的值)`
get(Object obj):获取指定对象的指定属性的值
get(java对象)
/*
获取属性 操作属性
*/
public class Demo4 {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取Class对象
Class<Admin> clazz = Admin.class;
//2.获取Admin类所有的public修饰的属性包括继承过来的
Field[] fields1 = clazz.getFields();
//3.获取Admin类所有的属性包括private修饰的
Field[] fields2 = clazz.getDeclaredFields();
System.out.println(Arrays.toString(fields1));
System.out.println(Arrays.toString(fields2));
//获取gender属性
Field genderField = clazz.getDeclaredField("gender");
//获取bbb属性
Field bbbField = clazz.getField("bbb");
System.out.println("-------------操作属性:取值、赋值---------------------------------");
//给gender属性赋值
/*
属性对象.set(java对象, 属性的值)
*/
//要操作private修饰的属性必须先开启权限
genderField.setAccessible(true);
Constructor<Admin> constructor = clazz.getConstructor();
Admin admin = constructor.newInstance();
genderField.set(admin, '男');
//取出gender属性的值
/*
属性对象.get方法(java对象)
*/
System.out.println(genderField.get(admin));//jay
}
}
5.通过反射获取类德方法
Method的获取
getMethod(String 方法名,形参列表): 获取指定方法(不能获取私有方法)
getDeclaredMethod(String 方法名,形参列表): 获取指定方法(可以获取私有方法)
Method的操作
方法对象.invoke(Java对象,形参列表): invoke方法的返回值,就是指定的方法的返回值。
如果指定的方法没有返回值,则invoke方法返回null
/*
获取方法 操作方法
*/
public class Demo5 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Admin> clazz = Admin.class;
/*
获取所有的公共方法包括继承的
*/
Method[] methods1 = clazz.getMethods();
/*
获取当前类的所有权限的方法
*/
Method[] methods2 = clazz.getDeclaredMethods();
System.out.println(Arrays.toString(methods1));
System.out.println(Arrays.toString(methods2));
/*
获取指定方法
类对象.getMethod(String 方法名,形参列表)
类对象.getDeclaredMethod(String 方法名,形参列表)
*/
//获取Admin类的test方法
Method method = clazz.getDeclaredMethod("test", String.class);
System.out.println("------------------执行方法-------------------");
/*
执行方法
方法对象.invoke(Java对象,形参列表)
invoke方法的返回值,就是指定的方法的返回值
如果指定的方法没有返回值,则invoke方法返回null
*/
method.setAccessible(true);
Constructor<Admin> constructor = clazz.getConstructor();
Admin admin = constructor.newInstance();
/*
执行指定方法,并接收该方法的返回值
*/
Object result = method.invoke(admin, "哈哈哈");
System.out.println(result);//输出返回值
}
}
6.通过反射获取注解
例1
1.自定义注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
String value(); // 这是注解的一个属性字段,也就是在使用注解时填写在括号里的参数
}
2.创建 TestController 类,然后在 TestController 类中使用 @MyRequestMapping 注解,代码如下:
@MyRequestMapping("/test")
public class TestController {
public void test() {
System.out.println("进入Test方法");
}
}
3.测试类代码
public class Test {
public static void main(String[] args) {
Class<?> c = TestController.class;
//获取该类中@MyRequestMapping 注解对象
MyRequestMapping baseRequestMapping = c.getAnnotation(MyRequestMapping.class);
System.out.println(baseRequestMapping.value()); // 输出value的值
//获取该类中所有注解对象
Annotation[] atnsArray = c.getAnnotations();
for (Annotation an : atnsArray) {
System.out.println(an);
}
}
}
Annotation[] getAnnotations():获取所有注解(不包括私有)
Annotation[] getDeclaredAnnotations():获取所有注解(包括私有)
<A extends Annotation> A getAnnotation(Class<A> annotationClass):获取指定注解
7.注意
如果方法名不带Declared,只能获取公共的属性/方法
同时还有获取继承过来的属性/方法
如果方法名带Declarred,能获取任意权限的属性/方法
但是不能获取继承过来的属性/方法
8.反射的优缺点
缺点:
- 反射代码的可读性和可维护性比较低
- 反射代码执行的性能低
- 反射破坏了封装性
优点:
- 可以在运行期间获取类的信息、并操作一个类的方法,提高程序的灵活性和扩展性
浙公网安备 33010602011771号