Java反射(简单详细且易懂,快速入门)

目录

一、介绍反射

1.反射概述

2.反射主要应用场景

3.Class类 

二、使用反射

1.获取Class类

2.Class类常用方法

 3.示例代码

3.1 测试获取成员变量 

3.2 测试获取成员方法 

3.3 测试获取构造函数

3.4 通过反射创建对象

3.5 通过反射修改属性 

3.6 通过反射调用方法 


一、介绍反射

1.反射概述

Java反射是Java语言的一种特性,它允许程序在运行时自我检查并对内部成员进行操作。这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。具体来说,反射机制允许在运行状态中

对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意方法和属性,并且能改变它的属性

Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。其本质是JVM得到Class对象之后,再通过Class对象进行反编译,从而获取对象的各种信息。

2.反射主要应用场景

  • 在运行时判断任意一个对象所属的类;
  • 在运行时实例化任意一个类的对象;
  • 在运行时获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等;
  • 在运行时获取任意对象的属性,并且能改变对象的属性;
  • 在运行时调用任意对象的方法。

3.Class类 

在Java编程语言中,Class类是一个特殊的类,它用于表示JVM运行时的类或接口的信息。你可以把它看作是一个普通的类,但它描述的是所有的类的公共特性。

每个类在Java中都对应着一个Class对象,这个对象保存了该类的结构信息,如类名、字段、方法等。换句话说,Class类是一个反射工具,能提供很多方法用于获取类的各种信息,比如获取类名、判断该类是否是一个接口还是普通类等等。

二、使用反射

1.获取Class类

  • Class.forName("类的全路径");
  • 类名.Class
  • 对象名.getClass();
  • 包装类.TYPE
  • Class类.getSuperClass();

下面附上示例代码:

package com.cqs.reflect_;

public class ReflectTest1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //方法1:通过 Class.forName("类的全路径");获取Class
        Class class1 = Class.forName("com.cqs.reflect_.Student");
        //方法2:通过 类名.Class 获取Class
        Class class2 = Student.class;
        //方法3:通过 对象名.getClass(); 获取Class
        Student student = new Student("小明", "10001", 18);
        Class class3 = student.getClass();
        //方法4:通过 包装类.TYPE 获取Class
        Class class4 = Integer.TYPE;
        //方法5:通过 Class类.getSuperClass(); 获取Class
        Class class5 = class4.getSuperclass();
    }
}
class Student{
    private String name;
    private String number;
    public String sex;
    public int age;

    public Student(String name, String number, int age) {
        this.name = name;
        this.number = number;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }
}

2.Class类常用方法

调用Class的方法一般会返回三个对象

  • Field对象:存放获取对象的成员变量属性
  • Method对象:存放获取对象的方法
  • Constructor对象:存放获取对象的构造方法

下面是Class类的一些常用方法

  • 获取成员变量

getFields()//获取所有公开的成员变量,包括继承变量

getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量

getField(变量名)//获取指定公共属性的Field对象

 getDeclaredField(变量名)//获取指定包括私有,不包括继承的Field对象

  • 获取成员方法

getMethods()//获取所有可见的方法,包括继承的方法

getMethod(方法名,参数类型列表)//获取指定方法的Method对象
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)//获取指定包括私有,不包括继承的Method对象

  • 获取构造方法

getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)//获取指定包括私有,不包括继承Constructor对象

  • 总结:

getXXXs()//获取公开的包括继承的XXX对象

getDeclaredXXXs()//获取包括私有,不包括继承的XXX对象

getXXX(xx)//获取指定xx的XXX对象(公开的)

getDeclaredXXX(xx)//获取指定xx的XXX对象(包括私有,不包括继承)

其中XXX表示 Field/Method/Constructor 三者之一

方法名get后如果接Declared可以获取私有属性或者方法

方法名最后如果有s可以获取所有的XXX对象

  • 其他方法

getInterfaces()//返回一个包含class对象的数组,存放该类或者接口实现的接口

newInstance()//使用无参构造创建一个类的实例

getName()//返回该类的完整名

 3.示例代码

  定义Students类

