参考结合网上博客做个笔记
反射的定义:
反射是java语言的一个特性,它允许程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取它所有的成员变量和方法并且显示出来。
反射机制的优点与缺点:
首先要搞清楚为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。
==静态编译==:在编译时确定类型,绑定对象,即通过。
==动态编译==:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
==反射机制的优点==:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
==反射机制的缺点==:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
Java反射使用
1)、forName
public static Class> forName(String className) throws ClassNotFoundException
相当于:Class.forName(className, true, currentLoader)
参数 :
className - 所需类的完全限定名称。
Class c = Class.forName("com.ash.demo.Test")
//结果
class com.ash.demo.Test
2)、.class
Class c2 = String.class;
//结果
class java.lang.String
--
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//获取对象
Class> student = Class.forName("com.test.Student");
//创建实例
Student student1 = (Student) student.newInstance();
//通过反射获取对象的属性、方法
student1.setAge(18);
student1.setName("zs");
student1.setClassName("移动应用开发");
System.out.println(student1);
}
}
//结果
Student{name='zs', age=18, className='移动应用开发'}
常用方法:
getDeclaredMethods() 获取所有的方法(包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法)
getReturnType() 获得方法的返回类型
getParameterTypes() 获得方法的传入参数类型
getDeclaredMethod(String name, Class>... parameterTypes) 获得特定的方法
3)、getMethod
public Method getMethod(String name, Class>... parameterTypes)
参数 :
name - 方法的名称
parameterTypes - 参数列表
结果 :
方法对象匹配指定的 name和 parameterTypes
4)、invoke
public abstract Object invoke(Class m, Object... args)
参数 :
m - 在服务上调用的方法
args - 方法参数
--
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
try {
//反射类
Class demoClass = Demo02.class;
//获取类的方法
Method cs = demoClass.getMethod("cs", String.class);
//调用方法
cs.invoke(demoClass.newInstance(),"zs");
} catch (NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
class Demo02 {
public void cs(String name) {
System.out.println("----" + name + "----");
}
}
Spring通过配置进行实例化对象,并放到容器中的伪代码:
//解析元素的id属性得到该字符串值为“studentDao”
String idStr = "studentDao";
//解析元素的class属性得到该字符串值为“"com.ash.demo.service.StudentDaoImpl”
String classStr = ""com.ash.demo.service.StudentDaoImpl";
//利用反射知识,通过classStr获取Class类对象
Class> cls = Class.forName(classStr);
//实例化对象
Object obj = cls.newInstance();
//container表示Spring容器
container.put(idStr, obj);
当一个类里面需要应用另一类的对象时
//解析元素的name属性得到该字符串值为“studentDao”
String nameStr = "studentDao";
//解析元素的ref属性得到该字符串值为“studentDao”
String refStr = "studentDao";
//生成将要调用setter方法名 , substring(开始取值,结束(不取值)),toUpperCase转换为大写
String setterName = "set" + nameStr.substring(0, 1).toUpperCase()
+ nameStr.substring(1);
//获取spring容器中名为refStr的Bean,该Bean将会作为传入参数
Object paramBean = container.get(refStr);
//获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象
Method setter = cls.getMethod(setterName, paramBean.getClass());
//调用invoke()方法,此处的obj是刚才反射代码得到的Object对象
setter.invoke(obj, paramBean);
只要在代码或配置文件中看到类的完整路径(包.类),其底层原理基本上使用的就是Java的反射机制。