什么是反射
**Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。**而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。)语言的一个关键性质。
反射能做什么?
我们知道反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!
反射的核心API:
在Class对象中可以获取:Constructor、Field、Method
反射的作用:我们知道反射是通过Class对象动态的获取某一个类的构造方法、成员变量、普通方法的方式。按照我们目前的能力,是无法通过私有的构造创建对象,无法给一个对象的私有的变量赋值、无法调用私有的方法。但是,通过反射就可以实现这种需求。
获取Class的三种方式,推荐第三种:
测试对象:
public class User {
private String userName ;
private String password;
private String age;
//public修饰的无参构造
public User(){};
//public修饰的三个参数构造
public User(String userName,String password,String age){
this.userName=userName;
this.password=password;
this.age=age;
}
//private修饰的两个参数构造
private User(String userName,String password){
this.userName=userName;
this.password=password;
}
public String getName(User user){
return user.getUserName();
}
private String showMethod(){
return "私有方法被调用";
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
Constructor介绍
获取一个构造方法:
获取多个的构造方法:
总结:当获取一个构造方法时,调用不带s的方法;当获取私有的构造方法时,调用带Declared的方法。
通过Constructor对象创建类的实例:
当通过Constructor对象类创建一个类的实例时,如果构造方法是非pubic修饰的,那么就需要调用Constructor父类 AccessibleObject的setAccessible(true)方法打破访问权限!!!
@Test
public void getConstructor() throws NoSuchMethodException, SecurityException, InstantiationException,
IllegalAccessException, IllegalArgumentException, Exception {
// 获取User类的Class对象
Class<User> userClass = (Class<User>) Class.forName("com.Lambda.test.User");
// 通过无参构造方法,获取User类的Constructor(构造方法)对象
Constructor<User> ConsUser1 = userClass.getConstructor();
// 通过Constructor创建User实例对象
User user1 = ConsUser1.newInstance();
System.out.println("无参构造获取对象内存地址:" + user1 + "====用户名:" + user1.getUserName());
System.out.println("----------------------------------------");
// 通过有参构造方法,获取User类的Constructor(构造方法)对象
Constructor<User> ConsUser2 = userClass.getConstructor(String.class, String.class, String.class);
User user2 = ConsUser2.newInstance("张三", "123", "18");
System.out.println("有参构造获取对象内存地址:" + user2 + "====用户名:" + user2.getUserName());
System.out.println("----------------------------------------");
// 获取非public修饰的构造方法对象,通过Constructor父类 AccessibleObject的setAccessible(true)方法打破访问权限
Constructor<User> ConsUser3 = userClass.getDeclaredConstructor(String.class, String.class);
// 是否越界访问(无视私有化)
ConsUser3.setAccessible(true);
User user3 = ConsUser3.newInstance("李四", "123");
System.out.println("私有带参构造获取对象内存地址:" + user3 + "====用户名:" + user3.getUserName());
System.out.println("----------------------------------------");
// 获取
Constructor<?>[] constructors = userClass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println("获取User类所有的公开构造方法:" + constructor);
}
System.out.println("----------------------------------------");
Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructors) {
System.out.println("获取User类所有的构造方法(包含非public修饰的):" + constructor);
}
}
运行结果:
Field介绍
获取一个Field对象的方法:
获取多个Field对象的方法:
给Field设置值以及获取Field的值:找Field的api
@Test
public void getFiled() throws ClassNotFoundException, NoSuchFieldException, SecurityException,
InstantiationException, IllegalAccessException {
// 获取User类的class对象
Class<?> userClass = Class.forName("com.Lambda.test.User");
// 获取私有化修饰的成员变量对象
Field field = userClass.getDeclaredField("userName");
// 是否越界访问(无视私有化)
field.setAccessible(true);
// 通过class对象实例化user对象
User user = (User) userClass.newInstance();
// 参数赋值:参数1:实例化对象,参数2:值
field.set(user, "王五");
System.out.println("获取user成员变量:" + user.getUserName());
System.out.println("----------------------------------------");
//获取field属性值(userName)
Object uname = field.get(user);
System.out.println("获取userName的值"+uname);
}
运行结果:
注:
获取对象的class类型,通过getDeclaredField(“id”)获取的是变量的对象,返回的Field就相当于是这个变量
field.set(user,“王五”):可以理解为设置user对象中field(“userName”)的值为"王五"
同理field.get(user):可以理解为获取user对象中field(“userName”)的值
Method获取介绍
获取一个Method对象的方法
获取多个Method对象的方法:
@Test
public void getMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
// 获取User类的class对象
Class<?> userClass = Class.forName("com.Lambda.test.User");
// 通过class对象实例化user对象
User user = (User) userClass.newInstance();
user.setUserName("赵六");
//获取方法的method对象,参数1:方法名,参数2:方法的参数类型
Method method = userClass.getMethod("getName",userClass);
//method代表方法对象;invoke方法参数1:执行方法的对象,参数2:方法的参数
Object resule1 = method.invoke(user, user);
System.out.println("public修饰的方法返回结果:"+resule1);
System.out.println("-------------------------------------------");
//获取非public方法的method对象,参数1:方法名,参数2:方法的参数类型
Method showMethod = userClass.getDeclaredMethod("showMethod");
//越界访问,无视私有化
showMethod.setAccessible(true);
//showMethod代表方法对象;invoke方法参数1:执行方法的对象,参数2:方法的参数
Object result2 = showMethod.invoke(user);
System.out.println("非public修饰的方法返回结果:"+result2);
}