获取类的运行时状态
//获取类的信息
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("com.mayb.demo02.Son");
Son01 son01 = new Son01();
//通过反射
c1 = son01.getClass();
System.out.println(c1.getName());//获取类的名称 包名 + 类名
System.out.println(c1.getSimpleName());//获取类的简单名称 类名
}
}
class Son01{
private int m = 10;
}
通过反射获取运行时类的完整结构
Field(属性)、Method(方法)、Constructor(构造器)、 Superclass(父类)、 Interface(接口)、 Annotation(注解)
实现的全部接口 ,所继承的父类,全部的构造器,全部的方法,全部的Field,注解等
获取在运行时类的完整结构
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//获取类的信息
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("com.mayb.demo02.Son");
System.out.println(c1.getName());//获取类的名称 包名 + 类名
System.out.println(c1.getSimpleName());//获取类的简单名称 类名
System.out.println("<-------------------------->");
//获取类的属性
Field[] fields = c1.getFields();//只能找到public属性
for (Field field : fields) {
System.out.println(field);
}
fields = c1.getDeclaredFields();//获取全部属性
for (Field field : fields) {
System.out.println(field);
}
Field m = c1.getDeclaredField("m");//获取指定属性
System.out.println(m);
System.out.println("<-------------------------->");
//获取类的方法
Method[] methods = c1.getMethods(); // 包括本类和父类的全部public方法
for (Method method : methods) {
System.out.println("public : "+method);
}
methods = c1.getDeclaredMethods();//仅获取本类的所有方法
for (Method method : methods) {
System.out.println("全部的 : "+ method);
}
//获取指定方法 小心重载
Method method = c1.getMethod("aVoid", String.class); //需要public
System.out.println(method);
method = c1.getDeclaredMethod("cVoid", String.class);//这个是全部的
System.out.println(method);
method = c1.getMethod("bVoid", String.class, int.class, int.class);
System.out.println(method);
System.out.println("<-------------------------->");
//获取构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("All : "+constructor);
}
//获取指定的构造器
Constructor constructor = c1.getConstructor(int.class, int.class);
System.out.println(constructor);
constructor = c1.getDeclaredConstructor();
System.out.println("All"+constructor);
}
}
Class.forName 的Son类
public class Son {
private int m = 100;
public int M = 1;
public void aVoid(String a ){}
private void cVoid(String a ){}
public void bVoid(String a ,int b,int c){}
public Son() {}
public Son(int m, int m1) {
this.m = m;
M = m1;
}
}
使用反射操作对象
创建类的对象:调用Class对象的newInstance()方法
- 类必须有一个无参数的构造器。
- 类的构造器的访问权限需要足够
思考?难道没有无参的构造器就不能创建对象了吗?只要在操作的时候明确的调用类中的构造器,
并将参数传递进去之后,才可以实例化操作。
步骤如下:
- 通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构
造器 - 向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
- 通过Constructor实例化对象
//动态的创建对象,通过反射
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// 获得Class对象
Class c1 = Class.forName("com.mayb.demo02.Son");
// 构造一个对象
Son son1 = (Son) c1.newInstance();//本质上调用无参构造 没无参构造就会错误
System.out.println(son1);
//通过构造器构造对象
Constructor constructor = c1.getConstructor(int.class,int.class);
Son son2 = (Son) constructor.newInstance(1,1);
System.out.println(son2);
// 通过反射调用方法
Son son3 = (Son) c1.newInstance();
Method method = c1.getDeclaredMethod("setName", String.class);
//给那个对象调用方法传入的参数 invoke 激活方法
//第一参数为对象 第二为参数值
method.invoke(son3,"Mayb");
System.out.println(son3.getName());
// 通过反射操作属性
Son son4 = (Son) c1.newInstance();
Field name = c1.getDeclaredField("name");//不能为私有的属性
// 是否开启关闭检查 开启了就可以给私有属性设值(程序的安全检测 setAccessible)
name.setAccessible(true);//降低程序效率
name.set(son4,"Mayb2");
System.out.println(son4.getName());
}
}
setAccessible
- Method和Field、Constructor对象都有setAccessible()方法。
- setAccessible作用是启动和禁用访问安全检查的开关。
- 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
- 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。
- 使得原本无法访问的私有成员也可以访问
- 参数值为false则指示反射的对象应该实施Java语言访问检查
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//分析性能问题
public class Test06 {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
// 普通方式调用
public static void test01(){
Son son = new Son("Mayb");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
son.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法执行时间:" + (endTime - startTime));
}
// 反射方式调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Son son = new Son("Mayb");
Class c1 = son.getClass();
Method getName = c1.getDeclaredMethod("getName",null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(son,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式调用:" + (endTime - startTime));
}
// 反射方式调用 关闭安全检查
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Son son = new Son("Mayb");
Class c1 = son.getClass();
Method getName = c1.getDeclaredMethod("getName",null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(son,null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭安全检查:" + (endTime - startTime));
}
}
结果
普通方法执行时间:3
反射方式调用:1999
关闭安全检查:1320
如果在使用时调用很多次反射方法可以关闭安全检测
通过反射获取泛型
泛型是一种约束机制
- Java采用泛型擦除的机制来弓|入泛型, Java中的泛型仅仅是给编译器javac使用的,确保数据
的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除 - 为了通过反射操作这些类型, Java新增了ParameterizedType , GenericArrayType,
TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原
始类型齐名的类型. - ParameterizedType :表示- -种参数化类型,比如Collection
- GenericArrayType :表示一种元素类型是参 数化类型或者类型变量的数组类型
- TypeVariable :是各种类型变量的公共父接口
- WildcardType :代表一种通配符类型表达式
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 Test07 {
public void test01(Map<String,Son> map, List<Son> list){
System.out.println("test01");
}
public Map<String,Son> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method test01 = Test07.class.getDeclaredMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = test01.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("genericParameterType : "+genericParameterType);
//如果泛型的参数类型 genericParameterType 属于 参数化类型
if (genericParameterType instanceof ParameterizedType){
//获取真实类型
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
test01 = Test07.class.getDeclaredMethod("test02",null);
Type genericReturnType = test01.getGenericReturnType();//返回类型
if (genericReturnType instanceof ParameterizedType){
//获取真实类型
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("actualTypeArgument: " + actualTypeArgument);
}
}
}
}
反操作注解
getAnnotations
getAnnotation
通过注解和反射完成ORM 对象关系映射
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.mayb.demo02.Student");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解value 的值
TableStudent tableStudent = (TableStudent)c1.getAnnotation(TableStudent.class);
String value = tableStudent.value();
System.out.println(value);
//获取类指定的注解
Field f = c1.getDeclaredField("id");
FieldInterface annotation = f.getAnnotation(FieldInterface.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@TableStudent("db_student")
class Student{
@FieldInterface(columnName = "db_id",type = "int",length = 10)
private int id;
@FieldInterface(columnName = "db_age",type = "int",length = 10)
private int age;
@FieldInterface(columnName = "db_name",type = "varchar",length = 10)
private String name;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", age=" + age +
", 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;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student() {
}
public Student(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
}
//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableStudent{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldInterface{
String columnName();
String type();
int length();
}