反射
反射是一种机制/功能,
利用该机制/功能可以在程序运行过程中对类进行解剖并操作类中的构造方法,成员方法,成员属性。
反射的应用场景
1. 开发工具中写代码时的提示
开发工具之所能够把该对象的方法和属性展示出来就使用利用了反射机制对该对象所有类
进行了解剖获取到了类中的所有方法和属性信息,这是反射在 IDE 中的一个使用场景。
2. 各种框架的设计
Java 的三大框架,简称 SSH,SSM。
【SSH = Struts2 + Spring + Hibernate】
【SSM = Springmvc + Spring + MyBatis】
这三大框架的内部实现也大量使用到了反射机制,所以要想学好这些框架,则必须要
求对反射机制熟练了。
使用反射机制解剖类的前提
必须先要获取字节码对象,即 Class 类型对象。
说明:
Java 中使用 Class 类表示 class 文件。任何一个 class 文件都是 Class 类的一个对象。
获取 Class 对象的三种方式
通过类名.class 获取
通过 Object 类的成员方法 getClass()方法获取
通过 Class.forName("全限定类名")方法获取
public class Demo01 {
public static void main(String[] args) throws Exception{
Class c1 = java.lang.String.class;
Class c2 = new String().getClass();
Class c3 = Class.forName("java.lang.String");
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
}
}
获取 Class 对象的信息
获取简单类名
String getSimpleName(); 获取简单类名,只是类名,没有包
获取完整类名
String getName(); 获取完整类名,包含包名 + 类名
创建对象
T newInstance() ; 创建此 Class 对象所表示的类的一个新实例。
要求:类必须有public 的无参数构造方法
public class Demo02 {
public static void main(String[] args) throws Exception {
Class c = String.class;
System.out.println(c.getSimpleName());
System.out.println(c.getName());
Object obj = c.newInstance();
if(obj instanceof String){
String s = (String) obj;
System.out.println(s.length());
}
}
}
获取 Class 对象的 Constructor 信息(构造方法信息)
利用反射可以在程序运行过程中对类进行解剖并操作里面的成员。
而一般常操作的成员:构造方法,成员方法,成员属性,
怎么利用反射来操作这些成员以及操作这些成员能干什么,先来看看怎么操作构造方法。
要通过反射操作类的构造方法,我们需要先知道一个Constructor 类。
Constructor
Constructor 是构造方法类,
类中的每一个构造方法都是 Constructor 的对象,
通过Constructor 对象可以实例化对象。
Class 类中与 Constructor 相关方法
1. Constructor[] getConstructors()
获取所有的 public 修饰的构造方法
2. Constructor[] getDeclaredConstructors()
获取所有构造方法,包括 privat 修饰的
3. Constructor getConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,只能获得 public 修饰的构造方法
4. Constructor getDeclaredConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,包括 private 修饰的构造方法
Constructor类中常用方法
1. T newInstance(Object... initargs)
根据指定参数创建对象
2. void setAccessible(true)
暴力反射,设置为可以直接访问私有类型的构造方法
public class Demo03 {
@Test
public void test1() throws Exception {
Class clazz = Student.class;
Constructor c = clazz.getConstructor(int.class);
Object obj = c.newInstance(22);
}
@Test
public void test2() throws Exception{
Class clazz = Student.class;
Constructor c = clazz.getDeclaredConstructor(int.class,String.class);
c.setAccessible(true);
Object obj = c.newInstance(22,"jack");
}
}
public class Student {
private int id;
private String name;
public Student(){
System.out.println("public Student()");
}
public Student(int id){
System.out.println("public Student(int id)");
}
private Student(int id,String name) {
System.out.println("private Student(int id,String name)");
}
public void run(){
System.out.println("public void run()");
}
public void jump(int id){
System.out.println("public void jump(int id)");
}
private void sleep(int id,String name){
System.out.println("private void sleep(int "+id+",String "+name+")");
}
public static void close(){
System.out.println("public static void close()");
}
public static void main(String[] args){
System.out.println("public static void main(String[] args)");
}
}
获取 Class 对象的 Method 信息(成员方法信息)
操作完构造方法之后,就来看看反射怎么操作成员方法了。
同样在操作成员方法之前我们需要学习一个类:Method 类。
Method 类
Method 是方法类,
类中的每一个方法都是 Method 的对象,
通过 Method 对象可以调用方法。
Class类中与Method相关方法
1. Method[] getMethods()
获取所有的public修饰的成员方法,
2. Method[] getDeclaredMethods()
获取当前类中所有的方法,包含私有的,
3. Method getMethod("方法名", 方法的参数类型... 类型)
根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
4. Method getDeclaredMethod("方法名", 方法的参数类型... 类型)
根据方法名和参数类型获得一个方法对象,包括private修饰的
Method类中常用方法
1. Object invoke(Object obj, Object... args)
根据参数args调用对象obj的该成员方法,如果obj=null,则表示该方法是静态方法
2. void setAccessible(true)
暴力反射,设置为可以直接调用私有修饰的成员方法
public class Demo04 {
@Test
public void test1() throws Exception{
Class clazz = Student.class;
Method m = clazz.getMethod("jump",int.class);
m.invoke(clazz.newInstance(),22);
}
@Test
public void test2() throws Exception{
Class clazz = Student.class;
Method m = clazz.getDeclaredMethod("sleep",int.class,String.class);
m.setAccessible(true);
m.invoke(clazz.newInstance(),22,"jack");
}
@Test
public void test3() throws Exception{
Class clazz = Student.class;
Method m = clazz.getDeclaredMethod("close",null);
m.invoke(null);
}
@Test
public void test4() throws Exception{
Class clazz = Student.class;
Method m = clazz.getDeclaredMethod("main",String[].class);
String[] args = {"a","b","c","d"};
Object[] obj = {args};
m.invoke(null,obj);
}
}
使用反射传入对象类型的数组时,默认情况会先对数组进行拆除.
class Person{
public void eat(String[] foods){
for(String food : foods){
System.out.println("吃"+food);
}
}
public void sum(int[] nums){
int sum = 0;
for(int num : nums){
sum+=num;
}
System.out.println("结果是:"+ sum);
}
}
public class Demo1 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.itheima.reflect.Person") ;
Person p = (Person) clazz.newInstance();
Method method = clazz.getMethod("eat", String[].class);
Method method2 = clazz.getMethod("sum", int[].class);
method2.invoke(p, new int[]{1,2,3});
}
}
获取Class对象的Field信息
Field是属性类,类中的每一个属性都是Field的对象,通过Field对象可以
给对应的属性赋值和取值。
Class类中与Field相关方法
1. Field[] getFields()
获取所有的public修饰的属性对象,返回数组
2. Field[] getDeclaredFields()
获取所有的属性对象,包括private修饰的,返回数组
3. Field getField(String name)
根据属性名获得属性对象,只能获取public修饰的
4. Field getDeclaredField(String name)
根据属性名获得属性对象,包括private修饰的
Field类中常用方法
String getName()
获取字段名
Type getType()
获取字段名对应的类型
基本类型:setXxx方法和getXxx方法
引用类型:set方法和get方法
void setAccessible(true)
暴力反射,设置为可以直接访问私有类型的属性
public class Demo05 {
@Test
public void test1() throws Exception{
Class clazz = Student.class;
Field[] fs = clazz.getDeclaredFields();
for (Field f : fs) {
System.out.println(f.getName()+"#"+f.getType());
}
}
@Test
public void test2() throws Exception {
Class clazz = Student.class;
Object obj = clazz.newInstance();
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
if(nameField.getType()==String.class){
nameField.set(obj,"jack");
System.out.println(nameField.get(obj));
}
}
}
编写一个方法可以根据配置文件产【任意类型】的对象,并读取属性文件中的值,【设置】到这个类型的对象中。