【Java基础】反射(reflect)

一.Java类加载器简单了解

1.类的加载

当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化

  1. 加载:
    就是指将class文件读入内存,并为之创建一个Class对象,任何类被使用时系统都会建立一个Class对象

  2. 连接:
    验证:确保被加载类的正确性
    准备:负责为类的静态成员分配内存,并设置默认初始化值
    解析:将类的二进制数据中的符号引用替换为直接引用

  3. 初始化:
    局部变量保存在栈区:必须手动初始化
    new 的对象保存在堆区:虚拟机会进行默认初始化,基本数据类型初始化值为0,引用类型初始化值为null

2.类加载的时机(只加载一次)

以下时机仅表示第一次的时候

  1. 直接使用java.exe命令来运行某个主类。
  2. 创建类的实例(new对象)。
  3. 使用类的静态变量,或者为静态变量赋值。
  4. 调用类的静态方法。
  5. 初始化某个类的子类,其父类先进入内存。
  6. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

最先进入内存的类是Object类,并且最先执行的方法并不是main方法,而是Object类中的registerNatives()将对象注册在操作系统上

3.类加载器

负责将.class文件加载到内存中,并为之生成对应的Class对象

虽然我们在开发过程中不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行

4.类加载器的组成

  • Bootstrap ClassLoader 根类加载器
    也被称为引导类加载器,负责Java核心类的加载,比如System类,在JDK中JRE的lib目录下rt.jar文件中的类

  • Extension ClassLoader 扩展类加载器
    负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录

  • System ClassLoader 系统类加载器
    负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径,主要是我们开发者自己写的类

二.什么是反射机制

简单的来说,反射机制就是程序在运行时能够获取自身的信息。在java中,只要给定类的,那么就可以通过反射机制来获取类的所有信息。

  • 反射机制是在运行状态中,对任意个类,都能知道这个类的所有属性,方法;
  • 对于任意一个对象,都能够·动态调用它的任意一个方法和属性;·
  • 这种动态获取信息以及动态调用的功能称之为JAVA的反射机制;

反射会把一个类的组成如:方法(Method)、构造方法(Constructor)、变量(Field),包(package)等信息,映射成一个个Java对象,通过这些反射对象我们可以动态的调用一个类的方法和属性

哪里用到了反射机制?
很多框架都是用到反射机制,如果Hbernate,Struts都是用反射机制实现的

反射的优点和缺点

编译时加载类是静态加载类

  • new 创建对象是静态加载类,在编译时刻就需要加载所有可用使用到的类,如果有一个用不了,那么整个文件都无法通过编译

运行时加载类是动态加载类

  • Class c = Class.forName("类的全名"),不仅表示了类的类型,还表示了动态加载类,编译不会报错,在运行时才会加载,使用接口标准能更方便动态加载类的实现。功能性的类尽量使用动态加载,而不用静态加载。

  • 很多软件比如QQ,360的在线升级,并不需要重新编译文件,只是动态的加载新的东西

三.java.lang.Class

1.什么是Class对象

  • Class 是反射的核心类,Class是由JVM在执行过程中动态加载的。JVM在第一次读取到一种class类型时,将其加载进内存吗,Class对象保存的就是字节码信息

  • 每加载一种class,JVM就为其创建一个Class类型的实例,并关联起来

    以String类为例,当JVM加载String类时,它首先读取String.class文件到内存,然后,为String类创建一个Class实例并关联起来:

    这个Class实例是JVM内部创建的,如果我们查看JDK源码,可以发现Class类的构造方法是private,只有JVM能创建Class实例,我们自己的Java程序是无法创建Class实例的。

    由于JVM为每个加载的class创建了对应的Class实例,并在实例中保存了该class的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等,这种通过Class实例获取class信息的方法称为反射(Reflection)

  • 任意类有且仅有一个class对象

获取Class对应的类或者接口成员Member(成员有:属性,方法,构造方法)
java.lang.reflect.Member是一个接口,代表 Class 的成员,每个成员都有类型,分为是否从父类继承,还有是否可以直接访问。
Member 有三个实现类:

  • java.lang.reflect.Constructor:表示该 Class 的构造函数
  • java.lang.reflect.Field:表示该 Class 的成员变量
  • java.lang.reflect.Method:表示该 Class 的成员方法

2.获取Class对象的三种方式?

public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        // 第一种方式, 通过类名.class 属性
        Class c1 = Student.class;

        // 第二种方式, 通过对象.getClass() 方法
        Class c2 = new Student().getClass();

        // 第三种方式, 通过Class.forName("包名.类名")
        Class c3 = Class.forName("com.demo.reflect.Student");//类路径不对会报错:  java.lang.ClassNotFoundException: xxxxx.Student

        // 打印信息
        System.out.println(c1 + " :" + c1.getName());//class com.demo.reflect.Student :com.demo.reflect.Student
        System.out.println(c2 + " :" + c2.getName());//class com.demo.reflect.Student :com.demo.reflect.Student
        System.out.println(c3 + " :" + c3.getName());//class com.demo.reflect.Student :com.demo.reflect.Student

        //比较每一个Class对象是否一样
        System.out.println(c1 == c2); //true
        System.out.println( c2 == c3);   //true
        //可以知道 :任意类有且仅有一个class对象
    }
}

class Student { }

三种方式区别:

第一种,使用 .class 方法。

  • 说明:仅适合在编译前就已经明确要操作的 Class
  • 缺点: 要导入类的包,依赖太强,不导包就抛编译错误

第二种,使用类对象的 getClass() 方法。

  • 适合有对象示例的情况下
  • 缺点: 对象都有了还要反射干什么

第三种,使用 Class.forName 静态方法。

  • 前提:已明确类的全路径名。
  • 缺点: 只能用于引用类型,所谓类的完整路径是:包名.类名 例如:java.lang.String。

