Java反射:打破静态限制的利器
目录
什么是反射?
什么是class类?
获取class对象的三种方法
利用反射获取构造方法
利用反射获取成员变量
利用反射获取成员方法
案例1
案例2
反射的作用
什么是反射?
反射允许对封装累的字段(成员变量),方法(成员方法)和构造函数(构造方法)的信息进行编程访问。
反射就是从类里面拿东西
反射允许对成员变量,成员方法和构造方法的信息进行编程访问。
但我们在获取的时候并不是从Java文件中获取的,而是从class字节码文件中获取的,所以我们要先创建class字节码文件对象,再从字节码文件里面获取字段,构造方法,成员方法。
什么是class类?
在Java编程语言中,Class类是一个非常特殊的类,它用于在运行时表示类或接口的信息。每当JVM加载一个类时,都会创建该类的一个Class对象,其中包含了类的名称、包名、父类、实现的接口、所有方法、字段等信息。这个Class对象是由JVM内部创建的,我们无法直接通过new来实例化一个Class对象。
Class类的主要作用是提供了一种在运行时获取类的各种信息的方法。
获取class对象的三种方法
- Class.forName("全类名");//源代码阶段
- 类名.class;//加载阶段
- 对象.getClass();//运行阶段
public class MyReflectDemo1 {public static void main(String[] args) throws ClassNotFoundException {//1.第一种方式//全类名:包名+类名//clazz表示Student类字节码文件的对象//最常用Class clazz1 = Class.forName("com.it.myreflect1.Student");System.out.println(clazz);//第二种方式//一般 更多的是当做参数进行传播Class clazz2 = Student.class;//第三种方式//当我们有了这个类的对象的 时候,才可以使用Student stu = new Student();Class clazz3 = stu.getClass();}
}
运行结果:
表示的是:com.it.myreflect1.Student类的class对象
class类对象的唯一性
可以对三个结果进行比较,答案为true。
System.out.println(clazz1 == clazz2);
System.out.println(clazz2 == clazz3);
利用反射获取构造方法
在Java里面,万物皆可为对象,字节码文件可以看做是class对象,那么构造方法的对象用Constructor类的对象表示,成员变量的对象用File类的对象表示,成员方法的对象用Method类的对象表示。
class类中用于获取构造方法的方法
Constructor[] getConstructors();返回所有公共构造方法对象的数组
Constructor[] getDeclaredConstructors();返回所有构造方法对象的数组(Declared就相当于权限的意思,有了Declare就可以访问所有的构造方法)
Constructor getConstructor(Class…parameterTypes);返回单个公共构造方法对象
Constructor getDeclaredConstructor(Class……parameterTypes);返回单个构造方法对象
Constructor类中用于创建对象的方法
T newInstance(Object... initargs);根据指定的构造方法创建对象
setAccessible(boolean flag);设置为true,表示取消访问检查
//1.获取class字节码文件对象
Class clazz = Class.forName("com.it.myreflect2.Student");//2.获取构造方法
//返回所有公共构造方法对象的数组
System.out.println("----返回所有公共构造方法对象的数组----");
Constructor[] con1 = clazz.getConstructors();
for(Constructor c : con1){System.out.println(c);
}System.out.println("----返回所有构造方法对象的数组----");
Constructor[] con2 = clazz.getDeclaredConstructors();
for(Constructor c : con2) {System.out.println(c);
}
System.out.println("----返回单个构造方法对象(无参的构造方法)----");
Constructor cons1 = clazz.getDeclaredConstructor();
System.out.println(cons1);System.out.println("----返回单个构造方法对象(有参的构造方法)-----");
Constructor cons2 = clazz.getDeclaredConstructor(String.class);
System.out.println(cons2);System.out.println("----返回单个构造方法对象(受保护的)----");
Constructor con3 = clazz.getDeclaredConstructor(int.class);
System.out.println(con3);
运行结果
----返回所有公共构造方法对象的数组----
public com.it.myreflect2.Student()
public com.it.myreflect2.Student(java.lang.String)
----返回所有构造方法对象的数组----
public com.it.myreflect2.Student()
public com.it.myreflect2.Student(java.lang.String)
protected com.it.myreflect2.Student(int)
private com.it.myreflect2.Student(java.lang.String,int)
----返回单个构造方法对象(无参的构造方法)----
public com.it.myreflect2.Student()
----返回单个构造方法对象(有参的构造方法)-----
public com.it.myreflect2.Student(java.lang.String)
----返回单个构造方法对象(受保护的)----
protected com.it.myreflect2.Student(int)
获取权限修饰符
Constructor con4 = clazz.getDeclaredConstructor(String.class, int.class);
//获取权限修饰符
int modifiers = con4.getModifiers();
System.out.println(modifiers);//公有返回1,私有返回2
获取到构造方法的所有参数
Parameter[] parameters = con4.getParameters();
for(Parameter p : parameters){System.out.println(p);
}
//java.lang.String arg0
//int arg1
创建对象
con4.setAccessible(true);//表示临时取消权限校验
Student stu = (Student) con4.newInstance("张三", 23);//Object强转Student类型
System.out.println(stu);
//Student{name='张三', age=23}
利用反射获取成员变量
Class类中用于获取成员变量的方法
Field[]getFields(): 返回所有公共成员变量对象的数组
Field[]getDeclaredFields(): 返回所有成员变量对象的数组
Field getField(String name): 返回单个公共成员变量对象
Field getDeclaredField(String name): 返回单个成员变量对象
Field类中用于创建对象的方法
void set(Object obj, Object value): 赋值
Object get(Object obj)获取值。
public class MyReflectDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {//先创建class对象Class clazz = Class.forName("com.it.myreflect6.Student");//获取成员变量Field[] name1 = clazz.getFields();for(Field f : name1) {System.out.println(f.getName());}System.out.println("----获取单个成员变量----");Field name2 = clazz.getDeclaredField("name");System.out.println(name2);System.out.println("----获取权限修饰符---");int modifiers = clazz.getModifiers();System.out.println(modifiers);System.out.println("---获取成员变量的名字---");String name = clazz.getName();System.out.println(name);System.out.println("---获取成员变量的类型---");String typeName = clazz.getTypeName();System.out.println(typeName);System.out.println("---获取成员变量记录的值---");Student s = new Student("张三",23);System.out.println(s);}
}
运行结果:
----获取单个成员变量----
private java.lang.String com.it.myreflect6.Student.name
----获取权限修饰符---
1
---获取成员变量的名字---
com.it.myreflect6.Student
---获取成员变量的类型---
com.it.myreflect6.Student
---获取成员变量记录的值---
Student{name='张三', age=23}
利用反射获取成员方法
Class类中用于获取成员方法的方法
Method[]getMethods(): 返回所有公共成员方法对象的数组,包括继承的
Method[]getDeclaredMethods(): 返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class……parameterTypes): 返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class…parameterTypes): 返回单个成员方法对象
Method类中用于创建对象的方法
Object invoke(Object obj, Object…args):
运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
//1.获取class字节码文件对象
Class clazz = Class.forName("com.it.myreflect3.Student");System.out.println("---包含继承父类的---");
Method[] methods1 = clazz.getMethods();
for (Method method : methods1) {System.out.println(method);
}System.out.println("---不包含继承父类的---");
Method[] methods2 = clazz.getDeclaredMethods();
for (Method method : methods2) {System.out.println(method);
}
运行结果
---包含继承父类的---
public java.lang.String com.it.myreflect3.Student.getName()
public java.lang.String com.it.myreflect3.Student.toString()
public void com.it.myreflect3.Student.sleep()
public void com.it.myreflect3.Student.setName(java.lang.String)
public int com.it.myreflect3.Student.getAge()
public void com.it.myreflect3.Student.setAge(int)
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
public final void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
---不包含继承父类的---
public java.lang.String com.it.myreflect3.Student.getName()
public java.lang.String com.it.myreflect3.Student.toString()
public void com.it.myreflect3.Student.sleep()
public void com.it.myreflect3.Student.setName(java.lang.String)
public int com.it.myreflect3.Student.getAge()
public void com.it.myreflect3.Student.setAge(int)
private void com.it.myreflect3.Student.eat(java.lang.String) throws java.lang.NegativeArraySizeException,java.io.IOException
成员方法的运行
//获取指定的单一方法
Method m = clazz.getDeclaredMethod("eat",String.class);
System.out.println(m);
//获取方法的修饰符
int mod = m.getModifiers();
System.out.println(mod);
//获取方法的名字
String name = m.getName();
System.out.println(name);
//获取方法的形参
Parameter[] parameters = m.getParameters();
for(Parameter p : parameters){System.out.println(p);
}
//获取方法的抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
for(Class c : exceptionTypes){System.out.println(c);
}
//方法运行
Student s = new Student();
m.setAccessible(true);
Object result = m.invoke(s,"汉堡包");
System.out.println(result);
运行结果
---获取指定的单一方法---
private void com.it.myreflect3.Student.eat(java.lang.String) throws java.lang.NegativeArraySizeException,java.io.IOException
---获取方法的修饰符---
2
---获取方法的名字---
eat
---获取方法的形参---
java.lang.String arg0
---获取方法的抛出的异常---
class java.lang.NegativeArraySizeException
class java.io.IOException
---方法运行---
在吃汉堡包
null
案例1
对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
public class MyReflectDemo {public static void main(String[] args) throws IllegalAccessException, IOException {/*对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去*///创建学生和老师的对象Student s = new Student("张三",23);Teacher t = new Teacher("波妞",34);getSaveObject(t);}private static void getSaveObject(Object obj) throws IllegalAccessException, IOException {//获取字节码对象Class clazz = obj.getClass();//创建IO流BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\java\\basic-code\\myreflect\\a.txt"));//获取所有的成员变量Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);//获取成员变量的名字String name = field.getName();//获取成员变量的值Object value = field.get(obj);bw.write(name+"="+value);bw.newLine();}bw.close();}
}
运行结果:a.txt文件有内容输入
name=波妞
age=34
案例2
配置文件中的信息为:
classname=com.it.myreflect5.Student
method=study
public class MyReflectDemo {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1.读取配置文件中的信息Properties prop = new Properties();FileInputStream fis = new FileInputStream("D:\\java\\basic-code\\myreflect\\prop.properties");prop.load(fis);fis.close();System.out.println(prop.getProperty("name"));//2.获取全类名和方法名String className = (String) prop.get("classname");String methodName = (String) prop.get("method");System.out.println(className);System.out.println(methodName);//3.利用反射创建对象并运行方法Class clazz = Class.forName(className);//获取构造方法Constructor con = clazz.getDeclaredConstructor();Object o = con.newInstance();System.out.println(o);//获取成员方法并运行Method m = clazz.getDeclaredMethod(methodName);m.setAccessible(true);m.invoke(o);}
}
运行结果:
null
com.it.myreflect5.Student
study
Student{name='null', age=0}
学生在学习
反射的作用
- 获取任意一个类中的所有信息
- 结合配置文件动态创建对象