java中的反射机制

反射

获取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标注");
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值