java反射原来是这么玩的(反射一开,谁都不爱)

本文深入解析Java反射机制的发展历程及应用,从1997年jdk1.1版本引入至今,反射已成为Java类加载、RTTI、Spring IOC等核心功能的基础。文章详细介绍了如何使用反射获取类的构造方法、方法、字段,以及如何调用它们。

反射的发展历史

1996年01月23日,jdk 1.0版本发布,代号为Oak(橡树)。

这个代号为Oak(橡树)的版本,在发布后的第二年,1997年02月19日,发布jdk 1.1版本,这次版本发布中引入了反射机制。

关于反射机制,由于年代久远,能搜索到对于反射机制的记载少之又少,能找到最为久远的是一篇题为《Using Java Reflection》的文章,发表于 1998年1月,文中提到:反射是一个可以获取java类、属性的一个工具,因为它是动态加载的

而在另外一篇文章《A Button is a Bean》里解释道,反射是为了能把一个类的属性可视化的展示给用户,如下图所示:

通俗的解释就是:无论是公有还是私有的方法、属性、构造方法,全都可以用反射进行获取、进行赋值、调用。听到这个解释,是不是感觉反射很强。

正因为反射的强大,在java世界里运用的地方有很多,比如:Java类加载和初始化、Java中RTTI、Spring的IOC,。

如此广泛的运用,只能说反射除了强,用起来肯定很爽。我想起我的同事,IT界的刁民,总是热衷于反射。

他在讲解他是如何运用反射时,嘴角总是压抑不住的微笑,这种迷恋反射的样子,像极了爱情。

正所谓:反射一开,谁都不爱。(傲娇)

下面就看看反射究竟是如何在程序中使用的。

反射的概述和使用

反射的概述

JAVA反射机制是在运行状态中,
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

我们知道class文件是在编译的时候生成的,Class对象是将class文件读入内存,并为之创建一个Class对象。

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

Class类里面,包含了一个类应有的所有描述,包括:
字段:Field.java
方法:Method.java
构造方法:Constructor.java
等等…

知道了Class类里面包含了哪些内容之后,再看一下new一个对象的究竟会发生那些过程:

反射的使用

这里使用一个Animal类来作为示范,可以看到这个类里的成员变量、方法、构造方法的访问修饰符既有public、也有private的。下面就将使用反射获取不同修饰符修饰的成员变量、方法、构造方法。

package com.shuai.ioc.ref;

public class Animal {

    /**
     * 动物名字
     */
    public String name;

    /**
     * 动物年龄
     */
    protected int age;

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    /**
     * 默认的构造方法
     *
     * @param name
     */
    Animal(String name) {
        System.out.println("执行了" + "默认的构造方法 " + name);
    }

    /**
     * 无参构造方法
     */
    public Animal() {
        System.out.println("执行了" + "无参构造方法 ");
    }

    /**
     * 有一个参数的构造方法
     *
     * @param name
     */
    public Animal(char name) {
        System.out.println("执行了" + "有一个参数的构造方法 name:" + name);

    }

    /**
     * 有多个参数的构造方法
     *
     * @param name
     * @param age
     */
    public Animal(String name, int age) {
        System.out.println("执行了" + "有多个参数的构造方法 name:" + name + "age:" + age);
    }

    /**
     * protected的构造方法
     *
     * @param n
     */
    protected Animal(boolean n) {
        System.out.println("执行了" + "受保护的构造方法 n:" + n);
    }

    /**
     * 私有构造方法
     *
     * @param age
     */
    private Animal(int age) {
        System.out.println("执行了" + "私有构造方法 age:" + age);
        this.name = "私有构造方法调用成功";
        this.age = age;
    }


    /**
     * 公有方法
     *
     * @param s
     */
    public void public1(String s) {
        System.out.println("调用了" + "公有的方法" + ": public1 , s:" + s);
    }

    /**
     * protected的方法
     */
    protected void protected2() {
        System.out.println("调用了" + "protected的方法" + ": protected2 ");
    }

    /**
     * 友好的方法
     */
    void friendly1() {
        System.out.println("调用了" + "友好的方法" + ": friendly1 ");
    }

    /**
     * 私有方法
     *
     * @param age
     * @return
     */
    private String private1(int age) {
        System.out.println("调用了" + "私有方法" + ": private1 ,age:" + age);
        return age + "";
    }


}