class Student{
    private String name;
    private String number;
    public String sex;
    public int age;
    public Student(String name, String number, int age) {
        this.name = name;
        this.number = number;
        this.age = age;
    }
    public Student(String name){
        this.name = name;
    }
    private Student(String name, String number){
        this.name = name;
        this.number = number;
    }
    private void schooling(){
        System.out.println("去上学");
    }
    public String getName() {
        return name;
    }

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

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

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

3.1 测试获取成员变量 

package com.cqs.reflect_;

import java.lang.reflect.Field;

public class ReflectField {
    public static void main(String[] args) throws NoSuchFieldException {
        Class<Student> studentClass = Student.class;
        //测试getFields()函数
        Field []studentFields = studentClass.getFields();
        System.out.println("通过getFields获取Student类所有公开属性");
        for (Field field:studentFields) {
            System.out.println("属性的类型为:"+field.getType()+"属性的名称为:"+field.getName());
        }
        System.out.println();//换行

        //测试getDeclaredFields()函数
        Field []studentDeclaredFields = studentClass.getDeclaredFields();
        System.out.println("通过getDeclaredFields获取Student类所有属性(包括私有,不包括继承)");
        for (Field field :studentDeclaredFields) {
            System.out.println("属性的类型为:"+field.getType()+"\t属性的名称为:"+field.getName());
        }
        System.out.println();//换行

        //getField(String)函数
        Field field = studentClass.getField("age");
        System.out.println("通过getField(\"age\")获取公开属性age");
        System.out.println("属性的类型为:"+field.getType()+"\t属性的名称为:"+field.getName());
        System.out.println();//换行

        //测试getDeclaredField(String)函数
        Field DeclaredFiled = studentClass.getDeclaredField("name");
        System.out.println("通过getDeclaredField(\"name\")获取私有属性name");
        System.out.println("属性的类型为:"+field.getType()+"\t属性的名称为:"+field.getName());
    }
}

运行结果:

通过getFields获取Student类所有公开属性
属性的类型为:class java.lang.String属性的名称为:sex
属性的类型为:int属性的名称为:age

通过getDeclaredFields获取Student类所有属性(包括私有,不包括继承)
属性的类型为:class java.lang.String    属性的名称为:name
属性的类型为:class java.lang.String    属性的名称为:number
属性的类型为:class java.lang.String    属性的名称为:sex
属性的类型为:int    属性的名称为:age

通过getField("age")获取公开属性age
属性的类型为:int    属性的名称为:age

通过getDeclaredField("name")获取私有属性name
属性的类型为:int    属性的名称为:age

进程已结束,退出代码0

3.2 测试获取成员方法 

package com.cqs.reflect_;

import java.lang.reflect.Method;

public class ReflectMethod {
    public static void main(String[] args) throws NoSuchMethodException {
        Class<Student> studentClass = Student.class;
        //测试getMethods()函数
        Method[] methods = studentClass.getMethods();
        System.out.println("通过getMethods()获取所有公开方法");
        for (Method method : methods) {
            System.out.println(method.getName());
            Class[] plts = method.getParameterTypes();
            System.out.println("参数数量为:"+plts.length);
            for (Class p : plts) {
                System.out.println("参数类型为:"+p.getTypeName());
            }
        }
        System.out.println();//换行

        //测试getDeclaredMethods()函数
        Method[] DeclaredMethods = studentClass.getDeclaredMethods();
        System.out.println("通过getDeclaredMethods()获取所有方法(包括私有,不包括继承)");
        for (Method method : DeclaredMethods) {
            System.out.println(method.getName());
            Class[] plts = method.getParameterTypes();
            System.out.println("参数数量为:"+plts.length);
            for (Class p : plts) {
                System.out.println("参数类型为:"+p.getTypeName());
            }
        }
        System.out.println();//换行

        //测试getMethod(参数)函数
        Method method = studentClass.getMethod("setName", String.class);
        System.out.println("通过getMethod(\"getName\",String.class)获取getName方法");
        System.out.println(method.getName());
        Class[] plts = method.getParameterTypes();
        System.out.println("参数数量为:"+plts.length);
        for (Class p : plts) {
            System.out.println("参数类型为:"+p.getTypeName());
        }
        System.out.println();//换行

        //测试getDeclaredMethod(参数)函数
        Method DeclaredMethod = studentClass.getDeclaredMethod("schooling");
        System.out.println("通过getDeclaredMethod(\"schooling\")获取schooling方法");
        System.out.println(DeclaredMethod.getName());
        Class[] pls = DeclaredMethod.getParameterTypes();
        System.out.println("参数数量为:"+pls.length);
        for (Class p : pls) {
            System.out.println("参数类型为:"+p.getTypeName());
        }
    }
}

运行结果:

通过getMethods()获取所有公开方法
getNumber
参数数量为:0
getName
参数数量为:0
setName
参数数量为:1
参数类型为:java.lang.String
setNumber
参数数量为:1
参数类型为:java.lang.String
wait
参数数量为:0
wait
参数数量为:2
参数类型为:long
参数类型为:int
wait
参数数量为:1
参数类型为:long
equals
参数数量为:1
参数类型为:java.lang.Object
toString
参数数量为:0
hashCode
参数数量为:0
getClass
参数数量为:0
notify
参数数量为:0
notifyAll
参数数量为:0

通过getDeclaredMethods()获取所有方法(包括私有,不包括继承)
getNumber
参数数量为:0
getName
参数数量为:0
setName
参数数量为:1
参数类型为:java.lang.String
schooling
参数数量为:0
setNumber
参数数量为:1
参数类型为:java.lang.String

通过getMethod("getName",String.class)获取getName方法
setName
参数数量为:1
参数类型为:java.lang.String

通过getDeclaredMethod("schooling")获取schooling方法
schooling
参数数量为:0

3.3 测试获取构造函数

示例代码

package com.cqs.reflect_;

import java.lang.reflect.Constructor;

public class ReflectConstructor {
    public static void main(String[] args) {
        Class<Student> studentClass = Student.class;
        //测试getConstructors()函数
        Constructor[] constructors = studentClass.getConstructors();
        System.out.println("通过getConstructors()获取所有公开构造方法");
        for (Constructor con: constructors) {
            System.out.println("构造方法名称为:"+con.getName());
            Class plts[] = con.getParameterTypes();
            System.out.println("参数数量为:"+plts.length);
            System.out.println("形参类型为:");
            for (Class p: plts) {
                System.out.println(p);
            }
        }
        System.out.println();//换行

        //测试getDeclaredConstructors()函数
        Constructor[] DeclaredConstructors = studentClass.getDeclaredConstructors();
        System.out.println("通过getDeclaredConstructors()获取所有构造方法(包括私有,包括继承)");
        for (Constructor con : DeclaredConstructors) {
            System.out.println("构造方法名称为:"+con.getName());
            Class[] plts = con.getParameterTypes();
            System.out.println("参数数量为:"+plts.length);
            System.out.println("形参类型为:");
            for (Class p: plts) {
                System.out.println(p);
            }
        }
    }
}

运行结果

通过getConstructors()获取所有公开构造方法
构造方法名称为:com.cqs.reflect_.Student
参数数量为:3
形参类型为:
class java.lang.String
class java.lang.String
int
构造方法名称为:com.cqs.reflect_.Student
参数数量为:1
形参类型为:
class java.lang.String

通过getDeclaredConstructors()获取所有构造方法(包括私有,包括继承)
构造方法名称为:com.cqs.reflect_.Student
参数数量为:3
形参类型为:
class java.lang.String
class java.lang.String
int
构造方法名称为:com.cqs.reflect_.Student
参数数量为:1
形参类型为:
class java.lang.String
构造方法名称为:com.cqs.reflect_.Student
参数数量为:2
形参类型为:
class java.lang.String
class java.lang.String

3.4 通过反射创建对象

package com.cqs.reflect_;
import java.lang.reflect.Constructor;

public class Reflect_newInstance {
    public static void main(String[] args) throws Exception{
        Class studentClass = Student.class;
        Constructor c = studentClass.getConstructor(String.class, String.class, int.class);
        Object obj = c.newInstance("小明","1001",18);
        System.out.println(obj);

        //等价于
        Student s = new Student("小明", "1001", 10);
        System.out.println(s);

    }
}

运行结果

Student{name='小明', number='1001', sex='null', age=18}
Student{name='小明', number='1001', sex='null', age=10}

3.5 通过反射修改属性 

package com.cqs.reflect_;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Reflect_modifyAttribute {
    public static void main(String[] args) throws Exception{
        //通过反射创建对象
        Class studentClass = Student.class;
        Constructor c = studentClass.getConstructor(String.class, String.class, int.class);
        Object obj = c.newInstance("小明","1001",18);
        //通过属性名获取field对象
        Field f = studentClass.getDeclaredField("name");
        //取消属性访问权限控制
        f.setAccessible(true);
        //获取更改前name的值
        System.out.println("更改前:"+f.get(obj));
        System.out.println(obj);
        f.set(obj,"小刚");
        System.out.println("更改后:"+f.get(obj));
        System.out.println(obj);
    }
}

运行结果

更改前:小明
Student{name='小明', number='1001', sex='null', age=18}
更改后:小刚
Student{name='小刚', number='1001', sex='null', age=18}

3.6 通过反射调用方法 

package com.cqs.reflect_;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Reflection_callMethod {
    public static void main(String[] args) throws Exception{
        //通过反射创建对象
        Class<Student> studentClass = Student.class;
        Constructor c = studentClass.getConstructor(String.class, String.class, int.class);
        Object obj = c.newInstance("小明","1001",18);
        //获取setName方法并调用
        Method m1 = studentClass.getDeclaredMethod("setName", String.class);
        m1.invoke(obj,"小飞");
        System.out.println(obj);
        //获取schooling方法
        Method m2 = studentClass.getDeclaredMethod("schooling");
        //因为schooling为私有方法,所以得取消权限访问控制
        m2.setAccessible(true);
        m2.invoke(obj);
    }
}

运行结果 

去上学
Student{name='小飞', number='1001', sex='null', age=18}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值