反射(完结)

反射

一、反射机制的作用

  1. 通过java语言中的反射机制可以操作字节码文件
  2. 有点类似于黑客(可以读和修改字节码文件)
  3. 可以通过反射机制操作代码片段(class文件)
  4. 在java.lang.reflect.* 包下

二、反射相关的类

  1. java.lang.Class:字节码文件。代表一个类型
  2. java.lang.reflect.Method:字节码中的方法字节码
  3. java.lang.relect.Constructor:字节码中的构造方法字节码
  4. java.lang.relect.Field:字节码中的属性字节码

三、获取Class的三种方式

image-20200708205903222

四、通过反射实例化

优点:

  1. 不改变java源代码的情况下,更改配置文件就可以实例化任何对象
  2. 符合开闭原则,对扩展开放。对修改关闭
  3. 较强的灵活性
  4. 框架底层实现原理都是采用的反射机制
public static void main(String[] args) throws Exception {
        FileReader fileReader=new FileReader("resources\MyClass.properties");
        //创建属性类的map
        Properties properties=new Properties();
        //加载
        properties.load(fileReader);
        //关闭流
        fileReader.close();
        //通过key获取到value
        String myUser = properties.getProperty("myUser");
        //打印myUser的类路径
        System.out.println(myUser);
        //获取myUser的类
        Class aClass = Class.forName(myUser);
        //实例化该类
        Object o = aClass.newInstance();
        //打印该类
        System.out.println(o);
    }
  1. Class.forName("")
    1. 它会让类的静态代码块执行,相当于进行类加载

五、拿到文件的绝对路径

  • 以下这种方式可以在任何操作系统中使用

image-20200708221511690

复制过来的文件需要重新改次名字

/*
    * 前提:资源文件一定要放在项目根路径下(src下面)
    * */
    public static void main(String[] args) {
        /*
        * 方法的解释:
        * 获取当前线程.获取当前线程的类加载器.获取该文件的加载资源.获取该资源的绝对路劲
        * 其中这个name参数是Path From Source Root
        * */
        String path = Thread.currentThread().getContextClassLoader().getResource("MyClass2.properties").getPath();
        System.out.println(path);///D:/new-work/utilTest/out/production/utilTest/MyClass2.properties
        //获取一个类的绝对路径
        String path2 = Thread.currentThread().getContextClassLoader().getResource("com\\xd\\反射\\获取文件的绝对路径\\MyClass.properties").getPath();
        System.out.println(path2);
    //以流的形式返回
        InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("MyClass2.properties");
        Properties pro=new Properties();
        pro.load(resourceAsStream);
        String myUser = pro.getProperty("myUser");
        System.out.println(myUser);
    }

六、资源绑定器

  • 便于获取属性配置文件中的内容
  • 使用以下这种方式的时候,属性配置文件。xxxx.properties必须放到类路径下。
  • 扩展名只能是:properties。
 public static void main(String[] args) {
        /*资源绑定起,只能绑定xxx.properties文件,并且这个文件必须在类路径下,文件扩展名必须是properties
        并且在写路径的时候,路径后面的扩展名不能写
        * */
        ResourceBundle myClass2 = ResourceBundle.getBundle("MyClass");
        String myUser = myClass2.getString("myUser");
        System.out.println(myUser);
    }

七、类加载器

1、JDK自带三个加载器

  1. 启动类加载器
    1. 会加载:jar/lib/rt.jar
  2. 扩展类加载器
    1. 如果启动加载器未加载到,就会启动扩展类加载器,加载:jar/lib/ext/*.jar
  3. 应用类加载器
    1. 如果扩展器加载器未加载到,就会启动应用类加载器,加载:classpath中的类(系统的环境变量)

八、获取fields

1、获取字段
public class 获取字段 {
    public static void main(String[] args )  throws  Exception{
        Class aClass = Class.forName("com.xd.反射.instanceMyclass.User");
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field f:declaredFields
             ) {
            System.out.println(f);
            //获取修饰符列表
            int modifiers = f.getModifiers();
            //获取修饰符
            String s = Modifier.toString(modifiers);
            System.out.println(s);

            //获取数据类型
            String name = f.getType().getName();
            System.out.println(name);

            //获取属性的名字
            String name1 = f.getName();
            System.out.println(name1);

            System.out.println("");
        }
    }
}

2、给属性赋值
public class 更改属性值 {
    public static void main(String[] args) throws Exception{
        Class aClass = Class.forName("com.xd.反射.instanceMyclass.User");
        Object o = aClass.newInstance();
        //获取a成员变量的属性
        Field a = aClass.getDeclaredField("a");
        //设置这个成员变量的值
        a.set(o,13);
        //获取这个值
        Object o1 = a.get(o);
        Field c = aClass.getDeclaredField("c");
        //设置非public属性值时,一定要设置为true
        c.setAccessible(true);
        c.set(o,new Date());
        Object o2 = c.get(o);
        System.out.println(o2);
    }
}

九、可变长参数

public class 可变长参数 {
    /*
    * 语法:参数列表为:int... args
    * 1、可变长参数个数要求【0,n】
    * 2、可编程参数在参数列表中必须为最后一个,而且可变长参数只能有1个
    * 3、可变长参数可以当做一个数组来遍历,所以传参数时,也可以传递一个同类型的数组
    * */
    public static void main(String[] args) {
        m();
        m(1,2,3,4);
        m(new int[]{1,2,3,4,5});
        m2("a");
        m2("b",1,2,3,4);
        m2("c",new int[]{1,2,3,4,5});
    }
    public static void m(int... args){
        if(args.length>0){
            for (int arg : args) {
                System.out.println(arg);
            }
        }
    }
    public static void m2(String str,int... args){
    }
}

