Java基础重点——反射机制入门、使用

前言
反射机制确实是Java基础重点,当然本文概括的并不是很全面,仅仅是对反射进行着手,要全面理解反射,必不可少的前提知识是Class类,这篇反射文章讲的比较全,可以参考如下文章

【Java基础】反射机制与Class对象学习总结


如何定义反射: 一句话定义反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法,所谓反射其实是获取类的字节码文件,也就是.class文件
如何理解反射:平时我们要调用某个类中的方法的时候都需要创建该类的对象,通过对象去调用类里面的方法,反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了,在这种情况下(没有创建对象)我们都能够对它的方法和属性进行调用,我们把这种 动态获取对象信息和调用对象方法的功能称之为反射机制

正常的操作类

package com.FanSe;

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

public class DemoOne {
	
	private String name;
	public int age;
   public String getName() {
		return name;
	}

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

   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
	//正常操作类
	   DemoOne one=new DemoOne();
	   one.setName("我");
	   System.out.println(one.getName()+"好帅");    //我好帅
));
}
   
}

反射操作类

package com.FanSe;

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

public class DemoOne {
	
	private String name;
	public int age;
	
   public String getName() {
		return name;
	}

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

   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
	
//    1、获取类的 Class 对象实例
	   Class demo=Class.forName("com.FanSe.DemoOne");
	   
//	  2、通过类的实例的getmethod方法得到Method对象
	  Method setNameMethod = demo.getMethod("setName", String.class);
	  
//	  3、根据class对象实例的getconstructor方法获取Constructor对象
	  Constructor demooneConstructor = demo.getConstructor();
	  
//	  4、使用constructor对象的newinstance方法获取反射类对象实例
	  Object newInstance = demooneConstructor.newInstance();
	  
//	  5、利用invoke方法调用方法
	  setNameMethod.invoke(newInstance, "我");
	  
//	  6、获取方法的method对象
	  Method getName =demo.getMethod("getName");
	  
	  System.out.println(getName.invoke(newInstance)+"好帅");  //我
}
   
}

上面两段代码的执行结果,其实是完全一样的。但是其思路完全不一样,第一段代码在未运行时就已经确定了要运行的类(FanSe),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.FanSe.DemoOne)。

一般情况下我们使用反射获取一个对象的步骤:

1、获取类的 Class 对象实例的三种方式
第一种,使用Class.forName 静态方法。

当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象最常用,必须掌握

Class classDemo = Class.forname("com.FanSe.DemoOne");
第二种,使用 .class方法。

这种方法只适合在编译前就知道操作的 Class,但是这种方法需要导入类的包,依赖性太强,所以用的比第一种稍微要少【重点】

Class classDemo = 类名.class;
第三种,使用类对象的 getClass() 方法。

这种方法已经创建了对象,那么这个时候就不需要去进行反射了,显得有点多此一举。【不常用,了解即可

ClassDemo str = new ClassDemo();
Class clz = str.getClass();
2、根据 Class 对象实例获取 Constructor(构造函数) 对象
Constructor demoConstructor =  classDemo.getConstructor();
3、使用 Constructor 对象的 newInstance 方法(实例)获取反射类对象
 Object classDemoObj = demoConstructor.newInstance();
如果要反射某一个方法,则需要经过下面的步骤(开发中经常反射类方法):
一:通过类的实例的getmethod方法得到Method对象
  Method setNameMethod = classDemo.getmethod("setName", String.class);   

注意:Method Class.getMethod(String name, Class<?>… parameterTypes)的作用是获得对象所声明的公开方法

getMethod方法的第一个参数name是要获得方法的名字,而第二个参数parameterTypes是按声明顺序标识该方法形参类型

//如果获得classDemo对象的setName方法中没有形参,那么parameterTypes为null,如下:

    classDemo.getClass().getMethod("classDemo", null);
二:利用一中得到的Method对象的invoke方法调用函数方法
  setNameMethod.invoke(newInstance, "我");

注意
Method中invoke(Object obj,Object…args)方法的第一个参数为类的实例**,**第二个参数为相应函数中的参数

在 JDK 中,反射相关的 API 可以分为下面几个方面:

获取反射的 Class 对象、通过反射创建类对象、通过反射获取类属性方法及构造器

通过反射创建类对象(两种方法)

通过反射创建类对象主要有两种方式:通过 Class 对象的 newInstance() 方法、通过 Constructor 对象的 newInstance() 方法。

第一种:通过 Class 对象的 newInstance() 方法【只能默认无参数构造方法】
 Class clz = classDemo.class;
 ClassDemo classDemo = (ClassDemo)clz.newInstance();
第二种:通过 Constructor 对象的 newInstance() 方法【可以选择任何构造方法】
Class clz = classDemo.class;
Constructor constructor = clz.getConstructor();
ClassDemo classDemo= (ClassDemo)constructor.newInstance();
两种方法的区别:

通过 Constructor 对象(第二种)创建类对象可以选择特定构造方法,而通过 Class 对象(第一种)则只能使用默认的无参数构造方法。下面的代码就调用了一个有参数的构造方法进行了类对象的初始化,这种情况就只能使用第二种方法创建类对象。

   Class clz = ClassDemo.class;
    Constructor constructor = clz.getConstructor(String.class, int.class);
    ClassDemo classDemo= (ClassDemo)constructor.newInstance("小明", 15);  //有参构造方法
反射获取类属性、方法、构造器

我们通过 Class 对象的 getFields() 方法可以获取 Class 类的属性,但无法获取私有属性

Class clz = ClassDemo.class;
Field[] fields = clz.getFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

输出结果是:

price
而如果使用 Class 对象的 getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性

Class clz = ClassDemo.class;
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
    System.out.println(field.getName());
}

输出结果是:

name
age

与获取类属性一样,当我们去获取类方法、类构造器时,如果要获取私有方法或私有构造器,则必须使用有 declared 关键字的方法。

反射的重要性

当我们懂得了如何使用反射后,或许大家平时没有使用过反射,但是在开发 Web 项目的时候会经常用到反射,正所谓,无反射不框架!可见反射的重要性

  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宜春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值