常用第三种方式创建Class对象: 这种方式参数为一个字符串可以直接传入也可读取在配置文件中等多种方法。

3.Class对象常用方法

3.1.获取Class类对应的实体类的相关的Class类的方法

方法 描述
Class<?>[] getSuperclass() 获取当前Class对象所有的父类(获取的类没有继承任何父类的,都默认获取object类)
Class<?>[] getClasses() 返回类定义的公共的内部类,以及从父类、父接口那里继承来的内部类
Class<?>[] getDeclaredClasses() .返回类中定义的公共、私有、保护的内部类

getSuperclass()

public static void main(String[] args) throws ClassNotFoundException
{
    Class<String> strClass = (Class<String>) Class.forName("java.lang.String");
    // 返回调用类的父类
    Class<?> superClass = strClass.getSuperclass();
    System.out.println("当前实体类的Class类    :"+strClass);
    System.out.println("实体类的父类的Class类:"+superClass);
}

//当前实体类的Class类    :class java.lang.String
//实体类的父类的Class类:class java.lang.Object

getClasses()和getDeclaredClasses()

Person类

public class Person{
	public class PA{};
	private class PB{};
	public interface PIA{};
	private interface PIB{};
}

Student类

public class Student extends Person{
	//公共的内部类
	public class A{}
	//保护内部类
	protected class B{}
	//默认内部类
	class C{}
	//私有内部类:
	private class D{}
	//共有静态内部类
	public static class E{}
	//共有内部接口
	public interface IA{}
	//保护内部接口
	protected interface IB{}
	//默认内部接口
	interface IC{}
	//私有内部接口
	private interface ID{}
}

main方法

public static void main(String[] args) throws ClassNotFoundException{
	Class<String> stuClass = (Class<String>) Class.forName("reflect.Student");
	
	//获取调用类的所有公共的内部类和接口,包括继承的共有的内部类和接口的Class
	System.out.println(stuClass.getName()+"的公有内部类和接口(包括继承):");
	Class[]   strClasses=stuClass.getClasses();
	for (Class class1 : strClasses){
		System.out.println(class1.getName());
	}
	
	System.out.println("#-------------------------");
	
	System.out.println(stuClass.getName()+"的所有内部类和接口(包括继承):");
	Class[]   stuAllClasses=stuClass.getDeclaredClasses();
	for (Class class1 : stuAllClasses) {
		System.out.println(class1.getName());
	}
}

执行结果:

reflect.Student的公有内部类和接口(包括继承):
reflect.Student$A
reflect.Student$E
reflect.Student$IA
reflect.Person$PA
reflect.Person$PIA
#-------------------------
reflect.Student的所有内部类和接口(包括继承):
reflect.Student$A
reflect.Student$B
reflect.Student$C
reflect.Student$D
reflect.Student$E
reflect.Student$IA
reflect.Student$IB
reflect.Student$IC
reflect.Student$ID

返回一个成员内部类/属性/方法/构造器所在的类的Class,这些方法是上面那两个方法的逆操作

java.lang.reflect.Class.getDeclaringClass()    ;//返回一个成员内部类所在的类的Class
java.lang.reflect.Field.getDeclaringClass()      ;//返回一个字段所在的类的Class
java.lang.reflect.Method.getDeclaringClass()    ;//返回一个方法所在的类的Class
java.lang.reflect.Constructor.getDeclaringClass() ;//返回一个构造器所在的类的Class

3.2.获取构造函数的方法

方法 描述
Constructor getConstructor(Class[] params) 根据指定参数获得(子类或者继承自父类)public构造器
Constructor[] getConstructors() 获得(子类或者继承自父类)的所有public的构造器
Constructor getDeclaredConstructor(Class[] params) 根据指定参数获得本类(不包括父类)public和非public的构造器
Constructor[] getDeclaredConstructors() 获得本类(不包括父类)所有public和非public的构造器

3.3.获取类方法的方法

方法 描述
Method getMethod(String name, Class[] params) 根据方法名,参数类型获得(子类或者继承自父类)public的方法
Method[] getMethods() 获得所有(子类或者继承自父类)的public方法
Method getDeclaredMethod(String name, Class[] params) 根据方法名和参数类型,获得本类(不包括父类)public和非public的方法
Method[] getDeclaredMethods() 获得本类(不包括父类)所有的public和非public方法

3.4.获取类中属性的方法

方法 描述
Field getField(String name) 根据名字得到(子类或者继承自父类)中相应的public变量
Field[] getFields() 获得类中所有(子类或者继承自父类)中public的变量
Field getDeclaredField(String name) 根据名字获得本类(不包括父类)public和非public变量
Field[] getDeclaredFields() 获得本类所有(不包括父类)的public和非public变量

3.5.获取类中注解的方法

方法 描述
<A extends Annotation> [] getAnnotation(Class< A >annotationClass) 返回指定元素上存在所有(子类或者继承自父类)注解
Annotation[] getAnnotations() 返回此元素上存在所有(子类或者继承自父类)注解
Annotation[] getDeclaredAnnotations() 返回此元素上存在所有(不包括父类)注解
<A extends Annotation> getDeclaredAnnotation(Class<A> annotationClass) 返回指定元素上存在所有(不包括父类)注解
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
<A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass): 由于Java8增加了重复注解,所以需要使用此方法获取修饰该元素、指定类型的多个Annotation。
<A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A>annotationClass) 由于Java8增加了重复注解,所以需要使用此方法获取直接修饰该元素、指定类型的多个Annotation。
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果此元素上存在指定类型的注解,则返回true,否则返回false。

如果需要获取某个注解里的元数据,则可以将注解强制类型转换为所需的注解类型,然后通过注解对象的抽象方法来访问这些元数据。如((MyTag) e).name();
为了让注解起作用,必须为这些注解提供一个注解处理工具方法。

