黑马程序员——Java基础---反射总结

时间:2022-03-05 11:36:34

定义:

JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。

用于描述字节码的类就是Class类,创建对象,可以提取字节码文件中的内容,如字段、构造函数、一般函数。该类就可以获取字节码文件中的所有内容,那么反射就是依靠该类完成的。想要对一个类文件进行解剖,只要获取到该类的字节码文件对象即可。

1、可以通过Class.forName("Reflect.Demo")得到类对应的Class 对象。

Class.forName(String className)使用装载当前类的类装载器来装载指定类。因为class.forName(String className)方法内部调用了Class.forName(className,true, this.getClass().getClassLoader())方法,如你所见,第三个参数就是指定类装载器,显而易见,它指定的是装载当前类的类装载器的实例,也就是this.getClass().getClassLoader();

classLoader.loadClass(StringclassName , boolean resolve);需要手动指定类装载器的实例。所以这两种类装载方式的区别之一是一个默认使用装载当前类实例的类装载器来装载指定类,而另一个则需要手动指定一个类装载器的实例。

2、如何产生该类的对象呢

Class clazz = Class.forName(name);

//调用Person的空参构造函数

Object obj = clazz.newInstance();

 Class clazz = Class.forName(name);
//获取到了指定的构造函数对象
Constructor constructor = clazz.getConstructor(int.class,String.class);
//通过该构造器对象的newInstance方法进行对象的初始化。
Object obj = constructor.newInstance(38,"小明");

3、获取字段值

  /*
* 获取字节码文件中的字段。
*/
public static void getFieldDemo() throws Exception {

Class clazz = Class.forName("cn.itcast.bean.Person");

//getField只能获取所有可访问公共字段,private获取不到。
//Field field = claszz.getField("age");

//getDeclaredField可以获取到公共字段,也可以获取到私有字段。
Field field = clazz.getDeclaredField("age");

//对私有字段的访问取消权限检查,暴力访问。
field.setAccessible(true);

Object obj = clazz.newInstance();

//为对象的属性赋值
field.set(obj,89);

//获取某对象的某属性值
Object o = field.get(obj);

System.out.println(field);
}
}
4、获取类的方法

 Method[] methods = clazz.getMethods();//获取的都是公有的方法

methods = clazz.getDeclaredMethods();//只获取本类中所有方法,包括私有。


实际开发中一些常用,但又容易写错,遗忘的

// 使用反射技术得到T的真实类型
// 获取当前new的对象的 泛型的父类 类型
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); 
// 获取第一个类型参数的真实类型
this.clazz = (Class<T>) pt.getActualTypeArguments()[0]; 

使用反射获取Method,可以使用getMethod(String name,  Class<?>... parameterTypes)来获取,第一个参数是方法的名字,第二个是参数类表
但是这个方法没参数呢?比如:
一个简单的Person 类
  1. public class Person {
  2.         public String name="zhangsan";
  3.         public int age;
  4.         public String str1 = "ball";
  5.         public String str2 = "baskecballl";
  6.         public Person(){
  7.                 this.str1=str1;
  8.                 this.str2=str2;
  9.         }
  10.         public String getName() {
  11.                 return name;
  12.         }
  13.         public void setName(String name) {
  14.                 this.name = name;
  15.         }
  16.         public int getAge() {
  17.                 return age;
  18.         }
  19.         public void setAge(int age) {
  20.                 this.age = age;
  21.         }
  22.         @Override
  23.         public String toString() {
  24.                 return "Person [age=" + age + ", name=" + name + ", str1=" + str1
  25.                                 + ", str2=" + str2 + "]";
  26.         }
  27. }
复制代码
如果是调用set方法很简单,根据规则
  1.                 Method methodName = p.getClass().getMethod("setName",String.class);
  2.                 System.out.println(methodName.invoke(p, "张三"));
复制代码
这样就获取了,但是如果是get 方法呢,参数列表是空,怎么做的?
这样可以
  1.                 Method methodName = p.getClass().getMethod("getName",null);
  2.                 System.out.println(methodName.invoke(p,null));
复制代码
这样更好
  1.                 Method methodName = p.getClass().getMethod("getName");
  2.                 System.out.println(methodName.invoke(p));
复制代码