反射的概述:java的反射机制是在程序的运行过程中,对于任何一个类,能够知道它的有哪些属性和方法;对于任何一个对象,都能对它的方法和属性进行调用;将这种动态获取对象信息以及调用对象方法的功能称为j反射机制。
java反射机制类java.lang.Class; //类
java.lang.reflect.Constructor;//构造方法
java.lang.reflect.Field; //类的成员变量(字段)
java.lang.reflect.Method;//类的方法
java.lang.reflect.Modifier;//访问权限
一.反射的三种方式(获取类的字节码文件,也就是.class文件):
1.Object中的getClass()
public static void main(String[] args) {
Demo demo = new Demo();
//获取该类的全路径名称
String name = demo.getClass().getName();
}
2.类.classpublic static void main(String[] args) {
Class c = Demo.class;
//获取该类的全路径名称
c.getName();
}
3.通过拿到类的全路径名来获取该类的字节码文件(如果找不到该路径下的此类,会抛出以下异常)public static void main(String[] args) {
try {
Class> c = Class.forName("interview_questions.Demo");
c.getName();
}catch (ClassNotFoundException cnfe){
cnfe.printStackTrace();
}
}
以上是获取一个类的字节码文件的三种方式,但是选择哪种好呢?第一种:我们获取字节码文件是为了调用该类的方法和属性,既然已经拿到了它的实例,就不需要字节码文件了;
第二种:通过这种方式去拿到它的字节码文件,就必须先要将该类的包导入,这种依赖性很强;
第三种:直接拿到该类的全路径名,通过全路径名的方式加载得到它的字节码文件。(常用)
二.通过反射获取类的构造方法、属性和类中方法//user类
public class user {
public String name;
public Integer age;
private String address;
public user(){
super();
}
public user(String name, Integer age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
private user(String name, String address) {
this.name = name;
this.address = address;
}
public void test01(String name,Integer age){
System.out.println("user类中的test01方法(public)_"+name+"_"+age);
}
private void test02(){
System.out.println("user类中的test02方法(private)");
}
protected void test03(){
System.out.println("user类中的test03方法(protected)");
}
void test04(){
System.out.println("user类中的test04方法");
}
}
1.获取类的构造方法public static void main(String[] args) throws Exception{
Class> user = Class.forName("interview_questions.user");
//public constructor
Constructor>[] constructors = user.getConstructors();
//All constructor
Constructor>[] cons = user.getDeclaredConstructors();
//public constructor no param
Constructor> constructor = user.getDeclaredConstructor(null);
//public constructor and param
Constructor> constructor1 = user.getConstructor(new Class[]{String.class,Integer.class, String.class});
//private constructor and param
Constructor> constructor2 = user.getDeclaredConstructor(new Class[]{String.class, String.class});
}
}
打印输出---------------public constructor--------------------
public interview_questions.user()
public interview_questions.user(java.lang.String,java.lang.Integer,java.lang.String)
---------------All constructor---------------------
public interview_questions.user()
public interview_questions.user(java.lang.String,java.lang.Integer,java.lang.String)
private interview_questions.user(java.lang.String,java.lang.String)
--------------public constructor no param-----------
public interview_questions.user()
--------------public constructor and param----------
public interview_questions.user(java.lang.String,java.lang.Integer,java.lang.String)
--------------private constructor and param--------
private interview_questions.user(java.lang.String,java.lang.String)
2.获取类属性//获取public修饰的所有字段
Field[] fields = user.getFields();
//获取类中所有字段
Field[] declaredFields = user.getDeclaredFields();
//获取指定的public字段,并设置值
Field name = user.getField("name");
//获取实例对象
Object obj = user.getConstructor().newInstance();
name.set(obj,"xiaoming");
user u = (user)obj;
System.out.println(u.name);//xiaoming
//获取类中的私有字段,并设置值
对于私有字段,设置Field对象的Accessible的访问标志位为Ture,就可以通过反射获取私有变量的值,在访问时会忽略访问修饰符的检查Field address = user.getDeclaredField("address");
Object obj01 = user.getConstructor().newInstance();
address.setAccessible(true);
address.set(obj01,"beijing");
String s = (String) address.get(obj01);
3.获取类中的方法先在user类中添加四个方法:
public void test01(String name,Integer age){
System.out.println("user类中的test01方法(public)_"+name+"_"+age);
}
private void test02(){
System.out.println("user类中的test02方法(private)");
}
protected void test03(){
System.out.println("user类中的test03方法(protected)");
}
void test04(){
System.out.println("user类中的test04方法");
}
//获取所有public修饰的方法
Method[] methods = user.getMethods();
//获取user类中所有的方法
Method[] declaredMethods = user.getDeclaredMethods();
//获取指定方法并调用执行
Method test01 = user.getMethod("test01", String.class,Integer.class);
Object obj = user.getConstructor().newInstance();
Object invoke = test01.invoke(obj, "xiaoming",18);
System.out.println(invoke);
反射的优缺点:优点:增加程序的灵活性、外部调用方便
缺点:性能比起源代码执行效率低;内部暴露(比如一些在正常情况下不允许访问的私有属性和方法)