反射机制Reflection _ 4.创建运行时类的对象
获取运行时类的完整结构
通过反射获取运行时类的完整结构:
Field,Method,Constructor,Superclass,Interface,Annotation
package com.company.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//获得类的信息
public class test09 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("com.company.reflection.User");
//获取类的名字
System.out.println(c1.getName()); //获得包名+类名
System.out.println(c1.getSimpleName()); //获得类名
//获得类的属性
Field[] fields = c1.getFields(); //只能找到public属性
fields = c1.getDeclaredFields(); //找到全部属性
for(Field field:fields) {
System.out.println(field);
}
//获得指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name);
//获得类的方法
Method[] methods = c1.getMethods(); //获得本类及其父类的所有方法
for(Method method:methods) {
System.out.println("正常的:"+method);
}
methods = c1.getDeclaredMethods(); //获得本类的所有方法
for(Method method:methods) {
System.out.println("getDeclaredMethods:"+method);
}
//获得指定方法
Method getName = c1.getMethod("getName",null);
Method setName = c1.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);
//获得指定的构造器
Constructor[] constructors = c1.getConstructors();
for(Constructor constructor:constructors) {
System.out.println("getConstructors:"+constructor);
}
constructors = c1.getDeclaredConstructors();
for(Constructor constructor:constructors) {
System.out.println("getDeclaredConstructors"+constructor);
}
//获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println("指定的构造器:"+declaredConstructor);
}
}
动态创建对象执行方法
-
创建类的对象:调用Class对象的
newInstance()
方法- 类必须有无参构造器
- 类的构造器必须有足够的权限
-
如果没有无参构造器,我们需要明确调用类中的构造器,并将参数传递进去,进行实例化。步骤如下:
- 通过Class类的
getDeclaredConstructor(Class...parameterTypes)
获取本类指定形参构造器 - 向构造器的形参中传递一个对象数组进去,里面包含了构造器所需的参数
- 通过Constructor来实例化对象
- 通过Class类的
通过反射,调用类中的方法,通过Method类完成:
- 通过Class类的
getMethod(...)
方法获取一个Method对象,并设置操作此方法时所需参数类型。 - 之后使用
Object invoke(...)
进行调用,并向方法中传递要设置的object对象的参数信息。
-
Object invoke(Object obj, Object ... args)
- Object对应原方法的返回值,若无返回值则返回null
- 原方法若为静态方法,则形参
Object obj
可为null - 原方法的参数列表为空,则
Object[] args
可为null - 原方法声明为private则需要在调用
invoke()
前,显式调用方法对象的setAccessible(true)
方法,然后可以访问private方法
-
SetAccessible
- Method,Field,Constructor对象都有
SetAccessible
方法 SetAccessible
方法的作用是启用或禁用安全访问检查的开关- 参数设置为true,反射对象取消Java语言访问检查
- 提高反射效率,反射代码频繁调用,设置为true可以提示效率
- 使得原本无法访问的私有成员也可以访问
- 参数设置为false,反射对象实施Java语言访问检查
- Method,Field,Constructor对象都有
package com.company.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//通过反射动态创建对象
public class test10 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得Class对象
Class c1 = Class.forName("com.company.reflection.User");
//构造一个对象
User user = (User) c1.newInstance();
System.out.println(user);
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User) constructor.newInstance("ZZ", 001, 18);
System.out.println(user2);
//通过反射调用不同方法
User user3 = (User) c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getMethod("setName", String.class);
//invoke: 激活的意思
//(对象,“方法的值”)
setName.invoke(user3, "SS");
System.out.println(user3);
//通过反射操作属性
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操纵私有属性,我们需要关闭程序的安全检测,通过 属性或者方法.setAccessible(true)
name.setAccessible(true);
name.set(user, "AA");
System.out.println(user4.getName());
}
}
反射操作泛型
- Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅
javac
是给编译器使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除 - 为了通过反射操作这些类型,Java新增了
ParameterizedType
、GenericArrayType
、TypeVariable
和WildcardType
几种类型来代表不能被归一到 Class类中的类型但是又和原始类型齐名的类型 ParameterizedType
:表示一种参数化类型,比如CollectionGenericArrayType
:表示一种元素类型是参数化类型或者类型变量的数组类型TypeVariable
:是各种类型变量的公共父接口WildcardType
:代表一种通配符类型表达式
package com.company.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//通过反射获取泛型
public class test11 {
public void test01(Map<String,User> map, List<User> list) {
System.out.println("test01");
}
public Map<String, User> test02() {
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = test11.class.getMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType:genericParameterTypes) {
System.out.println(genericParameterType);
if(genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArgumrnts = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for(Type actualTypeArgumrnt:actualTypeArgumrnts) {
System.out.println(actualTypeArgumrnt);
}
}
}
method = test11.class.getMethod("test02", null);
Type genericReturnType = method.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArgumrnts = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for(Type actualTypeArgumrnt:actualTypeArgumrnts) {
System.out.println(actualTypeArgumrnt);
}
}
/*
1. 获取当前类
2. 获取目标字段
3. 获取包含泛型类型的类型 getGenericType()
4. 强转至子类ParameterizedType因为Type没有任何对应的方法
5. 获得泛型真正的类型getActualTypeArguments()
*/
}
}
反射操作注解
练习:
-
ORM:Object Relationship Mapping 对象关系映射
- 类和表结构对应
- 属性和字段对应
- 对象和记录对应
-
利用注解和反射完成类和表的结构的映射关系
package com.company.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
//练习反射操作注解
public class test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.company.reflection.Student2");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for(Annotation annotation:annotations) {
System.out.println(annotation);
}
//获得注解的value值
Table1 table = (Table1) c1.getAnnotation(Table1.class);
String value = table.value();
System.out.println(value);
//获得类指定的注解
Field f = c1.getDeclaredField("name");
Field1 annotation = f.getAnnotation(Field1.class);
System.out.println(annotation.columName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@Table1("db_student")
class Student2 {
@Field1(columName = "db_name", type = "varchar", length = 3)
private String name;
@Field1(columName = "db_id", type = "int", length = 10)
private int id;
@Field1(columName = "db_age", type = "int", length = 10)
private int age;
public Student2() {
}
public Student2(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student2{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table1 {
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field1 {
String columName();
String type();
int length();
}