用反射获取类的构造方法

在Class类中,提供一系列获取被反射类构造方法的方法。

  • 批量获取构造方法的方法
    • public Constructor[] getConstructors():所有"公有的"构造方法
    • public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
  • 获取单个的方法,并调用
    • public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法
    • public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
  • 调用构造方法
    • newInstance(Object… initargs)
package com.shuai.ioc.ref;

import com.shuai.ioc.Book;

import java.lang.reflect.Constructor;

public class ConstructorsTest {

    public static void main(String[] args) throws Exception {

        //1.加载Class对象
        Class clazz = Class.forName("com.shuai.ioc.ref.Animal");

        //2.获取所有公有构造方法
        System.out.println("所有公有构造方法");
        Constructor[] conArray = clazz.getConstructors();
        for (Constructor c : conArray) {
            System.out.println(c);
        }

        // 所有的构造方法,公有、私有都行
        System.out.println("");
        System.out.println("所有的构造方法,包括:私有、受保护、默认、公有");
        conArray = clazz.getDeclaredConstructors();
        for (Constructor c : conArray) {
            System.out.println(c);
        }

        // 获取公有、无参的构造方法
        System.out.println("");
        System.out.println("获取公有、无参的构造方法");
        Constructor con = clazz.getConstructor(null);

        System.out.println("con = " + con);
        //调用构造方法
        Object obj = con.newInstance();

        // 获取私有构造方法
        System.out.println("");
        System.out.println("获取私有构造方法,并调用");
        con = clazz.getDeclaredConstructor(int.class);
        System.out.println(con);
        //暴力访问,忽略掉访问修饰符
        con.setAccessible(true);
        //调用构造方法
        Animal animal = (Animal) con.newInstance(1);
        System.out.println(animal.toString());

    }
}

用反射获取类的方法

在Class类中,提供一系列获取被反射类构造方法的方法。

  • 批量的
    • public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
    • public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
  • 获取单个的
    • public Method getMethod(String name,Class<?>... parameterTypes)name: 方法名;Class ...:形参的Class类型对象
    • public Method getDeclaredMethod(String name,Class<?>... parameterTypes)obj:要调用方法的对象;args:调用方式时所传递的实参;
  • 调用方法
    • public Object invoke(Object obj,Object... args)obj:要调用方法的对象;args:调用方式时所传递的实参;
package com.shuai.ioc.ref;

import java.lang.reflect.Method;

public class MethodClassTest {

    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class stuClass = Class.forName("com.shuai.ioc.ref.Animal");


        //2.获取所有公有方法
        System.out.println("获取所有 公有 方法");
        stuClass.getMethods();
        Method[] methodArray = stuClass.getMethods();
        for (Method m : methodArray) {
            System.out.println(m);
        }

        System.out.println();
        System.out.println("获取所有的方法,包括私有的");
        methodArray = stuClass.getDeclaredMethods();
        for (Method m : methodArray) {
            System.out.println(m);
        }

        System.out.println();
        System.out.println("获取公有的public1()方法");
        Method m = stuClass.getMethod("public1", String.class);
        System.out.println(m);
        //实例化一个Student对象
        Object obj = stuClass.getConstructor().newInstance();
        m.invoke(obj, "this is name value");


        System.out.println();
        System.out.println("获取私有的private1()方法");
        m = stuClass.getDeclaredMethod("private1", int.class);
        System.out.println(m);
        m.setAccessible(true);//解除私有限定
        Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
        System.out.println("返回值:" + result);

    }
}

用反射获取类的字段

在Class类中,提供一系列获取被反射类构造方法的方法。

  • 批量的
    • Field[] getFields():获取所有的"公有字段"
    • Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
  • 获取单个的
    • public Field getField(String fieldName):获取某个"公有的"字段;
    • public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
  • 设置字段的值
    • public void set(Object obj,Object value)obj:要设置的字段所在的对象;value:要为字段设置的值;
package com.shuai.ioc.ref;

import java.lang.reflect.Field;

public class FieldsTest {

