动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。比如众所周知的ECMAScript(JavaScript)便是一个动态语言。除此之外如Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。(引自: 百度百科)
var execString = "alert(Math.floor(Math.random()*10));";
eval(execString);
Class c = Class.forName("com.wmx.test.User");
反射API用来生成在当前JAVA虚拟机中的类、接口或者对象的信息。
在面向对象的世界里,万物皆对象。类是对象,类是java.lang.Class类的实例对象。另外class类只有java虚拟机才能new出来。任何一个类都是Class 类的实例对象。
String str = new String();
Class extends String> class2 = str.getClass();
Class extends String> class1 = String.class;
Class> forName = Class.forName("java.lang.String");
调用Class对象的newInstance()方法(类必须有一个无参数的构造器;类的构造器的访问权限需要足够。)
有参的构造方法构建对象时
package com.blog;
public class Person {
private String name;
private Integer age;
public Person(){
}
public Person(String name,Integer age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
通过Class生成Person的对象
import java.lang.reflect.Constructor;
public class Test {
public static void main(String[] args) throws Exception {
Class> clazz = Class.forName("com.blog.Person");
Person person1 = (Person)clazz.newInstance();
Constructor> constroctor = Class.forName("com.blog.Person").getDeclaredConstructor(String.class,Integer.class);
Person person2 = (Person)constroctor.newInstance("wmx",20);
System.out.println(person1);
System.out.println(person2);
}
}
执行结果
Person [name=null, age=null]
Person [name=wmx, age=20]
Class类提供了大量的实例方法来获取该Class对象所对应的详细信息,Class类大致包含如下方法,其中每个方法都包含多个重载版本,因此我们只是做简单的介绍,详细请参考JDK文档
获取内容 | 方法签名 |
---|---|
构造器 | Constructor getConstructor(Class>… parameterTypes) |
包含的方法 | Method getMethod(String name, Class>… parameterTypes) |
包含的属性 | Field getField(String name) |
包含的Annotation | < A extends Annotation > A getAnnotation(Class< A> annotationClass) |
所实现的接口 | Class>[] getInterfaces() |
修饰符 | int getModifiers() |
所在包 | Package getPackage() |
全路径类名 | String getName() |
类名 | String getSimpleName() |
通过反射,调用类中的方法,通过Method类完成。步骤:
public class Test {
public static void main(String[] args) throws Exception {
Class> clazz = Class.forName("com.blog.Person");
Person person1 = (Person)clazz.newInstance();
Constructor> constroctor = Class.forName("com.blog.Person").getDeclaredConstructor(String.class,Integer.class);
Person person2 = (Person)constroctor.newInstance("wmx",20);
//利用反射调用方法
Method method = clazz.getMethod("setName", String.class);
method.invoke(person1, "wmx1");
System.out.println(person1);
System.out.println(person2);
}
}
执行结果:
Person [name=wmx1, age=null]
Person [name=wmx, age=20]
说明:方法Object invoke(Object obj, Object … args)
1. Object 对应原方法的返回值,若原方法无返回值,此时返回null
2. 若原方法若为静态方法,此时形参Object obj可为null
3. 若原方法形参列表为空,则Object[] args为null
4. 若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。
public Field getField(String name) 返回此Class对象表示的类或接口的指定的public的Field。
public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。
在Field中:
public Object get(Object obj) 取得指定对象obj上此Field的属性内容
public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
public class Test {
public static void main(String[] args) throws Exception {
Class> clazz = Class.forName("com.blog.Person");
Person person1 = (Person)clazz.newInstance();
//利用反射调用方法
Method method = clazz.getMethod("setName", String.class);
method.invoke(person1, "wmx1");
//利用反射获取属性,并赋值
Field ageField = clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(person1, 10);
System.out.println(person1);
}
}
执行结果:
Person [name=wmx1, age=10]
说明:在类中属性都设置为private的前提下,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问。否则会报下面异常
Exception in thread “main” java.lang.IllegalAccessException: Class com.blog.Test can not access a member of class com.blog.Person with modifiers “private”
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(Unknown Source)
at java.lang.reflect.AccessibleObject.checkAccess(Unknown Source)
at java.lang.reflect.Field.set(Unknown Source)
at com.blog.Test.main(Test.java:18)
下面我们使用反射模拟一下Spring的自动注入
项目的目录结构如下图:
@Data
public class User {
private String username;
private String password;
}
dao层:
public interface UserDao {
public void save(User user);
}
dao实现层
public class UserDaoImpl implements UserDao{
public void save(User user) {
System.out.println(user.getUsername()+"保存成功");
}
}
service层:
public interface UserService {
public void save(User user);
}
service实现层
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void save(User user) {
userDao.save(user);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
bean.xml
根据bean.xml自动给userService注入userDao的实例
BeanFactory:
public interface BeanFactory {
public Object getBean(String id);
}
ClassPathXMLApplicationContext:
public class ClassPathXMLApplicationContext implements BeanFactory{
private Map beans = new HashMap();
public ClassPathXMLApplicationContext() throws Exception{
SAXReader reader = new SAXReader();
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("bean.xml");
Document doc = reader.read(resourceAsStream);
Element root=doc.getRootElement();
System.out.println(root.getName());
Iterator iterator = root.elementIterator();
while(iterator.hasNext()) {
Element element = iterator.next();//获取子元素
String id= element.attributeValue("id");
String clazz= element.attributeValue("class");
//使用反射生成实例对象
Object o = Class.forName(clazz).newInstance();
//将bean放入组件
beans.put(id, o);
List elements = element.elements();
for(int i=0;i interfaces = beanObject.getClass().getInterfaces()[0];
Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
//使用反射调用setter方法,注入元素
m.invoke(o, beanObject);
}
}
}
public Object getBean(String id) {
return beans.get(id);
}
}
测试:
public class UserServiceImplTest {
@Test
public void test() throws Exception{
ClassPathXMLApplicationContext factory = new ClassPathXMLApplicationContext();
UserService bean = (UserService)factory.getBean("userService");
User user = new User();
user.setUsername("admin");
bean.save(user);
}
}
执行结果:
admin保存成功
注入成功