一、Java反射框架主要提供以下功能
- 1.在运行时判断任意一个对象所属的类;
- 2.在运行时构造任意一个类的对象;
- 3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
- 4.在运行时调用任意一个对象的方法
二、主要用途
反射最重要的用途就是开发各种通用框架(Spring,hibernate,mybatis)。
三、基本反射功能的实现(反射相关的类一般都在java.lang.relfect包里)
- 1、获得Class对象
- 2、判断是否为某个类的实例
- 3、创建实例
- 4、获取方法
- 5、获取构造器信息
- 6、获取类的成员变量(字段)信息
- 7、调用方法
- 8、利用反射创建数组
通过转载大佬的实例帮助了解:
四、类例
1.hero类
package pojo;
public class Hero {
public String name; //姓名
public float hp; //血量
public float armor; //护甲
public int moveSpeed; //移动速度
}
获取类对象有3种方式
1.Class.forName()
2.Hero.class
3.new Hero().getClass()
在一个JVM中,一种类,只会有一个类对象存在(此处准确是在ClassLoader下,只有一个类对象)。所以以上三种方式取出来的类对象,都是一样。
2 .用反射机制创建对象
步骤:与传统的通过new 来获取对象的方式不同反射机制,反射会先拿到Hero的“类对象”,然后通过类对象获取“构造器对象”再通过构造器对象创建一个对象。
1.获取类对象 Class class = Class.forName("pojo.Hero");
2.获取构造器对象 Constructor con = clazz.getConstructor(形参.class);
3 获取对象 Hero hero =con.newInstance(实参)
//这是最简单的获取方法,当Hero的构造方法不是无参构造方法时,获取构造器对象略有不同
给Hero类添加构造方法:
//(默认的构造方法)
Hero(String str){
System.out.println("(默认)的构造方法 s = " + str);
//无参构造方法
public Hero(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
public Hero(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Hero(String name ,float hp){
System.out.println("姓名:"+name+"血量:"+ hp);
}
//受保护的构造方法
protected Hero(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Hero(float hp){
System.out.println("私有的构造方法 血量:"+ hp);
}
3.通过反射机制获取对象:
package test;
public class ConstructorTest {
/*
* 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
* 1.获取构造方法:
* 1).批量的方法:
* public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
* 2).获取单个的方法,并调用:
* public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
* 2.创建对象
* Constructor对象调用newInstance(Object... initargs)
*/
public static void main(String[] args) throws Exception {
//1.加载Class对象
Class clazz = Class.forName("pojo.Hero");
//2.获取所有公有构造方法
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("*****************获取公有、无参的构造方法*******************************");
Constructor con = clazz.getConstructor(null);
//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
//2>、返回的是描述这个无参构造函数的类对象。
System.out.println("con = " + con);
//调用构造方法
Object obj = con.newInstance();
System.out.println("******************获取私有构造方法,并调用*******************************");
con = clazz.getDeclaredConstructor(float.class);
System.out.println(con);
//调用构造方法
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
obj = con.newInstance(100);
}
}
//总结获取构造器对象方法:
1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
2).获取单个的方法:
public Constructor getConstructor(Class… parameterTypes): 获取单个的"公有的"构造方法
public Constructor getDeclaredConstructor(Class…parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
4.获取成员变量并使用
步骤;
1. 获取Hero类的对象
2. 获取属性 Field f1 = h.getDeclaredField("属性名")
3. 修改属性 f1.set(hero,实参),注意这里的hero是对象,不是类对象
Hero hero=new Hero();
hero.setName("hero1");
try {
//获取类HeroPlus的名字叫做name的字段
System.out.println("修改前的name:"+hero.name);
Field f1= hero.getClass().getDeclaredField("name");
//修改这个字段的值
f1.set(hero, "hero2");
//打印被修改后的值
System.out.println("修改后的name:"+hero.name);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//修改前的name:hero1
//修改后的name:hero2
//补充:getField和getDeclaredField的区别
//getField只能获取public的,包括从父类继承来的字段。
//getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。
(注:这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))
5.获取成员方法并使用
1.获取Hero类的对象
2.获取成员方法:
public Method getMethod(String name ,Class<?>… parameterTypes):
获取"公有方法";(包含了父类的方法也包含Object类)
public Method getDeclaredMethods(String name ,Class<?>… parameterTypes) :
获取成员方法,包括私有的(不包括继承的)
3.参数解释:
name : 方法名;
Class … : 形参的Class类型对象
4.调用方法(invoke)
Method --> public Object invoke(Object obj,Object… args):
5.参数说明:
obj : 要调用方法的对象;
args:调用方式时所传递的实参;
Hero hero = new Hero("hero1");
try {
// 获取这个名字叫做setName,参数类型是String的方法
Method m = hero.getClass().getMethod("setName", String.class);
System.out.println("修改前"+hero.getName());
// 对hero对象,调用这个方法
m.invoke(hero, "hero2");
// 使用传统的方式,调用getName方法
System.out.println("修改后"+hero.getName());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//修改前hero1
//修改后hero2
五、Class类方法总结
六、关于反射的用法举例
反射非常强大,但是从上面的记录来看,反而觉得还不如直接调用方法来的直接和方便。
通常来说,需要在学习了Spring 的依赖注入,反转控制之后,才会对反射有更好的理解
。
本文参考