    public static void main(String[] args) throws Exception {
        //1.获取Class对象
        Class animalClass = Class.forName("com.shuai.ioc.ref.Animal");
        //2.获取字段
        System.out.println("获取所有公有的字段");
        Field[] fieldArray = animalClass.getFields();
        for (Field f : fieldArray) {
            System.out.println(f);
        }

        System.out.println();
        System.out.println("获取所有的字段(包括私有、受保护、默认的)");
        fieldArray = animalClass.getDeclaredFields();
        for (Field f : fieldArray) {
            System.out.println(f);
        }

        System.out.println();
        System.out.println("获取公有字段并调用");
        Field f = animalClass.getField("name");
        System.out.println(f);
        //获取一个对象
        Object obj = animalClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
        //为字段设置值
        f.set(obj, "dog");//为Student对象中的name属性赋值--》stu.name = "刘德华"
        //验证
        Animal stu = (Animal) obj;
        System.out.println("验证name:" + stu.name);

        System.out.println();
        System.out.println("获取私有字段并调用");
        f = animalClass.getDeclaredField("name");
        System.out.println(f);
        f.setAccessible(true);//暴力反射,解除私有限定
        f.set(obj, "this is name value");
        System.out.println("验证name:" + stu);

    }
}

反射越过泛型检查

编写代码时,如果我们设置容器list为String类型,在调用add方法插入数据时入参传了其他类型,编译时会无法成功,但是通过反射却可以执行,实例代码:

package com.shuai.ioc.ref;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/*
 * 通过反射越过泛型检查
 *
 */
public class IgnoreType {
    public static void main(String[] args) throws Exception {
        List<String> list = new ArrayList<>();
        list.add("one");
        //反射获取list对象
        Class listClass = list.getClass();
        // 调用list对象的add方法
        Method m = listClass.getMethod("add", Object.class);
        m.invoke(list, 100);
        //输出验证
        for (Object obj : list) {
            System.out.println(obj);
        }
    }
}

欢迎关注公众号:java之旅

