java上乘武功入门--反射

目录
  • 先来看一段魔法吧
  • 反射机制是个什么玩意儿?
  • 构造任意一个类的对象
  • 了解任意一个对象所属的类
  • 了解任意一个类的成员变量和方法
  • 调用任意一个对象的属性和方法
  • 魔法揭秘
  • 总结

先来看一段魔法吧

public class Test {
    private static void changeStrValue(String str, char[] value) {
    	// 只要执行魔法代码就可以达到下面的效果
        // 施展魔法的代码稍后揭秘
    }
    public static void main(String[] args) {
        changeStrValue("abc", new char[]{'d','e','f'});
        String abc = "abc";
        System.out.println("abc");
        System.out.println(abc);
        System.out.println("abc".equals(abc));
    }
}

二当家的第一次看到这个执行结果觉得很有意思。明明应该是"abc"怎么就变成了"def"呢?

反射机制是个什么玩意儿?

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

以上就是百科的解释。可能有点抽象,接着看二当家的给你秀起来解释一下。

构造任意一个类的对象

一般情况下,我们如果想要创建一个类的对象,应该要用到new关键字。但是像spring这样的框架,我们只需要配置类名,就可以得到类的实例。他是怎么做到的呢?

import java.util.List;
public class Test {
    /**
     * 根据类名取得类实例
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param className
     * @param <T>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static <T> T getInstance(String className) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        Class<T> clazz = (Class<T>) Class.forName(className);
        return clazz.newInstance();
    }
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        List<String> list = getInstance("java.util.ArrayList");
        list.add("abc");
        list.add("def");
        for (String v : list) {
            System.out.println(v);
        }
    }
}

类名可以在程序运行中从配置文件获取,甚至是从网络获取,然后动态创建一个类的实例。

了解任意一个对象所属的类

import java.util.ArrayList;
public class Test {
     /**
     * 打印对象的类名
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param o
     */
    public static void printClass(Object o) {
        System.out.printf(o.getClass().getName());
    }
    public static void main(String[] args) {
        printClass(new ArrayList<>());
    }
}

了解任意一个类的成员变量和方法

我们一般要使用一个类,先要知道有什么方法和属性,先了解,后使用。但是像spring那样的框架为什么可以为我们自动注入呢?他怎么知道我们一个对象里有什么属性呢?

