反射
获取Class对象
获取Class对象的三种方式:(例如获取Student类的Class对象)
1、通过Student类的任意对象调用 getClass 方法:
Class clazz = new Student().getClass();
2、通过Student类调用class属性:
Class clazz = Student.class;
3、通过Class类的forName(“类路径”)方法:
Class clazz = Class.forName( “cn.tedu.Student” );
Class对象常用方法
获取Class对象所代表类(或接口)的所在包路径、类名、全限定名称
String getPackageName() – 返回所反射 类(或接口) 的包名
String getPackage().getName() – 返回所反射 类(或接口) 的包名
例如: clazz.getPackageName() 返回 “cn.tedu.reflect”
clazz.getPackage().getName() 返回 “cn.tedu.reflect”
String getSimpleName() – 返回所反射 类 的类名(或所反射接口的接口名)
例如: clazz.getSimpleName() 返回 “Student”
String getName()–返回 所反射 类(或接口) 的全限定类名(包名+类名/接口名)
例如: clazz.getName() 返回 “cn.tedu.reflect.Student”
获取所反射 类(或接口) 的成员变量定义信息
Field getField(String name)
– 返回一个Field对象,表示所反射 类(或接口) 中指定名称的成员变量
– 也就是说,可以通过 name 获取所反射 类(或接口) 中的某一个成员
– 只能获取公开的成员变量(包括从父类中继承的)
Field[] getFields()
– 返回一个Field对象数组,该数组中包含所反射 类(或接口) 的所有成员变量
– 只能获取公开的成员变量(包括从父类中继承的)
Field getDeclaredField(String name) – 返回一个 Field对象
– 返回一个Field对象,表示所反射 类(或接口) 中指定名称的成员变量
– 只能获取本类中的成员变量(包括私有成员变量),但不包括从父类中继承的
Field[] getDeclaredFields()
– 返回一个Field对象数组,该数组中包含所反射 类(或接口) 中的所有成员变量
– 只能获取本类中的成员变量(包括私有成员变量),但不包括从父类中继承的
获取所反射 类(或接口) 的构造方法定义信息
Constructor getConstructor(类… parameterTypes)
– 返回一个Constructor对象,表示 所反射 类 中指定参数的构造方法
– 只能获取公开的构造方法
Constructor[] getConstructors()
– 返回一个Constructor对象数组,该数组中包含 所反射 类 中的所有构造方法
– 只能获取公开的构造方法
Constructor getDeclaredConstructor(类… parameterTypes)
– 返回一个Constructor对象,表示 所反射 类 中指定参数的构造方法
– 获取的构造方法可以是公开的,也可以是私有的
Constructor[] getDeclaredConstructors()
– 返回一个Constructor对象数组,表示 所反射 类 中的所有构造方法
– 获取的构造方法可以是公开的,也可以是私有的
获取所反射 类(或接口) 的成员方法定义信息
Method getMethod(String name, 类… parameterTypes)
– 返回一个Method对象,表示 所反射 类 中指定参数的成员方法
– 只能获取公开的成员方法
Method[] getMethods()
– 返回一个Method对象数组,该数组中包含 所反射 类 中的所有成员方法
– 只能获取公开的成员方法
Method getDeclaredMethod(String name, 类… parameterTypes)
– 返回一个Method对象,表示 所反射 类 中指定参数的成员方法
– 获取的成员方法可以是公开的,也可以是私有的
Method[] getDeclaredMethods()
– 返回一个Method对象数组,该数组中包含 所反射 类 中的所有成员方法
– 获取的成员方法可以是公开的,也可以是私有的
反射的应用
准备工作
定义一个Person类(对该类进行反射)
package reflect;
/**
* 使用当前类来测试反射机制
*/
public class Person {
private String name = "张三";
private int age = 22;
//无参构造 全参构造
public Person(){}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello(){
System.out.println(name+":hello!!");
}
public void sayHi(){
System.out.println(name+":hi!!");
}
public void sayGoodBye(){
System.out.println(name+":bye!!");
}
public void dosome(String thing){
System.out.println(name+"正在"+thing);
}
public void dosome(String thing,int sum){
for(int i=0;i<sum;i++){
System.out.println(name+"正在"+thing);
}
}
private void secret(){
System.out.println(name+":这是我的私有方法!");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
定义一个Student类
package reflect;
public class Student {
public void study(){
System.out.println("学生:好好学习,天天向上!");
}
public void playGame(){
System.out.println("学生:好好游戏,才好学习!");
}
}
测试开始
ReflectDemo1
package reflect;
import java.lang.reflect.Method;
import java.util.Scanner;
/**
* java反射机制
* 反射是java中的动态机制,它允许我们在程序运行期间再确定对象的实例化,
* 方法的调用,属性的操作等,使得程序灵活度大大提升,但是同时他也带来了很多不好的地方,
* 比如资源的开销和较低的运行率
*/
public class ReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
/*
* Class类对象
* Class的每一个实例用于表示JVM中加载的一个类,并且每个被JVM加载的类都有且只有一个Class的实例
* 通过Class实例,可以得知其表示的类的一切信息:类名,包名,有哪些构造器,方法属性等等.并且在运行期间,
* 获取这些对象,对其相关操作
* 因此反射操作的第一步就是获取要操作的类的类对象.获取一个类的类对象的方式:
* 1:类名.class
* 例如:
* Class cls = String.class;
* Class cls = int.class;
* 注:基本类型只能靠这种方式获取类对象
* 2:Class.forName(String className);
* className是要加载的类的完全限定名(包名.类名)
* 例如:
* Class cls = Class.forName("java.lang.String");
* 3:类加载器ClassLoader形式
* */
//Class cls = String.class;//获取String的类对象
//Class cls = Person.class;
//Class cls = Class.forName("java.lang.String");
//Class cls = Class.forName("reflect.Person");
/*
* java.util.ArrayList
* java.io.FileInputStream
* reflect.Person
* */
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类全名:");
String className = scanner.nextLine();
Class cls = Class.forName(className);
//通过类对象获取其表示的String的相关信息
String name = cls.getName();//获取字节码文件的名字包名.类名
System.out.println(name);//java.lang.String
name = cls.getSimpleName();//获取的是简单的名字,就是类名
System.out.println(name);//String
//获取包名
System.out.println(cls.getPackage().getName());//java.lang
//获取当前类对象中的所有的公开方法(包含从父类中继承的方法)
Method[] methods = cls.getMethods();
System.out.println(cls.getSimpleName()+"一共有"+methods.length+"个公开方法");
//获取当前类对象中的所有的方法(包括私有的,但是不含从父类继承的方法)
//如果子类重写了父类的方法,那么这个方法算是子类的方法
//Method[] methods = cls.getDeclaredMethods();
//System.out.println(cls.getSimpleName()+"一共有"+methods.length+"个本类的方法");
for (Method method : methods) {
System.out.println(method.getName());
}
}
}
ReflectDemo2
package reflect;
import java.util.Scanner;
public class ReflectDemo2 {
public static void main(String[] args) throws
ClassNotFoundException,
InstantiationException,
IllegalAccessException {
Person p = new Person();
System.out.println(p);
//先获取要实例化对象的类的所对应的类对象
//Class cls = Class.forName("reflect.Person");
/*
* java.util.ArrayList
* java.util.HashMap
* java.util.Date(日期)
* */
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类全名:");
String className = scanner.nextLine();
Class cls = Class.forName(className);
//类对象提供了newInstance方法可以调用无参且公开的构造器
//那这个方法返回值是一个Object类型,因为这个方法实例化的内容不知道是什么类型
Object o = cls.newInstance();
System.out.println(o);
}
}
ReflectDemo3
package reflect;
import java.lang.reflect.Constructor;
/**
* 使用指定的构造器实例化对象
*/
public class ReflectDemo3 {
public static void main(String[] args) throws Exception{
Person p = new Person("李四", 18);
System.out.println(p);
//1.加载类对象
Class cls = Class.forName("reflect.Person");
//2.获取对应的构造器方法
//cls.getConstructor();//不传参获取的是一个无参构造
//Person(String name,int age)
Constructor c = cls.getConstructor(String.class, int.class);
//3.通过获取的构造器实例化对象
//new Person("王五",55);
Object o = c.newInstance("王五", 55);
System.out.println(o);
}
}
ReflectDemo4
package reflect;
import java.lang.reflect.Method;
import java.util.Scanner;
/**
* 使用反射机制调用方法
*/
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.sayHello();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入类全名:");
String className = scanner.nextLine();
Class cls = Class.forName(className);
System.out.println("请输入方法名:");
String methodName = scanner.nextLine();
//Class cls = Class.forName("reflect.Person");
//实例化Person Person o = new Person();
Object o = cls.newInstance();
//获取要调用的方法
//仅传入方法名时,获取的是无参方法
//Method method = cls.getMethod("sayHello");
Method method = cls.getMethod(methodName);
method.invoke(o);//o.sayHello()
}
}
ReflectDemo5
package reflect;
import java.lang.reflect.Method;
/**
* 调用有参方法
*/
public class ReflectDemo5 {
public static void main(String[] args) throws Exception {
Class cls = Class.forName("reflect.Person");
Object o = cls.newInstance();
//getMethod(methodName) 只有一个参数时,是调用无参方法
//getMethod(methodName,Class param1,Class param2,....)
Method method = cls.getMethod("dosome", String.class);//dosome(String thing)
//invoke(Object o) 只传一个对象时,只是调用的方法所属对象
//invoke(Object,Object param1,Object param2,...)
method.invoke(o, "玩王者荣耀");//o.dosome("玩游戏");
Method method1 = cls.getMethod("dosome", String.class, int.class);//dosome(String thing,int num)
method1.invoke(o, "玩原神",5);
}
}
ReflectDemo6
package reflect;
import java.lang.reflect.Method;
public class ReflectDemo6 {
public static void main(String[] args) throws Exception {
Person p = new Person();
//p.secret();私有方法不能在类的外部被调用
Class cls = Class.forName("reflect.Person");
Object o = cls.newInstance();
//getMethod() 获取公开的方法
//Method method = cls.getMethod("secret");
//getDeclaredMethod() 获取私有方法
Method method = cls.getDeclaredMethod("secret");
//强行打开访问权限
method.setAccessible(true);
method.invoke(o);
}
}
ReflectDemo7
package reflect;
import reflect.annotations.AutoRunClass;
/**
* @author少珩
* @data 2022/4/18 21:10
* 反射中使用注解
*/
public class ReflectDemo7 {
public static void main(String[] args) throws Exception {
//判断一个类是否被@AutoRunClass标注
//Class cls = Class.forName("reflect.Person");
Class cls = Class.forName("reflect.Student");
/*
* 除了Class之外,像Method,Filed等其他反射对象也支持isAnnotationPresent方法,
* 用来表示是否被指定的注解标注
* */
if (cls.isAnnotationPresent(AutoRunClass.class)){
System.out.println(cls.getName()+"被@AutoRunClass标注了!");
}else{
System.out.println(cls.getName()+"没有被@AutoRunClass标注!");
}
}
}
ReflectDemo8
package reflect;
import reflect.annotations.AutoRunClass;
import reflect.annotations.AutoRunMethod;
import java.io.File;
import java.lang.reflect.Method;
/**
* 自动实例化与当前ReflectDemo8同包下所有被AutoRunClass标注的类
*/
public class ReflectDemo8 {
public static void main(String[] args) throws Exception {
File dir = new File(
ReflectDemo8.class.getResource(".").toURI()
);
File[] subs = dir.listFiles(f -> f.getName().endsWith(".class"));
for (File sub : subs) {
String fileName = sub.getName();
String className = fileName.substring(0, fileName.indexOf("."));
Class cls = Class.forName(ReflectDemo8.class.getPackage().getName() + "." + className);
if (cls.isAnnotationPresent(AutoRunClass.class)){
System.out.println("实例化"+className);
Object o = cls.newInstance();
System.out.println(o);
//获取所有的当前类中的方法
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(AutoRunMethod.class)){
System.out.println("自动调用方法:"+method.getName());
method.invoke(o);
}
}
}
}
}
}
ArgsDemo
package reflect;
import java.util.Arrays;
/**
* JDK5之后,java推出了一个新特性:变长参数
*/
public class ArgsDemo {
public static void main(String[] args) {
doing(1,3);
doing(1,2,"one");
doing(1,2,"one","two");
doing(1,2,"one","two","three");
}
/*
* 变长参数只能是方法的最后一个参数,可以代表任意个类型的参数
* 实际是一个数组类型
* */
private static void doing(int age,long a,String... arg) {
System.out.println(arg.length);
System.out.println(Arrays.toString(arg));
}
}
Test1
package reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* @author少珩
* @data 2022/4/18 19:53
* 自动调用Person本类中所有名字含有"s"的无参的公有方法
* 提示:
* Method提供了方法:
* int getParameterCount() 可以获取其表示的方法的参数个数
* Method[] getDeclaredMethods() 获取本类中的所有方法
* String getName() 获取方法名
* contains(a) 判断字符串是否包含指定字符串a
* getModifiers() 判断方法的权限
*/
public class Test1 {
public static void main(String[] args) throws Exception {
Class cls = Class.forName("reflect.Person");
Object o = cls.newInstance();
Method[] methods = cls.getDeclaredMethods();
for (Method method : methods) {
if (method.getName().contains("s") &&
method.getParameterCount() == 0 &&
//判断当前方法是否为public修饰的方法
method.getModifiers() == Modifier.PUBLIC) {
System.out.println("自动执行的方法"+method.getName());
method.invoke(o);
}
}
}
}
Test2
package reflect;
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* 自动调用与当前类Test2在同一个包下所有的类中方法名含有"s"的无参公开方法
*/
public class Test2 {
public static void main(String[] args) throws Exception {
//定位Test2所在的目录(包)
File dir = new File(
Test2.class.getResource(".").toURI()
);
//过滤当前目录下,所有的文件名后缀为.class的文件
File[] subs = dir.listFiles(f -> f.getName().endsWith(".class"));
//遍历每一个class文件
for (File sub : subs) {
//获取Class对象(通过.class文件的名字拼出对应的全路径名)
String fileName = sub.getName();//获取文件名 Test2.class
String className = fileName.substring(0, fileName.indexOf("."));
Class cls = Class.forName(Test2.class.getPackage().getName() + "." + className);
//实例化对象
Object o = cls.newInstance();
//获取所有本类方法
Method[] methods = cls.getDeclaredMethods();
//遍历本类方法,筛选出复合条件的方法
for (Method method : methods) {
if (method.getName().contains("s") &&
method.getParameterCount() == 0 &&
method.getModifiers() == Modifier.PUBLIC) {
System.out.println("自动调用了"+className+"的方法:"+method.getName());
//执行方法
method.invoke(o);
}
}
}
}
}
Test3
package reflect;
import reflect.annotations.AutoRunClass;
import java.io.File;
import java.net.URISyntaxException;
public class Test3 {
public static void main(String[] args) throws Exception {
File dir = new File(
Test3.class.getResource(".").toURI()
);
File[] subs = dir.listFiles(f -> f.getName().endsWith(".class"));
for (File sub : subs) {
String fileName = sub.getName();
String className = fileName.substring(0, fileName.indexOf("."));
Class cls = Class.forName(Test3.class.getPackage().getName() + "." + className);
if (cls.isAnnotationPresent(AutoRunClass.class)){
System.out.println(className+"被@AutoRunClass标注了");
}else{
System.out.println(className+"没被@AutoRunClass标注");
}
}
}
}