3.6.获取接口的方法

方法 描述
Class<?> [] getInterfaces() 获取由此对象表示的类或接口实现的所有接口
Type[] getGenericInterfaces() 获取由此对象表示的类或接口直接实现的接口的Type

getInterfaces:主要是 获取由此对象表示的类或接口实现的接口
getGenericInterfaces: 主要是 获取由此对象表示的类或接口直接实现的接口的Type。
区别在于getGenericInterfaces可以返回其参数化类型,例如: Collection、 List中的String和Coupon

Java反射注解妙用(获取所有接口说明)

3.7.返回字符串(String)的方法

方法 描述
String getCanonicalName() 返回 Java Language Specification 中所定义的底层类的规范化名称
String getName() 获取当前Class表示的类的完整名字:(包名.类名)
String getSimpleName() 返回源代码中给出的底层类的简称。
String toString() 将对象转换为字符串。
public static void main(String[] args) throws ClassNotFoundException{
	Class<String> strClass = (Class<String>) Class.forName("java.lang.String");
	System.out.println("当前Class表示的实体的      规范化名字:"+strClass.getCanonicalName());
	System.out.println("当前Class表示的实体的          完整名字:"+strClass.getName());
	System.out.println("当前Class表示的实体的                  简称:"+strClass.getSimpleName());
	System.out.println("当前Class表示的实体的toString():"+strClass.toString());
}

//当前Class表示的实体的      规范化名字:java.lang.String
//当前Class表示的实体的          完整名字:java.lang.String
//当前Class表示的实体的                  简称:String
//当前Class表示的实体的toString():class java.lang.String

3.8.判断当前类是什么类的方法

方法 描述
boolean isLocalClass() 判断是不是局部类,也就是方法里面的类
boolean isMemberClass() 判断是不是成员内部类,也就是一个类里面定义的类
boolean isAnonymousClass() 判断当前类是不是匿名类,匿名类一般用于实例化接口
public class ClassTest{  
    public static void main(String[] args) {  
        ClassTest son = new ClassTest();  
 
        //测试匿名类  
        son.testAnonymous(new AnonymousClass() {  
            @Override  
            public void test() {  
                System.out.println("AnonymousClass是成员类:-> " + this.getClass().isMemberClass());  
                System.out.println("AnonymousClass是匿名类: -> " + this.getClass().isAnonymousClass());  
                System.out.println("AnonymousClass是局部类:-> " + this.getClass().isLocalClass());  
                System.out.println("#---------------------------------------");  
            }  
        });  
        //测试成员类  
        son.testMember();  
        //测试静态成员类  
        new StaticMemberClass();  
        //测试局部类  
        class LocalClass{  
            public LocalClass(){  
                System.out.println("LocalClass是成员类:-> " + this.getClass().isMemberClass());  
                System.out.println("LocalClass是匿名类: -> " + this.getClass().isAnonymousClass());  
                System.out.println("LocalClass是局部类:-> " + this.getClass().isLocalClass());  
                System.out.println("#---------------------------------------");  
            }  
        }  
        new LocalClass();  
    }  
    //测试匿名内部类
    private void testAnonymous(AnonymousClass inner) {  
        inner.test();  
    }  
    //测试成员内部类:
    private void testMember() {  
        new MemberClass();  
    }  
      
    /** 
     * 接口,用于测试匿名类
     */  
    interface AnonymousClass{  
        public void test();  
    }  
      
    /** 
     * 静态成员类 
     */  
    static class StaticMemberClass{  
        public StaticMemberClass() {  
            System.out.println("StaticMemberClass是成员类:-> " + this.getClass().isMemberClass());  
            System.out.println("StaticMemberClass是匿名类: -> " + this.getClass().isAnonymousClass());  
            System.out.println("StaticMemberClass是局部类:-> " + this.getClass().isLocalClass()); 
            System.out.println("#---------------------------------------");  
        }  
    }  
    /** 
     * 成员类 
     */  
class MemberClass{  
   public MemberClass() {  
        	 System.out.println("MemberClass是成员类:-> " + this.getClass().isMemberClass());  
             System.out.println("MemberClass是匿名类: -> " + this.getClass().isAnonymousClass());  
             System.out.println("MemberClass是局部类:-> " + this.getClass().isLocalClass());  
            System.out.println("#---------------------------------------");  
        }  
    }  
}  

测试结果:

AnonymousClass是成员类:-> false
AnonymousClass是匿名类: -> true
AnonymousClass是局部类:-> false
#---------------------------------------
MemberClass是成员类:-> true
MemberClass是匿名类: -> false
MemberClass是局部类:-> false
#---------------------------------------
StaticMemberClass是成员类:-> true
StaticMemberClass是匿名类: -> false
StaticMemberClass是局部类:-> false
#---------------------------------------
LocalClass是成员类:-> false
LocalClass是匿名类: -> false
LocalClass是局部类:-> true
#---------------------------------------

3.9.其他判断方法

方法 描述
boolean isAnnotation() 判断当前Class对象是否是注释类型
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
boolean isAssignableFrom(Class<?> cls) 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是该类或接口的父类或父接口。
boolean isEnum() 当且仅当该类声明为源代码中的枚举时返回 true。
boolean isArray() 当前元素是数组类时返回true。
boolean isInstance(Object obj) 判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。
boolean isInterface() 判定指定的 Class 对象是否表示一个接口类型。
boolean isPrimitive() 判定指定的 Class 对象是否表示一个基本类型。
boolean isSynthetic() 如果此类是复合类,则返回 true,否则 false。

3.10.其他常用方法

方法 描述
ClassLoader getClassLoader() 返回该类的类加载器
Package getPackge() 获取此类的包
URL getResource(String name) 通过传入的文件名去获取对应文件
InputStream getResourceAsStream(String name) 通过传入的文件名去获取对应资源

