反射笔记2022

本文深入探讨了Java反射机制,通过反射可以动态调用方法、获取属性,甚至访问私有成员。文中给出了使用Properties文件动态加载类并执行方法的例子,并详细介绍了Class对象的获取方式、构造器、方法和字段的访问。此外,还讨论了类加载的静态和动态加载概念,以及如何通过反射实现权限爆破。
摘要由CSDN通过智能技术生成

反射,这个名字就可体现出了反射的特点,就像镜子一样。

正常情况下:

调用方法:类名.方法名();

获取变量:对象名.属性名;   

但在反射下:

调用方法:方法.inoke(对象名)

获取变量 :属性.get(对象名)

两个进行比较,刚好相反,就像再照镜子,很符合反射的名字,注意在反射下,方法、属性都是对象(通过class类对象拿到),万物皆对象。

看的是韩老师的视频

下面这张图体现了计算机程序的三个阶段

计算机编译阶段 会获得一个字节码文件,然后通过类加载器,再堆生成一个 Class类对象,注意:在一个程序中一个类只会有一个Class类对象,在这个Class类对象中,无论属性还是方法都是对象,真正的一切皆对象,方法是:Method  属性是:Field   构造器是:Constructor。然后再运行阶段,通过Class类对象,创建对象,但这个对象是知道它是属于哪一个Class对象的。再

获取class对象的三种方式(另外三种不重要)  class对象是有泛型的

1.在编译阶段

通过Class的forName("路径")

Class cls1=Class.forName("java.lang.Cat");

应用场景:多用于配置文件,读取全路径,加载类

2 加载阶段(加载已经完成)

类名.class

Class cls2=Cat.class;

应用场景:多用于参数传递,比如通过反射得到对应的构造器对象

3.运行阶段

对象名.getClass()

应用场景:通过已经创建好的对象,获得class类对象

4.其他方式

ClassLoder cl=对象。getClass.getClassLoder();

Class clazz4=cl.loadClass("类的全类名");

5 基本数据类型获得class

基本数据类型.class

6.基本数据类型包装类

包装类.TYPE

通过class的方法可以获得class对象中类的属性、方法、构造器的对象

设置属性值的方法

f.set(o,值)//这个o是实例化对象o

下面是Class的常用方法

 可以看出获取方法的命名都是get+类型(只能是public),如果中间有declared则说明可以是私有的,否则如果不满足权限,会报异常。当然就算拿到了也用不了,这个时候就要用到爆破了

爆破

通过调用类对象(属性,方法)的setAccessible() 方法,传入一个布尔值,要爆破就设置ture,这样就使用了,相当于走了个后门,绕过了访问权限

例子:        

Method move = cls.getDeclaredMethod("move");//这个方法可返回私有的方法
move.setAccessible(true);//爆破
move.invoke(o);

Field name = cls.getDeclaredField("name");//可以包括私有的
name.setAccessible(true);//爆破
System.out.println(name.get(o));

获取对象的三种方法

1.常规的使用构造器

2,使用class类对象的newInstance() 方法 但只能用无参构造器

3.先获得构造器对象,通过参数进行选择,参数是数据类型的class类对象。再使用newInstance方法,

示例

 Constructor declaredConstructor = cls.getDeclaredConstructor(String.class)
//获得构造器,通过传入参数的class对象获取
 Cat a = (Cat)declaredConstructor.newInstance("可爱极了");
//创建对象,一样是通过newInstance,不过直接调用是访问的无参构造器,这个可以选择
 a.love();

类加载分为静态加载和动态加载

1.静待加载:编译时加载相关的类,如果没有就会报错,依赖性太强

2 动态加载:运行时即加载需要的类,如果不运行该类,即使不存在,也不会报错,降低了依赖性

1.

创建对象new  、

加载子类时,加载父类、

调用类的静态成员

这些都是属于静态加载,在编译期就会完成加载

2

使用反射

这个属于动态加载,只有执行到这个语句时才会加载,为什么可以动态加载,主要是使用反射可以自己手动获得Class类对象,当然这里也就是能使用forName()方法,因为其他两种方法分别实在类加载阶段和实例完对象后才能用的,

最后是一些代码

package com.Cat.Reflection;

import com.Cat.Cat;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
@SuppressWarnings({"all"})
public class ReflectionQuesqution {
    public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
     //传统方法
     Cat cat=new Cat();
     cat.hi();

//
        //2使用Properties 类,可以读写配置文件

        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\re.properties"));
        String  classfullpath = properties.get("classfullpath").toString();
        String method=properties.get("method").toString();
        System.out.println("classfullpath="+classfullpath);
        System.out.println("method="+method);
        //new com.Cat.Cat.var,通过全路经,可以生成对象
        //但是我们用 classfullpath却无法生成,因为那是一个字符串

        //通过类加载,获取Class类型的对象cls
        Class cls= Class.forName(classfullpath);
       //获得class的三种方式,1.forname (编译)2.类名.class(加载) 3.对象名.getclass

        //通过cls得到的对象
        Object o=cls.newInstance();
        System.out.println("o的运行类型是="+o.getClass());

        //通过cls得到的对象的getMethod 对象
        Method method1=cls.getMethod(method);//要求权限为public
        //通过menthod1调用方法,使用方法对象调用用方法-
        method1.invoke(o);
        //方法反射:方法.invoke(对象)  传统;对象.方法()
       /* Field name = cls.getField("name");//获取属性*/
        Field name = cls.getDeclaredField("name");//可以包括私有的

        name.setAccessible(true);//爆破
        System.out.println(name.get(o));
        Class<Integer> integerClass = int.class;//基本类型获得class对象

        Method move = cls.getDeclaredMethod("move");//这个方法可返回私有的方法
        move.setAccessible(true);//爆破,
        //可以总结出,setAccessible,可以使访问到私有权限,Declared则是可以返回这个方法或属性,然后用setAccessible爆破
        move.invoke(o);
        //同时获取方法的命名都是get+类型,如果中间有declared则说明可以是私有的,否则如果不满足权限,会报异常

        //获取构造器
        Constructor declaredConstructor = cls.getDeclaredConstructor(String.class);//获得构造器,通过传入参数的class对象获取
        Cat a = (Cat)declaredConstructor.newInstance("可爱极了");//创建对象,一样是通过newInstance,不过直接调用是访问的无参构造器,这个可以选择
        a.love();
        Class<Cat> catClass = Cat.class;//通过类名返回class对象
        //获得对象的三种方式
       /*
       * 1.调用构造器
       *
       * 2.使用class对象的newInstance方法
       *
       *
       *
       * 3.通过class对象获得构造器
       *
       * 再使用newInstance方法,获取正式对象
       *
       *
       *
       *
       * */

        Class<Integer> type = Integer.TYPE;

    }

   //





}
package com.Cat;

public class  Cat {

  private  String name="莲莲";
public  String des;
    public  void hi()
    {
        System.out.println("我是"+name);
    }

    public  void  cry ()
    {
        System.out.println("莲莲最可爱了");
    }

    public Cat() {
    }

    public Cat(String desc) {
        this.des = desc;
    }

    private void move()
    {

        System.out.println("莲莲你带我走把");



    }
    public  void love()
    {

        System.out.println(name+des);
    }
}

配置文件

classfullpath=com.Cat.Cat
method=cry

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值