十、通过反射获取方法

public class 方法的操作 {
    public static void main(String[] args) throws Exception{
        Class aClass = Class.forName("com.xd.反射.instanceMyclass.User");
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            //方法全称
            //System.out.println(declaredMethod);
            //方法修饰符
            String s = Modifier.toString(declaredMethod.getModifiers());
            System.out.println(s);
            //方法返回值类型
            String name = declaredMethod.getReturnType().getName();
            System.out.println(name);
            //方法名
            String name1 = declaredMethod.getName();
            System.out.println(name1);
            //方法参数列表类型
            Class[] parameterTypes = declaredMethod.getParameterTypes();//这个获取是随机排序的
            for (Class parameterType : parameterTypes) {
                //String name3 = parameterType.getName();//这个就是java.lang.String
                String name2 = parameterType.getSimpleName();//简单名称
                System.out.println(name2);
            }
        }
    }
}

十一、通过反射机制如何调用方法

  • 可以同过字段名获得成员变量
  • 但是不能通过方法名获取方法(因为方法会重载)
  • 调用方法的四要素
    1. 对象
    2. 要调用的方法
    3. 实参列表
    4. 返回值
public class 反编译调用对象方法 {
    public static void main(String[] args)  throws Exception{
        //反射加载
        Class aClass = Class.forName("com.xd.反射.instanceMyclass.User");
        //实例化对象
        Object o = aClass.newInstance();
        //获取方法
        Method method2 = aClass.getDeclaredMethod("method2", Integer.class);
        //调用方法:返回的是return的数据
        /*
        * 注意方法的权限修饰符  protected  以下需要设置权限
        *
        * */
        method2.setAccessible(true);
        Object invoke = method2.invoke(o, 1);
        System.out.println(invoke);
    }
}

十二、反编译获取对象构造方法

public class 获取一个类中的所有构造方法 {
    public static void main(String[] args) throws  Exception {
        Class aClass = Class.forName("com.xd.反射.instanceMyclass.User");
        //所有的构造方法
        Constructor[] declaredConstructors = aClass.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            //修饰符
            String s = Modifier.toString(declaredConstructor.getModifiers());
            //构造方法没有返回值
            //方法名
            String simpleName = aClass.getSimpleName();
            System.out.println(s+" "+simpleName+" ");
            //参数类型列表
            Class[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                String simpleName1 = parameterType.getSimpleName();
                System.out.println(simpleName1);
            }
        }
    }
}

十三、通过反射创造对象

public class 通过反射实例化对象 {
    public static void main(String[] args) throws Exception{
        Class aClass = Class.forName("com.xd.反射.instanceMyclass.User");
        //方法一:调用无参数构造方法
        Object o = aClass.newInstance();
        System.out.println(o);
        //方法二;调用有参构造方法
        Constructor declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class, Date.class, Integer.class);
        Object xd = declaredConstructor.newInstance(1, "xd", new Date(), 1);
        System.out.println(xd);
    }
}

十四、获取父类和父类的接口

public class 获取父类和接口 {
    public static void main(String[] args)  throws Exception{
        Class aClass = Class.forName("java.lang.String");
		//所有父类
        Class superclass = aClass.getSuperclass();
        System.out.println("Sting的父类"+superclass);
		//所有接口
        Class[] interfaces = aClass.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface.getSimpleName());
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值