Java中getResourceAsStream的用法
getResource和getResourceAsStream

4.反射生成java对象的两种方式

4.1.使用Class对象.newInstance()获取对应实例

	Object o = clazz.newInstance();

newInstance()默认调用无参构造方法 ,若是没有,则会报异常

没有无参构造函数异常:
在这里插入图片描述
私有的构造函数异常:
在这里插入图片描述

4.2.通过Class获取构造器Constructor

有带参数的构造函数的类,先获取到其构造对象,再通过该构造方法类获取实例:

//获取构造函数类的对象
Constroctor constroctor = User.class.getConstructor(String.class); 

// 使用构造器对象的newInstance方法初始化对象
Object obj = constroctor.newInstance("name"); 

4.3.举个栗子

User类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private  Integer age;
}

import java.lang.reflect.Constructor;
public class TestReflection {
 
    public static void main(String[] args) {
//      第一、通过Class.forName方式
        Class clazz1 = null;
        try {
            clazz1 = Class.forName("com.demo.reflect.createObj.User");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
 
//      第二、通过对象实例方法获取对象
        Class clazz2 = User.class;
 
//      第三、通过Object类的getClass方法
        User user = new User();
        Class clazz3 = user.getClass();
 
        System.out.println(clazz1);
        System.out.println(clazz2);
        System.out.println(clazz3);

        //第一种调用Class对象newInstance()方式创建对象
        User user1 = null;
        try {
             user1 =(User) clazz1.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        user1.setName("齐天大圣");
        user1.setAge(500);
        System.out.println("user1:"+user1.toString());


        //第二种获取Class的构造器对象Constructor方式创建对象
        User user2 = null;
        try {
            // 获取构造函数
            Constructor constroctor = clazz2.getConstructor(String.class,Integer.class);
            // 通过构造器对象的newInstance方法进行对象的初始化
            user2 = (User) constroctor.newInstance("猪八戒",1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("user2:"+user2.toString());
 
    }
}

执行结果:

class com.demo.reflect.createObj.User
class com.demo.reflect.createObj.User
class com.demo.reflect.createObj.User
user1:User(name=齐天大圣, age=500)
user2:User(name=猪八戒, age=1000)

示例类(以下代码以这个类为基准)

import java.sql.Timestamp;
public class Question {
	private Integer id;
	private String content;
	private Timestamp  creationDate;
	public String userName;
	
	public Question() {}
	public Question(Integer id, String content, Timestamp creationDate) {
		super();
		this.id = id;
		this.content = content;
		this.creationDate = creationDate;
	}
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Timestamp getCreationDate() {
		return creationDate;
	}
	public void setCreationDate(Timestamp creationDate) {
		this.creationDate = creationDate;
	}
}

四.java.lang.reflect.Constuctor

1.Constuctor是什么?能做什么?

是什么 ?

  • 构造器的描述对象,描述着指定类的构造器

能做什么

  • 可以通过其newInstance()方法来创建对象

2.Constuctor的常用方法

方法 描述
Class<?>[] getParameterTypes() 按照声明顺序以Class数组的形式获得该构造方法的各个参数的类型
boolean equals(Object obj) 将其Constructor与指定对象进行比较。
<T extends Annotation> T getAnnotation(Class<T> annotationClass) 如果该构造器对象存在指定类型的注解,则返回该注解,否则返回null
Annotation[] getAnnotations() 返回该构造器对象上的所有注解,如果没有注解,则返回空数组
T getDeclaredAnnotation(Class annotationClass) 如果该构造器对象存在指定类型的注解,则返回该注解,否则返回 null
Annotation[] getDeclaredAnnotations() 返回该构造器对象上的所有注解,如果没有注解,则返回空数组
T[] getAnnotationsByType(Class annotationClass) 如果该构造器对象存在指定类型的注解,则返回该注解数组,否则返回 null
T[] getDeclaredAnnotationsByType(Class annotationClass) 如果该构造器对象存在指定类型的注解,则返回该注解数组,否则返回 null
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果该构造器对象上有指定类型的注解,则返回 true,否则为 false
setAccessible(boolean bool) 1.设置为true调用非public方法,此外,setAccessible(true)可能会失败。
2.如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。
getModifiers() 获得可以解析出该方法所采用修饰符的整数,它是一个int,不同的bit表示不同的含义
Class<?>[] getExceptionTypes() 以Class数组的形式获得该方法可能抛出的异常类型

3.反射创建对象实现步骤

//第一步:获取class对象
         Class clazz = Class.forName("com.panshi.Foo");  // clazz对象是Foo的描述
//第二步:通过class对象获取到其构造器描述
         Constructor constructor = clazz.getConstructor([参数类型列表]);
//第三步:调用构造器描述的newInstance来创建实例对象
         Foo foo = constructor.newInstance([参数列表]);

具体栗子:
有参构造器实例化对象

//1.获取class对象
Class<Question> clazz=(Class<Question>) Class.forName("com.reflect.test.Question");
//2.通过class对象获取到构造器
Constructor<Question> constructor=clazz.getConstructor(Integer.class,String.class,Timestamp.class);
//3.调用构造器的 newInstance()来创建实例
Question question=(Question) constructor.newInstance(1,"我要进华为",new Timestamp(System.currentTimeMillis()));
//4.打印结果
System.out.println(question.getContent());
//我要进华为

无参构造器实例化(简化)(调用无参构造器实例化)

//Class clazz = Foo.class;
//Foo foo = clazz.newInstance();

具体栗子:

 //1.获取class对象
 Class<Question> clazz=(Class<Question>) Class.forName("com.reflect.test.Question");
//2.通过class对象直接创建实例
 Question question=clazz.newInstance();
//4.打印结果
 question.setContent("111111");
 System.out.println(question.getContent());
//  111111

4.举个栗子

/**
     * 打印类的构造方法
     */
    public static void printClassConstructor(Object obj) {
        //要获取类的信息,首先要获取类的类类型

        Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
        //获取类的名称
        System.out.println("类的名称是:" + c.getName());

        /**
         * 构造函数也是对象
         * java.lang.Constructor中封装了构造函数的信息
         * getConstructor()方法获取所有的public的构造函数
         * getDeclaredConstructors得到所有的构造函数
         */
        Constructor[] cs = c.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            System.out.print(constructor.getName() + "(");
            //获取构造函数的参数列表---》得到的是参数列表的类类型
            Class[] paramTypes = constructor.getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName() + ",");
            }
            System.out.println(")");
        }
    }
    @Test
    public void testPrintClassMessage() {
        printClassConstructor(new StringBuffer());
    }

执行结果:
在这里插入图片描述

五.java.lang.reflect.Method

1.Method是什么?能做什么?

是什么 ?

