一、反射
1.JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方
法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象
方法的功能称为java语言的反射机制。
2.动态获取类中信息,就是java反射。可以理解为对类的解剖。
3.如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了反射技术。
4.用于描述字节码的类就是Class类,创建对象,可以提取字节码文件中的内容,如字段、构造函数、一般函数。该类就可以获取字节码文件中的所有内容,那么反射就是依靠该类完成的。想要对一个类文件进行解剖,只要获取到该类的字节码文件对象即可。
Class类
1.反射的基石-Class类;
java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class;
Class类代表Java类,对应各个类在内存中的字节码;
2.得到各个类字节码对应的实例对象(Class类型);
类名.class;例:System.class;;
对象.getClass();例:new Data().getClass();
Class.forName(“类名”);例:Class.forName(“java.util.Data”);
3.基本数据类型包装类中的常量TYPE对应的是该基本数据类型的字节码,即:int.class==Integer.TYPE;//true;
1.反射的基石-Class类;
java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class;
Class类代表Java类,对应各个类在内存中的字节码;
2.得到各个类字节码对应的实例对象(Class类型);
类名.class;例:System.class;;
对象.getClass();例:new Data().getClass();
Class.forName(“类名”);例:Class.forName(“java.util.Data”);
3.基本数据类型包装类中的常量TYPE对应的是该基本数据类型的字节码,即:int.class==Integer.TYPE;//true;
Class类中的常用方法
forName(String className);返回相应参数类名的类对象;
isArray();判断此class对象是否是一个数组类;
isPrimitive();判定指定的class对象是否表示一个基本类型;
getConstructor(Class< ?>… parameterTypes);返回某个类指定构造方法;
getConstructors();返回某个类的所有构造方法;
getField(String name);返回一个类中由name指定的Field对象,name-字段名;
getFields();返回一个类中的成员变量;
getDeclaredField(String name);
forName(String className);返回相应参数类名的类对象;
isArray();判断此class对象是否是一个数组类;
isPrimitive();判定指定的class对象是否表示一个基本类型;
getConstructor(Class< ?>… parameterTypes);返回某个类指定构造方法;
getConstructors();返回某个类的所有构造方法;
getField(String name);返回一个类中由name指定的Field对象,name-字段名;
getFields();返回一个类中的成员变量;
getDeclaredField(String name);
获取字节码文件对象的3种方式
Person.java
package cn.itcast.bean;
public class Person
{
<span style="white-space:pre"> </span>private int age;
<span style="white-space:pre"> </span>private String name;
<span style="white-space:pre"> </span>public Person(int age,String name){
<span style="white-space:pre"> </span>super();
<span style="white-space:pre"> </span>this.age = age;
<span style="white-space:pre"> </span>this.name = name;
<span style="white-space:pre"> </span>System.out.println("Person param run..." + this.name + ":" +this.age);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public Person(){
<span style="white-space:pre"> </span>super();
<span style="white-space:pre"> </span>System.out.println("person run");
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public void show(){
<span style="white-space:pre"> </span>System.out.println(name + "...show run..." + age);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>private void privateMethod(){
<span style="white-space:pre"> </span>System.out.println("method run");
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public void paramMethod(String str,int num){
<span style="white-space:pre"> </span>System.out.println("paramMethod run..." + str + ":" + num);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public static void staticMethod(){
<span style="white-space:pre"> </span>System.out.println("static method run...");
<span style="white-space:pre"> </span>}
}
import cn.itcast.bean.Person;
// 要想要对字节码文件进行解剖,必须要有字节码文件对象。
public class ReflectDemo
{
<span style="white-space:pre"> </span>public static void main(String[] args) throws ClassNotFoundException
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>getClassObject_1();
<span style="white-space:pre"> </span>System.out.println("--------------------");
<span style="white-space:pre"> </span>getClassObject_2();
<span style="white-space:pre"> </span>System.out.println("--------------------");
<span style="white-space:pre"> </span>getClassObject_3();
<span style="white-space:pre"> </span>}
/*
* 获取字节码对象的方式:
* 方式一: Object 类中的 getClass() 方法的。
* 想要用这种方式,必须要明确具体的类,并创建对象。
* 麻烦。
*/
<span style="white-space:pre"> </span>public static void getClassObject_1(){
<span style="white-space:pre"> </span>Person p = new Person();
<span style="white-space:pre"> </span>Class clazz = p.getClass();
<span style="white-space:pre"> </span>Person p1 = new Person();
<span style="white-space:pre"> </span>Class clazz1 = p1.getClass();
<span style="white-space:pre"> </span>System.out.println(clazz == clazz1);
<span style="white-space:pre"> </span>}
/*
* 方式二:任何数据类型都具备一个静态的属性 .class 来获取其对应的 Class 对象。
* 相对简单,但是还是要明确用到类中的静态成员。
* 还是不够扩展。
*/
<span style="white-space:pre"> </span>public static void getClassObject_2(){
<span style="white-space:pre"> </span>Class clazz = Person.class;
<span style="white-space:pre"> </span>Class clazz1 = Person.class;
<span style="white-space:pre"> </span>System.out.println(clazz == clazz1);
<span style="white-space:pre"> </span>}
/*
* 方式三:只要通过给定的类的字符串名称就可以获取该类,更为扩展。
* 可以用 Class 类中的方法完成。
* 该方法就是 forName 。
* 这种方法只要有名称即可,更为方便,扩展性更强。
*/
<span style="white-space:pre"> </span>public static void getClassObject_3() throws ClassNotFoundException {
<span style="white-space:pre"> </span>// 可以把类的字符串名称写到配置文件中,然后读取出来。
<span style="white-space:pre"> </span>String className = "cn.itcast.bean.Person";
<span style="white-space:pre"> </span>Class clazz = Class.forName(className);
<span style="white-space:pre"> </span>System.out.println(clazz);
<span style="white-space:pre"> </span>}
}
获取Class中的构造函数
示例:
import cn.itcast.bean.Person;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo
{
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {
<span style="white-space:pre"> </span>createNewObject_1();
<span style="white-space:pre"> </span>System.out.println("--------------------");
<span style="white-space:pre"> </span>createNewObject_2();
}
public static void createNewObject_1() throwsClassNotFoundException,InstantiationException,IllegalAccessException {
<span style="white-space:pre"> </span>// 早期: new 时候,先根据被 new 的类的名称找寻该类的字节码文件,并加载进内存,
<span style="white-space:pre"> </span>// 并创建该字节码文件对象,并接着创建该字节文件的对应的 Person 对象。
<span style="white-space:pre"> </span>//Person p = new Person();
<span style="white-space:pre"> </span>// 现在:
<span style="white-space:pre"> </span>String name = "cn.itcast.bean.Person";
<span style="white-space:pre"> </span>// 找寻该文件类文件,并加载进内存,并产生 Class 对象。
<span style="white-space:pre"> </span>Class clazz = Class.forName(name);
<span style="white-space:pre"> </span>// 如何产生该类的对象呢?
<span style="white-space:pre"> </span>Object obj = clazz.newInstance();// 调用 Person 的空参构造函数
<span style="white-space:pre"> </span>}
public static void createNewObject_2() throwsClassNotFoundException,InstantiationException,NoSuchMethodException,IllegalAc
cessException,InvocationTargetException {
<span style="white-space:pre"> </span>//Person p = new Person(" 小强 ",39);
/*
* 当获取指定名称对应类中的所体现的对象时。
* 而该对象初始化不使用空参数构造函数该怎么办呢?
* 既然是通过指定的构造函数进行对象的初始化。
* 所以应该先获取到该构造函数,通过字节码文件对象即可完成。
* 该方法是: getConstructor(parameterTypes);
*/
<span style="white-space:pre"> </span>String name = "cn.itcast.bean.Person";
<span style="white-space:pre"> </span>// 找寻该名称类文件,并加载进内存,并产生 Class 对象。
<span style="white-space:pre"> </span>Class clazz = Class.forName(name);
<span style="white-space:pre"> </span>// 获取到了指定的构造函数对象
<span style="white-space:pre"> </span>Constructor constructor =clazz.getConstructor(int.class,String.class);
<span style="white-space:pre"> </span>// 通过该构造器对象的 newInstance 方法进行对象的初始化。
<span style="white-space:pre"> </span>Object obj = constructor.newInstance(38," 小明 ");
<span style="white-space:pre"> </span>}
}
获取Class的字段
示例:
import cn.itcast.bean.Person;
import java.lang.reflect.Field;
public class ReflectDemo
{
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {
<span style="white-space:pre"> </span>getFieldDemo();
}
/*
* 获取字节码文件中的字段。
*/
public static void getFieldDemo() throws Exception {
<span style="white-space:pre"> </span>Class clazz = Class.forName("cn.itcast.bean.Person");
<span style="white-space:pre"> </span>//getField 只能获取所有可访问公共字段, private 获取不到。
<span style="white-space:pre"> </span>//Field field = claszz.getField("age");
<span style="white-space:pre"> </span>//getDeclaredField 可以获取到公共字段,也可以获取到私有字段。
<span style="white-space:pre"> </span>Field field = clazz.getDeclaredField("age");
<span style="white-space:pre"> </span>// 对私有字段的访问取消权限检查,暴力访问。
<span style="white-space:pre"> </span>field.setAccessible(true);
<span style="white-space:pre"> </span>Object obj = clazz.newInstance();
<span style="white-space:pre"> </span>// 为对象的属性赋值
<span style="white-space:pre"> </span>field.set(obj,89);
<span style="white-space:pre"> </span>// 获取某对象的某属性值
<span style="white-space:pre"> </span>Object o = field.get(obj);
<span style="white-space:pre"> </span>System.out.println(field);
<span style="white-space:pre"> </span>}
}
获取Class中的方法
示例:
import cn.itcast.bean.Person;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
public class ReflectDemo
{
<span style="white-space:pre"> </span>public static void main(String[] args) throws Exception {
<span style="white-space:pre"> </span>getMethodDemo_1();
<span style="white-space:pre"> </span>System.out.println("---------------------------");
<span style="white-space:pre"> </span>getMethodDemo_2();
<span style="white-space:pre"> </span>System.out.println("---------------------------");
<span style="white-space:pre"> </span>getMethodDemo_3();
<span style="white-space:pre"> </span>}
/*
* 获取指定 Class 中的公共函数。
*/
<span style="white-space:pre"> </span>public static void getMethodDemo_1() throws Exception {
<span style="white-space:pre"> </span>Class clazz = Class.forName("cn.itcast.bean.Person");
<span style="white-space:pre"> </span>Method[] methods = clazz.getMethods();// 获取的都是公有的方法
<span style="white-space:pre"> </span>methods = clazz.getDeclaredMethods();// 只获取本类中所有方法,包括私有。
<span style="white-space:pre"> </span>for(Method method : methods){
<span style="white-space:pre"> </span>System.out.println(method);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public static void getMethodDemo_2() throws Exception {
<span style="white-space:pre"> </span>Class clazz = Class.forName("cn.itcast.bean.Person");
<span style="white-space:pre"> </span>Method method = clazz.getMethod("show",null);// 获取空参数一般方法
<span style="white-space:pre"> </span>Object obj = clazz.newInstance();
<span style="white-space:pre"> </span>Constructor constructor =clazz.getConstructor(int.class,String.class);
<span style="white-space:pre"> </span>obj = constructor.newInstance(37," 小明 ");
<span style="white-space:pre"> </span>method.invoke(obj,null);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>public static void getMethodDemo_3() throws Exception {
<span style="white-space:pre"> </span>Class clazz = Class.forName("cn.itcast.bean.Person");
<span style="white-space:pre"> </span>Method method =clazz.getMethod("paramMethod",String.class,int.class);// 获取空参数一般方法
<span style="white-space:pre"> </span>Object obj = clazz.newInstance();
<span style="white-space:pre"> </span>Constructor constructor = clazz.getConstructor();
<span style="white-space:pre"> </span>obj = constructor.newInstance();
<span style="white-space:pre"> </span>method.invoke(obj," 小强 ",89);
<span style="white-space:pre"> </span>}
}