Java反射机制(适合初学者)

本文是为初学者准备的Java反射机制介绍,包括反射的概念、功能、相关类以及实例演示,帮助理解如何获取类信息、创建对象、访问属性和方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java反射机制(初学者福利)

前言

最近在学习Java的反射机制,看了很多网上的资料,感觉有点深,初学者理解起来有点困难,干脆把自己理解的写了些总结,希望能对初学反射机制的童鞋有些帮助,如果有不对的地方,还望各位侠士不吝指出.

注:部分内容来源于网络

一.什么是反射

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

我们通常写的程序都是静态的代码,就是编译之后就能够确定执行顺序的就是静态,而动态是需要程序在运行的时候才知道是如何执行的是便动态,这是我对于动态的理解.换句话说就是我们对想要获取的类在编译期间是完全不了解的,只有在运行的时候才知道.

二.有什么功能

Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。(好长啊,总之就是在运行时获取类的所有属性和方法,然后可以任意调用用里边的方法和属性)

三.Java为我们提供了这些反射机制中的类:

java.lang.Class;

java.lang.reflect.Constructor;

java.lang.reflect.Field;
java.lang.reflect.Method;

java.lang.reflect.Modifier;

很多反射中的方法,属性等操作我们可以从这四个类中查询。

四.具体功能实现

1.获取类

这里我以获取Person类为例

package reflect;

public class Person {
    private String name;
    private int age;

    public Person(){
        System.out.println("无参构造器");
    }

    public Person(String name, int age) {
        System.out.println("有参构造器");
        this.name = name;
        this.age = age;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
//设置的全局变量
//person类 全类名(路径, 我是放在src目录下的reflect目录里边)
    private static String str = "reflect.Person";
/**
     * 反射机制的三种获取类的方法
     * @throws ClassNotFoundException
     */
    @Test
    public void testGetClass() throws ClassNotFoundException {
        Class cla = null;

        //1.通过 类名.class 直接获得
        cla = Person.class;
        System.out.println("通过类名:" + cla);

        //2.通过 对象的getClass()方法获取, 这个使用的少(一般传的是Object, 不知道是什么类型的时候采用)
        Object object = new Person();
        cla = object.getClass();
        System.out.println("通过对象的getClass获取:" + cla);

        //3.通过全类名获取, 用的比较多, 但可能抛出ClassNotFoundException异常
        cla = Class.forName(str);
        System.out.println("通过全类名:" + cla);
    }

结果:

通过类名:class reflect.Person
无参构造器
通过对象的getClass获取:class reflect.Person
通过全类名:class reflect.Person

2.利用newInstance创建对象

/**
     * Class类的newInstance()方法,创建类的一个对象。
     *
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    @Test
    public void testNewInstance() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class clazz = Class.forName(str);

        //使用Class类的 newInstance()方法 创建类的一个对象
        //实际调用的类的那个 无参数的构造器(这就是为什么写的类的时候,要写一个无参数的构造器,就是给反射用的)
        //一般的,一个类若声明了带参数的构造器,也要声明一个无参数的构造器
        Object object = clazz.newInstance();
        System.out.println(object);
    }

结果:

无参构造器
Person{name='null', age=0}

这里有一个点需要注意,调用的类(这里是Person类)一定一定一定要有无参构造方法(为了避免重载构造方法后忘记写无参构造方法,最好在类创建的时候就写出来)

下面是重载无参构造方法后(没有无参构造方法)执行的结果:

Error:(32, 25) java: 无法将类 reflect.Person中的构造器 Person应用到给定类型;
  需要: java.lang.String,int
  找到: 没有参数
  原因: 实际参数列表和形式参数列表长度不同

3.获取类里边属性:分为所有的属性和指定的属性

/**
     * 获取类的所有属性
     * @throws ClassNotFoundException
     */
    @Test
    public void testGetDeclaredFields() throws ClassNotFoundException {
        Class clazz = Class.forName(str);

        //获取所有的属性
        Field[] fields = clazz.getDeclaredFields();

        //定义可变长的字符串,用来存储属性
        //通过追加的方法,将每个属性拼接到此字符串中
        StringBuffer strB = new StringBuffer();

        //最外边的public Class 类
        strB.append(Modifier.toString(clazz.getModifiers()) + " class " + clazz.getSimpleName() +"{\n");

        //里边的每一个属性
        for(Field field: fields){
            strB.append("\t");//空格
            strB.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
            strB.append(field.getType().getSimpleName() + " ");//属性的类型的名字,例如int, String
            strB.append(field.getName()+";\n");//属性的名字
        }

        strB.append("}");

        System.out.println(strB.toString());

    }

结果:

public class Person{
	private String name;
	private int age;
}
/**
     * 获取类的指定属性
     * @throws ClassNotFoundException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    @Test
    public void testGetDeclaredFiled() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {

        //1.获取类
        Class clazz = Class.forName(str);

        //2.获取age属性
        Field age = clazz.getDeclaredField("age");
        System.out.print(Modifier.toString(age.getModifiers()) + " " + age.getType().getSimpleName() + " " + age.getName() + "\n");

        //3.获取name属性
        Field name = clazz.getDeclaredField("name");
        System.out.print(Modifier.toString(name.getModifiers()) + " " + name.getType().getSimpleName() + " " + name.getName() + "\n");

        //实例化这个类
        Object obj = clazz.newInstance();
        
        //打破封装
        //使用反射机制可以打破封装性,导致了java对象的属性不安全
        age.setAccessible(true); 
    
        //给obj对象的age属性赋值 18
        age.set(obj, 18);
        System.out.println(age.get(obj));
    }

结果:

private int age
private String name
无参构造器
18

4.获取类里其他内容的相关方法

在这里就不再一一演示下面这些方法的使用,大家可以自己去code看看

方法关键字含义
getDeclaredMethods()获取所有的方法
getReturnType()获得方法的放回类型
getParameterTypes()获得方法的传入参数类型
  
getDeclaredMethod("方法名",参数类型.class,……)获得特定的方法
构造方法关键字含义
getDeclaredConstructors()获取所有的构造方法
getDeclaredConstructor(参数类型.class,……)获取特定的构造方法
父类和父接口含义
getSuperclass()获取某类的父类
getInterfaces()获取某类实现的接口

总结

这篇主要是介绍了如何使用反射机制,反射机制原理我将在下一篇中再和大家一起探讨(还在学习中,233),毕竟用轮子比造轮子简单.

我刚开始看反射机制时也不是太懂,然后我就反复看,最重要的是反复code,然后反复理解,逐渐对反射机制的掌握就加深了,先熟练使用轮子后再去学习如何造轮子总是最快的(学习其他知识也是一样).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值