  • 方法的描述对象,描述着指定类的方法

能做什么 ?

  • 允许通过invoke()方法来动态调用对象 (invoke调用的意思)

2.Method的常用方法

方法 描述
String getName() 返回方法名称,例如:“getScore”
Class<?>[] getParameterTypes() 按照声明顺序以Class数组的形式获得该方法的各个参数的类型
Class<?> getReturnType() 以Class对象的形式获得该方法的返回值的类型,也是一个Class实例,例如:String.class
invoke(Object obj, Object… args) 利用指定参数args执行指定对象obj中的该方法,返回值为object型。
<T extends Annotation> T getAnnotation(Class<T> annotationClass) 如果该方法对象存在指定类型的注解,则返回该注解,否则返回null
Annotation[] getAnnotations() 返回该方法对象上的所有注解,如果没有注解,则返回空数组
T getDeclaredAnnotation(Class annotationClass) 如果该方法对象存在指定类型的注解,则返回该注解,否则返回 null
Annotation[] getDeclaredAnnotations() 返回该方法对象上的所有注解,如果没有注解,则返回空数组
T[] getAnnotationsByType(Class annotationClass) 如果该字方法对象存在指定类型的注解,则返回该注解数组,否则返回 null
T[] getDeclaredAnnotationsByType(Class annotationClass) 如果该方法对象存在指定类型的注解,则返回该注解数组,否则返回 null
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果该方法对象上有指定类型的注解,则返回 true,否则为 false
setAccessible(boolean bool) 1.设置为true调用非public方法,此外,setAccessible(true)可能会失败。
2.如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。
getModifiers() 获得可以解析出该方法所采用修饰符的整数,它是一个int,不同的bit表示不同的含义
isVarArgs() 查看该构造方法是否允许带有可变参数,允许为true
Class<?>[] getExceptionTypes() 以Class数组的形式获得该方法可能抛出的异常类型

3.反射调用方法实现步骤

如何获取某个方法

Method m = c.getDeclaredMethod("方法名",可变参数列表(参数类型.class)

方法的名称和方法的参数列表才能唯一决定某个方法

方法的反射操作

//1.调用有参方法
m.invoke(对象,参数列表)

//2.调用无参方法
m.invoke(对象,null)

如果调用的是私有方法那么需要暴力访问

//1.Class对象.getDeclaredMethod()

//2. m.setAccessiable(true);

方法如果没有返回值,返回null,如果有返回值返回Object类型,然后再强制类型转换为原函数的返回值类型

/**
 * 反射获取无参数成员方法并运行
 *  步骤:
 *      1.获取class对象中所有的public成员方法
 *          Method[] getMethods() 获取的是class文件中所有的成员方法,包括继承的方法
 *          Method类是描述成员方法的对象
 *      2.获取class对象中指定的public成员方法
 *          Method getMethod("字符串类型的方法名",参数列表)
 *      3.执行,使用Method类中的方法,运行所获取的方法
 *          Object invoke(Object obj , Object ... o)
 */



//第一步: 获取class对象
Class clazz = Class.forName("com.panshi.Foo");  // clazz对象是Foo的描述

//第二步: 通过class对象获取到指定的方法描述
Method method = clazz.getMethod("setName", String.class);

//第三步: 反射调用
method.invoke(foo,"小明"); // 等同于  foo.setName("小明");

具体栗子:

	   //第一步获取class对象
		Class<Question> clazz=(Class<Question>) Class.forName("com.reflect.test.Question");
		
		Question question=clazz.newInstance();
		
		//第二步 获取class对象获取到指定的方法描述
		Method method=clazz.getMethod("setContent", String.class);
		
		//第三步:反射调用
		method.invoke(question,"我要上王者");
		//打印结果
     System.out.println(question.getContent());
     //  我要上王者  说明 我们调用了setContent()方法并为它传入了参数

4.举个栗子

    /**
     * 打印类的方法(出参,入参)
     */
    public static void printClassMethod(Object obj) {
        //要获取类的信息,首先要获取类的类类型

        Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
        //获取类的名称
        System.out.println("类的名称是:" + c.getName());

        /*
         * Method类,方法的对象
         * 一个成员方法就是一个Method对象
         * getMethods()方法获取的是所有的public的函数,包括父类继承而来的
         * getDeclaredMethods()获取的是多有该类自己声明的方法,不问访问权限
         */
        Method[] ms = c.getMethods();//c.getDeclaredMethods();
        for (int i = 0; i < ms.length; i++) {
            //得到方法的返回值类型的类类型
            Class retrunType = ms[i].getReturnType();
            System.out.print(retrunType.getName() + " ");

            //得到方法的名称
            System.out.print(ms[i].getName() + "(");

            //获取的参数类型--->得到的是参数列表的类型的类类型
            Class[] paraTypes = ms[i].getParameterTypes();
            for (Class class1 : paraTypes) {
                System.out.print(class1.getName() + ",");
            }
            System.out.println(")");
        }
    }
    
	@Test
    public void  testPrintClassMessage(){
        printClassMethod(new Object());
    }

执行结果:
在这里插入图片描述

六.java.lang.reflect.Field

1.Fidle是什么?能做什么?

是什么 ?

  • 提供有关类或接口的单个字段的信息

能做什么 ?

  • 允许通过get,set方法来动态取值,设值

2.Field的常用方法

方法 描述
String getName() 返回方字段名称
Class<?> getType() 返回字段类型,也是一个Class实例 (擦除泛型)例如,String.class
AnnotatedType getAnnotatedType() 1.返回一个 AnnotatedType 对象,该对象表示使用类型来指定由该字段对象表示的字段的类型
2.通过其 getType() 方法,我们可以获取到对应的字段类型
<T extends Annotation> T getAnnotation(Class<T> annotationClass) 如果该字段对象存在指定类型的注解,则返回该注解,否则返回null
Annotation[] getAnnotations() 返回该字段对象上的所有注解,如果没有注解,则返回空数组
T getDeclaredAnnotation(Class annotationClass) 如果该字段对象存在指定类型的注解,则返回该注解,否则返回 null
Annotation[] getDeclaredAnnotations() 返回该字段对象上的所有注解,如果没有注解,则返回空数组
T[] getAnnotationsByType(Class annotationClass) 如果该字段对象存在指定类型的注解,则返回该注解数组,否则返回 null
T[] getDeclaredAnnotationsByType(Class annotationClass) 如果该字段对象存在指定类型的注解,则返回该注解数组,否则返回 null
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果该字段对象上有指定类型的注解,则返回 true,否则为 false
setAccessible(boolean bool) 1.设置为true调用非public方法,此外,setAccessible(true)可能会失败。
2.如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。
getModifiers() 获得可以解析出该方法所采用修饰符的整数,它是一个int,不同的bit表示不同的含义
Class<?>[] getExceptionTypes() 以Class数组的形式获得该方法可能抛出的异常类型

3.反射获取字段实现步骤

如何获取某个字段

Field f.getDeclaredField("字段名")

字段的反射操作

//——>取值
//方式1.获取obj对象该Field的字段值(可以是基本类型也可以是引用类型)
Object value = f.get(Object obj); 

//方式2.获取obj对象该Field的字段值(只能为基本类型)
xxx getXxx(Object obj)//此处的xxx表示8个基本数据类型 如 getInt(),getDouble()


//——>赋值
//方式1. 将obj对象的该Field字段设置成val值(可以是基本类也可以是引用类型)
field.set(Object obj, Object val);  // 等同于 user.name = "小明";

//方式2. 将obj对象的该Field字段设置成val值(只能是引用类型)
//void setXxx(Object obj,xxx val):

如果调用的是私有方法那么需要暴力访问

//1.Class对象.getDeclaredField()

//2. f.setAccessiable(true);

栗子:

/**
 * 反射获取成员变量值,并修改值
 *  Class类中的方法:
 *      1.getFields(),返回值为Field[]
 *          获取所有成员变量,Field类为表述成员变量的类
 *      2.getField(字符串类型的变量名),返回值为Field
 *          获取指定成员变量
 *  Field类中的方法:
 *      1.void set(Object obj,Object value)
 *          用来修改成员变量,前者为对象,后者为值
 */
 
			//第一步 获取class对象
			Class clazz=Class.forName("com.reflect.test.Question");
			//第二步: 通过class对象获取到字段描述
			Field field=clazz.getDeclaredField("userName");

			Question question= clazz.newInstance();
			//反射调用
            // 1.使用set方法()赋值
			field.set(question,"我是字段,我设值");
			
            //2.使用get方法()取值
            Object value=field.get(question);
			System.out.println(value);//打印 我是字段,我设值
        // 说明:set()设值成功,get()方法 取值成功

4.举个栗子

/**
     * 打印类的成员变量(类型,名称)
     */
    public static void printClassField(Object obj) {
        //要获取类的信息,首先要获取类的类类型

        Class c = obj.getClass();//传递的是哪个子类的对象,c就是该子类的类类型
        //获取类的名称
        System.out.println("类的名称是:" + c.getName());

        /**
         * 成员变量也是对象,是java.lang.reflect.Field这个类的的对象
         * Field类封装了关于成员变量的操作
         * getFields()方法获取的是所有public的成员变量的信息
         * getDeclareFields()方法获取的是该类自己声明的成员变量的信息
         */
        Field[] fs = c.getDeclaredFields();
        for (Field field : fs) {
            //得到成员变量的类型的类类型
            Class fieldType = field.getType();
            String typeName = fieldType.getName();
            //得到成员变量的名称
            String fieldName = field.getName();
            System.out.println(typeName + " " + fieldName);
        }
    }
    
    @Test
    public void testPrintClassMessage() {
        printClassField(new HashMap<>());
    }

执行结果:
在这里插入图片描述

七.反射使用方式

1.反射来获取泛型信息

通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public。获得Field对象后都可以使用getType()来获取其类型。

Class<?> type = f.getType();//获得字段的类型

但此方法只对普通Field有效,若该Field有泛型修饰,则不能准确得到该Field的泛型参数,如Map<String,Integer>;

为了获得指定Field的泛型类型,我们采用:

Type gType = f.getGenericType();得到泛型类型

然后将Type对象强转为ParameterizedType,其表示增加泛型后的类型

Type getRawType()//返回被泛型限制的类型;
Type[]  getActualTypeArguments()//返回泛型参数类型;

利用反射来获取泛型的类型(泛型信息)
步骤:

  • 获取当前类
  • 获取目标字段
  • 获取包含泛型类型的类型 getGenericType()
  • 强转至子类ParameterizedType 因为Type没有任何对应的方法
  • 获得泛型真正的类型 getActualTypeArguments()
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
public class GetGenericTypeDemo14 {
   Map<String,Integer> map = new HashMap<String,Integer>();
  
   public static void main(String[] args) throws Exception {
      Class c = GetGenericTypeDemo14.class;
      Field f = c.getDeclaredField("map");
      System.out.println(f);
      System.out.println(f.getName());//map
     
      // Class<?> getType()  返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
      Class cl = f.getType();
      System.out.println("获得其类型:"+cl);
//获得其类型:interface java.util.Map
    
      /**
       *  Type getGenericType() 返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。
       *  Type是Class的接口;
       */
      Type t = f.getGenericType();//包含泛型的类型
      System.out.println(t);
//java.util.Map<java.lang.String, java.lang.Integer>
     
      /**
       * Type这个类里面没有任何的方法,所以需要调用子类的方法,那么大的类型转到小的类型,需要强转!
       */
      ParameterizedType pt = (ParameterizedType)t;//强转到其子类
      /**
       *  Type[] getActualTypeArguments()
                   返回表示此类型实际类型参数的 Type对象的数组。
          Type getOwnerType()
                   返回 Type 对象,表示此类型是其成员之一的类型。
          Type getRawType()
                   返回 Type 对象,表示声明此类型的类或接口。
       */
     
      t = pt.getRawType();//类型的类或接口
      System.out.println(t);
     
      Type[] ts = pt.getActualTypeArguments();
      for (Type type : ts) {
         System.out.println(type);
         /**
          *  class java.lang.String
             class java.lang.Integer
          */
      }
   }
}

打印:
java.util.Map junereflect624.GetGenericTypeDemo14.map
map
获得其类型:interface java.util.Map
java.util.Map<java.lang.String, java.lang.Integer>
interface java.util.Map
class java.lang.String
class java.lang.Intege

2.泛型擦除

  • 定义集合类,泛型String,要求向集合中添加Integer类型。
  • 集合类的泛型为String,向集合添加Integer类型数据会编译失败。
  • 伪泛型:编译后的class文件是没有泛型的。
  • 想法:绕过泛型,直接调用class文件中的add方法。
    步骤:
    • 获取ArrayList类的class文件对象。
    • 获取ArrayList.class文件中的方法add()。
    • 向其中添加字符串元素。
import java.lang.reflect.Method;
import java.util.ArrayList;

public class GenericErasure{
    public static void main(String[] args) throws Exception {
        ArrayList<String> list = new ArrayList<>();
        list.add("abc");
        list.add("def");
        //获取ArrayList类的class文件对象
        Class<? extends ArrayList> c1 = list.getClass();
        //获取ArrayList.class文件中的方法add()
        Method add = c1.getMethod("add",Object.class);
        System.out.println(add);
        //向其中添加字符串元素
        add.invoke(list,1);
        System.out.println(list);
    }
}

3.反射通过配置文件运行功能的实现

  • 调用某类的某个方法,不清楚哪个类的哪个方法。
  • 通过配置文件实现此功能:
    • 运行的类名与方法名,以键值对的形式写在文本中。
    • 运行哪个类,读取配置文件即可。
  • 实现步骤:
    1. 准备配置文件,键值对的形式。
    2. IO流读取配置文件 Reader。
    3. 将文件中的键值对存储到集合中Properties(集合中保存的键值对就是要运行的类名与方法)。
    4. 反射获取指定类的class文件对象。
    5. 通过class文件对象,获取指定的方法。
    6. 运行方法。
//测试类1
public class Person {
    public void eat(){
        System.out.println("人在吃饭");
    }
}

//测试类2
public class Student {
    public void study(){
        System.out.println("学生在学习");
    }
}
className=cn.mrzhang.demo2.Student
methodName=study

#className=cn.mrzhang.demo2.Person
#methodName=job
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 调用3个类中一个类的方法
 *  不清楚调用哪个类中的哪个方法,不能修改代码
 *
 *      通过配置文件实现此功能
 *          运行的类名与方法名,以键值对的形式写在文本中
 *          运行哪个类,读取配置文件即可
 *      实现步骤:
 *          1.准备配置文件,键值对的形式
 *          2.IO流读取配置文件 Reader
 *          3.将文件中的键值对存储到集合中Properties
 *              集合中保存的键值对就是要运行的类名与方法名
 *          4.反射获取指定类的class文件对象
 *          5.通过class文件对象,获取指定的方法
 *          6.运行方法
 */
public class TestReflectConfig {
    public static void main(String[] args) throws Exception {
        //IO流读取配置文件
        InputStream resourceAsStream = TestDemo2.class.getClassLoader().getResourceAsStream("config.properties");
        //创建集合对象
        Properties p = new Properties();
        //调用方法load传递流对象
        p.load(resourceAsStream);
        //释放流对象
        resourceAsStream.close();
        //通过键获取值
        String className = p.getProperty("className");
        String methodName = p.getProperty("methodName");
        //反射获取指定类的class文件对象
        Class<?> c1 = Class.forName(className);
        Object obj = c1.newInstance();
        //反射获取指定的方法
        Method method = c1.getMethod(methodName);
        //执行方法
        method.invoke(obj);
    }
}

4.使用反射获取类、方法、属性上的注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    public int id() default -1;
    public String msg() default "Hi";
 
}


public @interface Check {
    String value();
}

public @interface Perform {}
 

@TestAnnotation(msg="hello")
public class Test {
    @Check(value="hi")
    int a;
 
