一、概念
反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期知道运行的对象是谁,他允许运行中的Java程序获取类的信息,并且可以操作类或对象内部属性。
程序中对象的类型一般都是在编译期就确定下来的,而当我们的程序在运行时,可能需要动态的加载一些类,这些类因为之前用不到,所以没有加载到jvm,这时,使用Java反射机制可以在运行期动态的创建对象并调用其属性,它是在运行时根据需要才加载。
二、反射的作用
即,创建对象。
由上述概念可知传统创建对象的问题是:
- 传统方式创建对象: new 类名();(此时类名已知,但我们往往无法提前预知要执行的对象)
- 若要修改使用的类,必须要修改源码
解决方法:
- 当然是使用反射,动态创建对象啦(可以通过敲以下代码来感受反射的魅力)
三、反射的优缺点
优点:与传统的new静态创建对象相比,反射可以动态的创建对象。
缺点:反射的代码效率低,影响程序性能。
四、反射获取对象的三种方式
(一)根据全限定路径获取(常用)
//反射创建类对象,通过cla创建Person对象(其中forName中的参数是"包名.类名")
Class cla=Class.forName("com.jdbc.pojo.Person");
//newInstance()就是返回对象,其返回对象的类型为Object
Object obj=cla.newInstance();
//总结反射相比于传统创建对象的好处:当改变forName中的参数时,Object对象就随即改变(动态创建java对象)
(二)根据对象获取
//调用底层使用反射封装的方法
Class cla=Person.class;
(三)根据类名获取
//调用底层使用反射封装的方法
Class cla=new Person().getClass();
(四)注意
一个类只有一个类对象
五、操作属性、方法及构造器
在码操作属性部分的代码前先给出类Student及其父类Person:
package com.jdbc.pojo;
public class Student extends Person {
//声明实体类属性
public String sname;
protected int sage;
String sfav;
private String ssex="男";
public static int money=1000;
public Student() {
super();
}
public String sHi() {
return "Hi reflect";
}
public String sHi(int num,String str) {
System.out.println(str+num);
return str+num;
}
public static String sHi(String str) {
System.out.println(str);
return str;
}
protected void sHello() {
System.out.println("Student.sHello(protected)");
}
private void sHello1() {
System.out.println("Student.sHello1(private)");
}
void sHello2() {
System.out.println("Student.sHello2(default)");
}
}
package com.jdbc.pojo;
public class Person {
public String pname="张三";
protected int page;
String pfav;
private String psex;
public String pHi() {
return "Hi reflect";
}
public String pHi(int num,String str) {
return str+num;
}
protected void pHello() {
System.out.println("Person.pHello(protected)");
}
private void pHello1() {
System.out.println("Person.pHello1(private)");
}
void pHello2() {
System.out.println("Person.pHello2(default)");
}
}
接下来的部分是操作属性的代码:
package com.jdbc.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
//反射操作类属性
operField();
//反射操作类方法
operMethod();
//反射调用构造器
operConstructor();
}
//反射操作类属性
public static void operField() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
//1.获取类对象
Class cla=Class.forName("com.jdbc.pojo.Student");
//2.获取反射类属性
Field[] fds=cla.getFields();//获取该类以及父类的公共字段(public)
for (Field f:fds) {
System.out.println("获取属性名:"+f.getName());
}
Field[] fds2=cla.getDeclaredFields();//获取该类声明的所有字段
Field fds3=cla.getField("sname");//指定获取该类及父类的public字段
Field fds4=cla.getDeclaredField("sage");//指定获取该类的所有字段
Field fds5=cla.getSuperclass().getDeclaredField("pname");//指定获取父类的所有字段,其中getSuperclass()是获取父类
//3.操作类属性
//获取静态属性值
Field fs=cla.getDeclaredField("money");
fs.set(null,2000);
System.out.println(fs.get(null));//get()中的值为属性值,如果是静态变量放入null就好
//获取非静态属性值
Field fd=cla.getDeclaredField("sname");
Object obj=cla.newInstance();
fd.set(obj,"李四");
System.out.println(fd.get(obj));//newInstance()返回该对象的实例化对象,相当于new Student();
/*
* 注意此处,不能直接写成:
* fd.set(cla.newInstance(),"李四");
* System.out.println(fs.get(cla.newInstance()));
* 因为,这两行中的newInstance()是两个不同的对象
*
* */
/*
* 与传统new Student()相比的不同是:
* new Student()是先声明对象再获取
* cla.newInstance()是先获取,再说是哪个对象的东西
*
* */
//获取private属性
Field fd2=cla.getDeclaredField("ssex");
fd2.setAccessible(true);//操作private属性,不安全
Object obj2=cla.newInstance();//获取实例化对象
System.out.println(fd2.get(obj2));
}
//反射操作类方法
public static void operMethod() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
//1.获取类对象
Class cla=Class.forName("com.jdbc.pojo.Student");
//2.获取类方法对象
Method[] ms=cla.getMethods();//获取该类以及父类的公共方法(public)
Method[] ms2=cla.getDeclaredMethods();//获取该类声明的所有方法
Method m=cla.getMethod("sHi",int.class,String.class);//指定获取该类及父类的public方法,由于方法重载,可在getMethod()中指明参数类型
Method m2=cla.getDeclaredMethod("sHello",null);//指定获取该类的所有方法,由于该方法只有一个,所以可在getMethod()中添加null
//3.执行方法
//静态方法
Method m3=cla.getDeclaredMethod("sHi",String.class);
m3.invoke(null,"今天学习了反射,超开心");//对sHi传参
//非静态方法
Method m4=cla.getDeclaredMethod("sHi",int.class,String.class);
m4.invoke(cla.newInstance(),100,"反射功能好强大");
}
//反射操作类构造器
public static void operConstructor() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取类对象
Class cla=Class.forName("com.jdbc.pojo.Student");
//2.获取构造方法
Constructor[] cs=cla.getConstructors();//获取该类的公共构造方法(public)
Constructor[] cs1=cla.getDeclaredConstructors();//获取该类的所有构造方法
Constructor c=cla.getConstructor(null);//获取该类指定的无参构造方法,也可在getConstructor()中填写null
Constructor c2=cla.getConstructor(String.class);//获取该类指定的有参构造方法
//3.执行构造方法
Constructor c3=cla.getDeclaredConstructor(String.class);
Object obj=c3.newInstance("moon");//传参
}
}