<think>嗯,用户想让我介绍一下Java的基础知识点,而且要让新手一看就懂。首先,我需要确定用户的需求是什么。他们可能刚开始学习编程,或者刚刚接触Java,想要一个全面但易懂的概览。我需要确保覆盖所有基础内容,但要过于深入,避免让新手感到困惑。 首先,我应该从Java的基本概念开始,比如Java的特点,比如跨平台、面向对象这些。然后可能需要解释开发环境的搭建,比如JDK、JRE、IDE的选择,比如Eclipse或IntelliJ IDEA。但用户可能更关心知识点本身,环境配置可能可以简略带过,或者放到后面。 接下来是基础语法,变量、数据类型、运算符、流程控制这些肯定是必须的。然后面向对象的部分,类、对象、继承、多态、封装、抽象类、接口,这些需要详细解释,但要用简单的例子。例如,用动物和猫狗的例子来说明继承和多态。 然后,可能需要涵盖异常处理,包括常见的异常类型和try-catch块。还有数组和集合框架,比如List、Set、Map的区别和使用场景。输入输出流也是基础的一部分,但可能需要简单介绍,避免太多细节。 多线程和网络编程可能属于进阶内容,但作为基础知识点,可能需要提及基本概念,比如线程的创建方式,Runnable接口和Thread类的区别。网络编程可以简要介绍Socket编程,但需要深入。 最后,可能需要一些学习建议,帮助新手规划学习路径,推荐书籍或在线资源。同时,提醒他们多练习,参与项目,使用IDE的重要性。 在组织内容时,要结构清晰,分点列出,每个部分用简单的例子和类比,避免使用专业术语过多,或者解释清楚每个术语。例如,解释变量时,可以比喻为容器,装同类型的数据。面向对象的概念可以用现实中的例子,比如汽车作为类,具体的某辆车作为对象。 需要检查是否遗漏了重要的基础点,比如包的概念、访问修饰符、静态关键字、方法重载和重写,这些在面向对象中很重要。还有基本的数据结构,如数组和集合的区别,ArrayList和LinkedList的同。 另外,要注意用户的身份是新手,所以语言要尽量通俗易懂,避免复杂的概念堆砌。每个知识点点到为止,需要深入底层原理,但确保正确性。例如,解释JVM的时候,可以简单说它是运行Java程序的虚拟机,让Java跨平台。 可能还需要考虑常见的误区,比如基本数据类型和包装类的区别,==和equals的同,这些在初学阶段容易出错的地方,可以适当提醒。 最后,总结部分要简明扼要,鼓励用户多动手实践,因为编程学习离开实际操作。可能还需要推荐一些练习项目,比如简单的计算器、学生管理系统等,帮助巩固知识。 总之,整个思考过程需要围绕如何将Java的基础知识点系统化、简单化地呈现,用新手能理解的语言和例子,结构清晰,逐步引导,确保覆盖全面但过载。</think>以下是专为新手整理的Java基础知识点详解,采用**分模块+通俗类比**的方式讲解: --- ### 一、Java基础概念(先建立“世界观”) 1. **Java是什么** - 一种**跨平台**编程语言(写一次代码,Windows/Mac/Linux都能运行) - 核心机制:`JVM`(虚拟机,像“翻译官”把Java代码转成机器能懂的语言) 2. **JDK与JRE** - `JDK` = 开发工具箱(含编译器、调试工具等) - `JRE` = 运行环境(仅能运行Java程序) --- ### 二、基础语法(从“单词”到“句子”) 1. **变量与数据类型** - **变量**:存储数据的容器 ```java int age = 20; // 整型 double price = 9.9; // 小数 char grade = 'A'; // 单个字符 String name = "小明"; // 字符串(注意首字母大写) ``` - **基本数据类型**:`int`, `double`, `boolean`, `char`等(共8种) 2. **运算符** - 算术:`+ - * / %` - 比较:`== != > <` - 逻辑:`&&(与) ||(或) !(非)` 3. **流程控制** - **条件语句** ```java if (score >= 60) { System.out.println("及格"); } else { System.out.println("及格"); } ``` - **循环语句** ```java for (int i = 0; i < 5; i++) { // 打印0到4 System.out.println(i); } ``` --- ### 三、面向对象(OOP核心思想) 1. **类与对象** - **类**:设计图(如“汽车设计图”) - **对象**:具体实例(如“一辆红色宝马”) ```java // 定义类 class Dog { String name; void bark() { System.out.println("汪汪!"); } } // 创建对象 Dog myDog = new Dog(); myDog.bark(); ``` 2. **四大特性** - **封装**:隐藏内部细节(如手机内部电路可见,只提供按键) ```java private String password; // 私有属性,外部无法直接访问 ``` - **继承**:子类继承父类特性(如“猫”继承“动物”的吃、睡行为) ```java class Cat extends Animal { ... } ``` - **多态**:同一方法同表现(如“动物”叫,猫“喵”、狗“汪”) - **抽象**:定义规范实现细节(如“交通工具”必须能run(),具体实现由子类完成) --- ### 四、常用工具类 1. **字符串处理** ```java String s = "Hello"; System.out.println(s.length()); // 长度 System.out.println(s.substring(1,3)); // 截取"el" ``` 2. **集合框架** - **List**(有序可重复):`ArrayList`(数组实现)、`LinkedList`(链表实现) - **Set**(无序重复):`HashSet` - **Map**(键值对):`HashMap` ```java List<String> list = new ArrayList<>(); list.add("苹果"); ``` --- ### 五、异常处理(代码的“保险机制”) ```java try { int result = 10 / 0; // 可能出错的代码 } catch (ArithmeticException e) { System.out.println("除数能为0!"); // 捕获异常 } finally { System.out.println("无论是否出错都会执行"); // 清理资源 } ``` --- ### 六、学习路线建议 1. **初级阶段** - 掌握基础语法 → 理解OOP → 练习小项目(如计算器) 2. **中级阶段** - 学习集合、IO流 → 多线程 → 网络编程 3. **高级阶段** - 框架(Spring)→ 数据库(MySQL)→ 分布式系统 --- ### 附:避坑指南 - `==`比较对象时比较的是内存地址,比较内容用`.equals()` - 循环中避免频繁操作字符串(用`StringBuilder`代替`String`) - 集合使用泛型指定类型(如`List<String>`避免类型转换错误) 学习资源推荐:《Java核心技术 卷Ⅰ》(书籍)、菜鸟教程(网站)、B站韩顺平课程(视频)。**关键是多写代码!** 从Hello World开始,逐步实现小功能,积累成就感。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值