    @Perform
    public void testMethod(){}
 
    @SuppressWarnings("deprecation")
    public void test1(){
        Hero hero = new Hero();
        hero.say();
        hero.speak();
    }
 
    public static void main(String[] args) {
        boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
 
        if ( hasAnnotation ) {
            TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
            //获取类的注解
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
        
        try {
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);
            //获取一个成员变量上的注解
            Check check = a.getAnnotation(Check.class);
 
            if ( check != null ) {
                System.out.println("check value:"+check.value());
            }
 
            Method testMethod = Test.class.getDeclaredMethod("testMethod");
 
            if ( testMethod != null ) {
                // 获取方法中的注解
                Annotation[] ans = testMethod.getAnnotations();
                for( int i = 0;i < ans.length;i++) {
                    System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (SecurityException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

5.使用反射映射Jdbc的结果集

数据表

CREATE TABLE `user` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(50) DEFAULT '',
  `pwd` varchar(50) DEFAULT '',
  `age` tinyint(2) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

用户类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
    private int age;
 
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                ", age=" + age +
                '}';
    }
}

获取数据库连接简易工具类

public class ConnectDBFactory {
    public static  Connection getDBConnection(){
        Connection conn = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=gbk&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Hongkong  ";
            String user = "root";
            String password = "root";
            conn = DriverManager.getConnection(url,user,password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
}

反射处理的Jdb-c新增/查询映射工具

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SqlSession {
    public static String getSaveObjectSql(Object o) throws InvocationTargetException, IllegalAccessException {

        String sql = "insert into ";
        /*获取Class对象*/
        Class c = o.getClass();
        /*获取pojo所有的方法*/
        Method[] methods = c.getDeclaredMethods();
        /*获取全类名*/
        String cName = c.getName();
        /*通过全类名获取数据库名称*/
        String tableName = cName.substring(cName.lastIndexOf(".") + 1, cName.length());
        sql += tableName + "(";
        /*字段名字*/
        List<String> fieldList = new ArrayList<>();
        /*字段对应的值*/
        List valueList = new ArrayList();

        /*遍历Class对象的Method对象,就可以执行相对于的方法了*/
        for (Method method :
                methods) {
            String methodName = method.getName();
            /*找出get方法,并设置值*/
            if (methodName.startsWith("get") && !method.equals("getClass")) {
                String fieldName = methodName.substring(3, methodName.length());
                fieldList.add(fieldName);
                Object res = method.invoke(o, null);
                if (res instanceof String) {
                    valueList.add("\"" + res + "\"");
                } else {
                    valueList.add(res);
                }
            }
        }

        /*拼接sql语句的字段*/
        for (int i = 0; i < fieldList.size(); i++) {
            if (i < fieldList.size() - 1) {
                sql += fieldList.get(i) + ",";
            } else {
                sql += fieldList.get(i) + ") values (";
            }
        }

        /*拼接sql语句的值*/
        for (int i = 0; i < valueList.size(); i++) {
            if (i < valueList.size() - 1) {
                sql += valueList.get(i) + ",";
            } else {
                sql += valueList.get(i) + ")";
            }
        }

        return sql;
    }


    /*保存数据的操作*/
    public int saveObject(Object o) throws InvocationTargetException, IllegalAccessException, SQLException {
        Connection connection = ConnectDBFactory.getDBConnection();
        String sql = getSaveObjectSql(o);
        PreparedStatement statement = connection.prepareStatement(sql);
        int i = 0;
        i = statement.executeUpdate();
        return i;
    }

    /*
     * 查询数据,查询出来的数据映射到pojo的每一个属性上
     * */
    public List<Object> getObject(String pname, int id) throws ClassNotFoundException {
        List<Object> list = new ArrayList<>();

        /*通过包名获取数据表名*/
        String tableName = pname.substring(pname.lastIndexOf(".") + 1, pname.length());
        String sql = "select * from " + tableName + " where Id = " + id;

        Connection conn = ConnectDBFactory.getDBConnection();
        Class c = Class.forName(pname);
        Object obj = null;
        try {
            Statement statement = conn.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            Method[] methods = c.getDeclaredMethods();

            while (resultSet.next()) {
                obj = c.newInstance();
                for (Method method : methods
                ) {
                    String methodName = method.getName();
                    if (methodName.startsWith("set")) {
                        /*通过方法名获取数据库的列名*/
                        String columnName = methodName.substring(3, methodName.length());
                        /*获取参数的类型*/
                        Class[] params = method.getParameterTypes();
                        /*判断参数的类型*/
                        if (params[0] == String.class) {
                            method.invoke(obj, resultSet.getString(columnName));
                        }
                        if (params[0] == int.class) {
                            method.invoke(obj, resultSet.getInt(columnName));
                        }
                    }
                }
                list.add(obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }


    public static void main(String[] args) {
        try {
            SqlSession session = new SqlSession();

            //新增
            User user = new User();
            user.setAge(22);
            user.setName("JiemingLi");
            user.setId(44);
            user.setPwd("123456");
            int resNum  = session.saveObject(user);
            if(resNum > 0){
                System.out.println("成功");
            }else{
                System.out.println("插入失败");
            }

            //查询
            List<Object> list = session.getObject("com.demo.reflect.jdbc.User", 44);
            System.out.println(list.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6.调用方法的反射工具类

	public static Object setMethod(String className,String methodName,Object[] valueArr,Class[] classArr) throws Exception, SecurityException{
		//获取class对象
		Class clazz=Class.forName(className);
	
		//获取该class对象对应的构造器描述
		Constructor<?> constr=clazz.getConstructor();
		
		//根据class对象获取指定方法描述
		Method method=clazz.getMethod(methodName,classArr);
	
		//调用方法
		return method.invoke(constr.newInstance(), valueArr);
	}

大家都说 Java 反射效率低,你知道原因在哪里么?
java反射机制性能优化
java 获取某个包下的所有类名
利用java反射来查找某个包下的所有类,并得到class取得实例
java利用反射获取某个包下的所有获取对象属性、方法、并实例化

猜你喜欢

转载自blog.csdn.net/qq877728715/article/details/104533298