Java反射机制初探

类的反射机制

1.反射的概念

反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

在计算机科学领域,反射是一类应用,它们能够自描述和自控制。

这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

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

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象

1.1 Java的反射机制

在Java中的反射机制,被称为Reflection 。 它允许运行中的Java程序对自身进行检查,并能直接操作

程序的内部属性或方法

注意一点JVM并不是在一开始就把一个程序就所有的类都加载到内存中,而是到用的时候才把它加载进

来,当Java虚拟机载入一个类的时候,它就会自动创建一个Class类()的实例来表示这个类,该实例中包

含了完整的类的结构信息。

ps:Class本身就是一个单独的类,java.lang.Class

这个对象就像一面镜子将类的结构展示给我们,所以我们形象的称之为“反射”![img]
在这里插入图片描述

图源:https://blog.csdn.net/sirie/article/details/81435090

1.2 反射的功能

1、在运行时判断任意一个对象所属的类;

2、在运行时构造任意一个类的对象;

3、在运行时判断任意一个类所具有的成员变量和方法;

4、在运行时调用任意一个对象的方法;

5、生成动态代理

之后会有举例说明

2 反射的三种方式

2.1 直接通过类名.Class获得
Class<User> userClass = User.class;
System.out.println(userClass);//class com.goktech.User
2.2 通过对象的getClass()方法获取
User user = new User();
Class userClass = user.getClass();
System.out.println(userClass);//class com.goktech.User
2.3 通过全类名获取

使用Class 类,但是可能会抛出classNotFoundException的异常

        Class c = null;
        try {
            c = Class.forName("com.goktech.User");
            System.out.println(c);//class com.goktech.User
            System.out.println(c.getName());//com.goktech.User
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

3、反射中常用的方法

测试用的User类

public class User {
    private String name;
    public int age;
    private String school;
    
    public User() {
    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private User(String name, int age, String school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }

    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;
    }

    public String getSchool() {
        return school;
    }
    public void setSchool(String school) {
        this.school = school;
    }

    public void say(){
        System.out.println("什么都没说:");
    }
    public void say(String message){
        System.out.println("说了:"+message);
    }
    public void say(String message,Integer age){
        System.out.println("说了:"+message+",年龄:"+age);
    }

    @Override
    public String toString() {
        ..........
    }
}

通过全限定类名获取类

 Class c = null;
        try {
            c = Class.forName("com.goktech.User");
			//其他方法写这里
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
3.1 获取类的构造方法

注意:私有的都带有Declared,要看清每个constructor后有没有加s

//获取所有的构造方法(有参+无参、共有+私有)
Constructor[] constructors = c.getConstructors();
System.out.println(Arrays.toString(constructors));
//[public com.goktech.User(java.lang.String,int), public com.goktech.User()]

//获取公有的无参构造方法
Constructor constructor = c.getConstructor(null);
System.out.println(Arrays.toString(new Constructor[]{constructor2}));
//[public com.goktech.User()]

//获取公有的有参构造
constructor = c.getConstructor(new Class[]{String.class,int.class});
System.out.println(constructor);
//[public com.goktech.User(java.lang.String,int)]

//获取私有的有参构造
constructor = c.getDeclaredConstructor(new Class[]{String.class,int.class,String.class});
System.out.println(constructor);
//private com.goktech.User(java.lang.String,int,java.lang.String)
3.2 获取字段(属性)
//获取所有公有字段(私有不可获得)
Field[] fields = c.getFields();
	for (Field field: fields) {
        System.out.println(field); //public int com.goktech.User.age
    }

//获取所有字段(私有+公有)
fields = c.getDeclaredFields();
    for (Field field:  fields) {
        System.out.println(field);
         //private java.lang.String com.goktech.User.name
         // public int com.goktech.User.age
         //private java.lang.String com.goktech.User.school
    }

//获取指定字段的filed
Field name = c.getField("name");
//若这个字段是私有的得加上下面一行才能获取
//但是由于是私有字段还是不能访问,可以进行属性修改,结合实例化对象使用
name.setAccessible(true);
3.3 获取方法
//获取所有方法
Method[] methods = c.getDeclaredMethods();
System.out.println(Arrays.toString(methods));
//获取class对象的所有方法,包括父类
Method[] allMethods = c.getMethods();
//因为获取了父类的方法,所以这里打印出的的方法比上面多了Object类的方法
System.out.println(Arrays.toString(allMethods));

//获取指定参数名的方法
//第一个参数是方法的名字,后面参数是方法中的参数,没有就写null
Method method = c.getDeclaredMethod("setAge", int.class);
System.out.println(method);
3.4 使用反射创建对象
//方法一:通过Class的newInstance()方法,常用
Object o = c.newInstance();

//方法二通过Constructor的newInstance()方法 ,先使用Class对象获取指定的Constructor对象 ,再调用
//Constructor对象的newInstance
Field field = clazz.getField("password"); 
Constructor constructor = clazz.getConstructor(); 
Object object = constructor.newInstance(); 
System.out.println("实例化出来的对象:"+object); 
//为属性设置值 
field.set(object, "123456");
User user = (User)object;
System.out.println(user);
3.5 利用Java反射机制对参数的值进行修改
//获得类
Class c = Class.forName("com.goktech.User");
Object o = c.newInstance();//获得类的实例

//获得User类中指定的属性
Field nameField = c.getDeclaredField("name");
//因为是私有的所以要解除访问控制
nameField.setAccessible(true);

//通过nameField 的get方法可以获得name值
String name = (String) nameField.get(o);
System.out.println(name);//null

//通过通过nameField的set方法可以设置值
nameField.set(o,"zhangsan");
name = (String) nameField.get(o);
System.out.println(name);//zhangsan
3.6 invoke方法实现动态调用
//获得类
Class c = Class.forName("com.goktech.User");
Object o = c.newInstance();//获得类的实例

Method m1 = c.getDeclaredMethod("say", String.class);
Method m2 = c.getDeclaredMethod("say");

m1.invoke(o,"helloword");//说了:helloword
m2.invoke(o);//什么都没说:

Method m3 = c.getDeclaredMethod("say", String.class, Integer.class);
m3.invoke(c.newInstance(),"my name is..",20);//说了:my name is..,年龄:20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值