java反射机制

反射机制是java的动态机制,可以在程序"运行期间"在确定实例化对象,方法调用,属性操作等。

反射机制可以提高代码的灵活度,但是会带来较多的系统开销的较低的运行效率,因此不能过度依赖

Class类
Class类称为类的类对象。
JVM加载一个类的class文件时,就会创建一个Class实例与该类绑定。因此每个被加载的
类都有且只有一个Class实例,这个实例就是该加载的类的类对象。
通过一个类的类对象我们可以获取这个类的一切信息(类名,属性,方法,构造器等)从而在
程序运行期间进行相关的操作
因此反射第一步就是要获取操作的类的类对象。而获取方式有三种:
1:类名.class
Class cls = String.class;
Class cls = int.class;
2:Class.forName(String className)
Class cls = Class.forName("java.lang.String");//参数需要是完全限定名:包名.类名
注意:基本类型不支持此种方式获取类对象

3:ClassLoader类加载器形式获取

代码示例

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要加载的类的名字:");
        String className = scanner.nextLine();
        Class cls = Class.forName(className);


        String name = cls.getName();//获取完全限定名:包名.类名
        System.out.println(name);

        name = cls.getSimpleName();//仅获取类名
        System.out.println(name);

        String packageName = cls.getPackage().getName();//获取包名
        System.out.println("包名:"+packageName);

//获取String类的所有公开方法(包含从超类继承的方法)

Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            System.out.println(method.getName());
        }

使用反射机制实例化对象

//2调用Class的newInstance()来调用无参构造器
        Object obj = cls.newInstance();
        System.out.println(obj);
通过类对象获取指定的有参构造器:Person(String,int)
Constructor c = cls.getConstructor();//不传参获取的就是无参构造器
Constructor c1 = cls.getConstructor(String.class,int.class);
        Object obj = c1.newInstance("王五",66);//new Person("王五",66);
        System.out.println(obj);
相当于new Person("王五",66);

调用有参方法

        Class cls = Class.forName("reflect.Person");
        Object obj = cls.newInstance();

        //public void say(String info){
        Method method = cls.getMethod("say",String.class);
        method.invoke(obj,"你好!");//p.say("你好!");

        //public void say(String info,int count){
        Method method2 = cls.getMethod("say",String.class,int.class);
        method2.invoke(obj,"嘿嘿",5);//p.say("嘿嘿",5)

若方法是私有的,可以利用setAccessible()方法强行打开访问权限

        method.setAccessible(true);//强行打开访问权限
        method.invoke(obj);//p.hehe();
        method.setAccessible(false);//打开之后要关闭

练习:

/**
 * 自动调用Person类中所有无参方法
 *
 * Method的方法:
 * int getParameterCount()
 * 返回当前Method表示的方法的参数个数
 */
public class Test {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("reflect.Person");
        Object obj = cls.newInstance();

        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
           //判断是否为无参且公开的方法
           if(method.getParameterCount()==0             //没有参数的
                   &&
              method.getModifiers() == Modifier.PUBLIC  //公开的
                   &&
              method.getName().contains("a")            //名字含有字母"a"
           ){
               System.out.println("自动调用方法:"+method.getName()+"()");
               method.invoke(obj);
           }
        }
    }
}

练习2:

public class Test2 {
    public static void main(String[] args) throws URISyntaxException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        //定位当前类所在的包(目录)
        File dir = new File(
                Test2.class.getResource(".").toURI()
        );
        File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
        for(File sub : subs){
            //通过每一个class文件的文件名得到类名
            String fileName = sub.getName();
            String className = fileName.substring(0,fileName.indexOf("."));
            //根据Test2这个类的包名来拼接其它同包中的类的完全限定名
            className = Test2.class.getPackage().getName()+"."+className;
            //加载该类的类对象
            Class cls = Class.forName(className);

            Object obj = cls.newInstance();//实例化对象
            //根据类对象获取该类中所有定义的方法
            Method[] methods = cls.getDeclaredMethods();
            for(Method method : methods){
                if(method.getParameterCount()==0
                            &&
                   method.getModifiers()== Modifier.PUBLIC
                ){
                    System.out.println("自动调用:"+method.getName()+"()");
                    method.invoke(obj);
                }
            }

        }


    }
}

通常在定义一个有参方法时,不知道需要传几个参数的时候可以利用下面这个方法

public static void dosome(int d,String... s){
        System.out.println(s.length);
        System.out.println(Arrays.toString(s));
    }

在定义方法时,在数据类型后面加...

变长参数会被编译器改为数组。
变长参数只能是方法的[最后一个]参数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛老师来巡山~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值