import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
    /**
     * 打印类的属性
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param clazz
     */
    public static void printFields(Class clazz) {
        System.out.println(clazz.getName() + "包含如下属性:");
        for (Field f : clazz.getDeclaredFields()) {
            System.out.println(f);
        }
    }
    /**
     * 打印类的方法
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param clazz
     */
    public static void printMethods(Class clazz) {
        System.out.println(clazz.getName() + "包含如下方法:");
        for (Method m : clazz.getDeclaredMethods()) {
            System.out.println(m);
        }
    }
    public static void main(String[] args) {
        printFields(MyClass.class);
        printMethods(MyClass.class);
    }
}
class MyClass {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

调用任意一个对象的属性和方法

像spring这样的框架,即使一个属性是私有属性并且没有set方法,一样可以注入。

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
    /**
     * 调用一个对象的方法
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param o
     * @param methodName
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void callMethod(Object o, String methodName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method m = o.getClass().getDeclaredMethod(methodName);
        m.setAccessible(true);
        m.invoke(o);
    }
    /**
     * 修改一个对象的属性
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param o
     * @param fieldName
     * @param value
     * @throws IllegalAccessException
     */
    public static void changeFieldValue(Object o, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field f = o.getClass().getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(o, value);
    }
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException {
        MyClass o = new MyClass();
        // 修改任意属性,即使是私有的
        changeFieldValue(o, "name", "二当家的白帽子");
        // 调用任意方法,即使是私有的
        callMethod(o, "printName");
    }
}
class MyClass {
	// 私有属性,只可以调用set方法修改
    private String name;
    private void printName() {
        // 私有方法,只有本类自己的实例可以调用
        System.out.println("My name is " + name);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

魔法揭秘

是时候揭秘魔法的真面目了,没错,也是利用了反射。

import java.lang.reflect.Field;
public class Test {
    /**
     * 修改字符串内部的值
     * @author 二当家的白帽子 https://le-yi.blog.csdn.net/
     * @param str
     * @param value
     */
    private static void changeStrValue(String str, char[] value) {
        try {
            Field f = str.getClass().getDeclaredField("value");
            f.setAccessible(true);
            f.set(str, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        changeStrValue("abc", new char[]{'d','e','f'});
        // 这里的"abc"字符串和上面调用changeStrValue的参数"abc"会指向同一块内存
        String abc = "abc";
        System.out.println("abc");
        System.out.println(abc);
        System.out.println("abc".equals(abc));
    }
}

要理解这段代码,除了反射机制还需要了解java对于字符串的处理。"字符串常量池"已经超出本文的范围,是另一个话题,本文就不多说了。

原本字符串内容是"abc",我们正常情况下无法修改这个内容,因为String是不变类。但是反射大法却可以打破一切禁忌。

总结

一般的程序可能用不到写反射的代码。但是像spring这样的框架,如果没有反射,我真的想不出如何实现呢。哪怕永远不需要用反射,了解机制对我们都有着莫大的好处。

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java的枚举,注解和反射(一)

    目录 枚举 什么是枚举? 枚举类的实现 自定义实现枚举类 使用关键字enum定义枚举类 Enum的常用方法 实现接口的枚举类 注解 注解概述 常见的注解 总结 枚举 什么是枚举? 枚举的字面意思就是 一一列举出来 在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数.这两种类型经常(但不总是)重叠.是一个被命名的整型常数的集合,枚举在日常生活中很常见,例如表示星期的SUNDAY.MONDAY.TUESDAY.WEDNESDAY.THURSDAY

  • Java开发反射机制的实战经验总结

    目录 前言 一.创建Class的三种方式 二.反射获取类的所有属性和属性类型 三.反射动态修改类属性的注解值 四.反射获取类的方法及调用方式 总结 前言 我在实际项目当中有经常用到反射机制,故而将学会的反射用法做一些汇总笔记,当做以后复盘所用. 存在这样一个类: package com.example.demo; import com.alibaba.fastjson.annotation.JSONField; public class User { private String name; @

  • 一篇文章带你搞定JAVA反射

    目录 1.反射的概念 1.概念 2.获取字节码文件对象的方式 2.1 元数据的概念 2.2 获取class对象的方式 1.访问权限 2.获取方法 2.1 访问静态方法 2.2 访问类方法 3.获取字段,读取字段的值 4.获取实现的接口 5.获取构造函数,创建实例 6.获取继承的父类 7.获取注解 4.反射实例 5.总结 1.反射的概念 1.概念 反射,指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法

  • Java的枚举,注解和反射(二)

    目录 反射 什么是反射? 反射的用途 反射的具体作用 反射的主要API Class类 总结 反射 什么是反射? 反射是指在程序运行期间,可以通过Reflection Api提供方法可以获取任何类的内部的信息,并能直接操作任意类的方法和属性.反射被视为动态语言的关键. //在反射之前可以做的事情 @Test public void Test1() { //创建Person类的对象 Person person = new Person("name", 78); //通过对象调用其内部的方法

  • 新手了解java 反射基础知识

    目录 一.反射概述 二.常用api 三.创建Class对象的四种方式 总结 一.反射概述 Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意 对象的内部属性及方法. 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象 (一个类只有一个Class对象),这个对象就包含了完整的类的结构信 息.我们可以通过这个对象看到类的结构,这个对象就像一面镜子,透 过这个镜子看到类的结构,所以我们形象的

  • java上乘武功入门--反射

    目录 先来看一段魔法吧 反射机制是个什么玩意儿? 构造任意一个类的对象 了解任意一个对象所属的类 了解任意一个类的成员变量和方法 调用任意一个对象的属性和方法 魔法揭秘 总结 先来看一段魔法吧 public class Test { private static void changeStrValue(String str, char[] value) { // 只要执行魔法代码就可以达到下面的效果 // 施展魔法的代码稍后揭秘 } public static void main(String[

  • Java高级特性之反射机制实例详解

    本文实例讲述了Java高级特性之反射机制.分享给大家供大家参考,具体如下: 老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一. 什么是反射? 二.反射能做什么? 一. 什么是反射? 用在Java身上指的是我们可以于运行时加载.探知.使用编译期间完全未知的classes.换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体.或对其fields设值.或唤起其methods. 如果你是一个

  • Java使用注解和反射简化编程的方法示例

    本文实例讲述了Java使用注解和反射简化编程的方法.分享给大家供大家参考,具体如下: 一 点睛 当调用大量方法,可以使用反射和注解简化编程. 二 代码 import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.la

  • Java基础篇之反射机制详解

    目录 1.反射概述 1.1什么是反射 1.2.反射能干什么 2.解剖类 2.1反射构造方法 2.1.1反射无参的构造函数 2.1.2反射“一个参数”的构造函数 2.1.3反射“多个参数”的构造函数 2.1.4反射“私有”的构造函数 2.1.5反射得到类中所有的构造函数 2.2反射类中的方法 2.3反射类中的属性字段 思考:在讲反射之前,先思考一个问题,java中如何创建一个对象,有哪几种方式? Java中创建对象大概有这几种方式: 1.使用new关键字:这是我们最常见的也是最简单的创建对象的方式

  • Java的RTTI和反射机制代码分析

    RTTI,即Run-Time Type Identification,运行时类型识别.运行时类型识别是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息.RTTI能在运行时就能够自动识别每个编译时已知的类型. 很多时候需要进行向上转型,比如Base类派生出Derived类,但是现有的方法只需要将Base对象作为参数,实际传入的则是其派生类的引用.那么RTTI就在此时起到了作用,比如通过RTTI能识别出Derive类是Base的派生类,这样就能够向上转型为Derived.类似的,

  • Java Mybatis框架入门基础教程

    一.Mybatis介绍 MyBatis是一款一流的支持自定义SQL.存储过程和高级映射的持久化框架.MyBatis几乎消除了所有的JDBC代码,也基本不需要手工去 设置参数和获取检索结果.MyBatis能够使用简单的XML格式或者注解进行来配置,能够映射基本数据元素.Map接口和POJOs(普通java对象)到数据库中的记录. 二.MyBatis工作流程 (1)加载配置并初始化 触发条件:加载配置文件 配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个

  • Java动态代理和反射机制详解

    反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). 静态代理 预先(编译期间)确定了代理者与被代理者之间的关系,也就是说,若代理类在程序运行前就已经存在了,这种情况就叫静态代理 动态代理 代理类在程序运行时创建的代理方式.也就是说,代理类并不是在Java代码中定义的,而是在运行期间根据我们在Java代码中的"指示"动态生成的. 动态代理比

  • Java Lambda表达式入门示例

    本文实例讲述了Java Lambda表达式.分享给大家供大家参考,具体如下: 一 点睛 Lambda表达式支持将代码块作为方法参数,Lambda表达式允许使用更简洁的代码来创建只有一个抽象方法的接口(函数式接口)的实例. Lambda表达式主要作用就是代替匿名内部类的繁琐语法. 它由三部分组成: 形参列表.形参列表允许省略形参类型.如果形参列表中只有一个参数,甚至连形参列表的圆括号也可以省略. 箭头(->),必须通过英文等号和大于符号组成. 代码块.如果代码块只有包含一条语句,Lambda表达式

  • 详解Java高级特性之反射

    定义 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制. 用途 在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量.方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法.当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符.阅读源码发现,经过层层调用后在

  • java新人基础入门之递归调用

    一.递归概念 递归本质:程序调用自身的编程技巧叫做递归. 程序调用自身的编程技巧称为递归( recursion).递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调: 用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过: 程所需要的多次重复计算,大大地减少了程序的代码量.递归的能力在于用有限的语句来定义对象的无限集合. 二.递归的三个条件: 边界条件 递归前进段 递归返回段 当

随机推荐