反射学习(入门)
反射
1、作用
- 在运行时分析类的能力
- 在运行是检查对象,例如,编写一个适用于所有类的toString方法
- 实现泛型数组操作代码
- 利用Method对象(像C++中的指针)
2、Class类
在程序运行期间,Java运行时系统初始为所有对象维护一个运行时类型标识。这个信息会跟踪每一个对象所属的类。JVM利用运行时类型信息选择要执行的正确方法。
2.1、获取Class对象
getClass
Object中的getClass()会返回一个Class类型的实例
import Employee.Employee;
public class javaStydy05 {
public static void main(String[] args) {
Employee employee = new Employee("wang");
Class cl = employee.getClass();
System.out.println(cl);
System.out.println(cl.getName());
}
}
运行结果:
class Employee.Employee
Employee.Employee
如果类在一个包中,name包名也会作为类名的一部分
2.2、静态方法forName()
使用静态方法forName获取类名对应的Class对象
import Employee.Employee;
public class javaStydy05 {
public static void main(String[] args) {
Employee employee = new Employee("wang");
Class cl2 = null;
//forName()
try {
cl2 = Class.forName("Employee.Employee");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(cl2);
}
}
forName中传入的必须是类的全限定名
2.3、T.class
假设T是一个Java类型 那么T.class就可以得到其匹配的类对象
import Employee.Employee;
public class javaStydy05 {
public static void main(String[] args) {
Employee employee = new Employee("wang");
//T.class
Class cl3 = Employee.class;
System.out.println(cl3);
}
}
2.4、补充
可以直接用==比较两个类对象
当获取一个类对象时,可以使用getConstructor()的到一个Constructor类型的对象,然后通过它使用newInstance()构造一个实例
import Employee.Employee;
import java.lang.reflect.Constructor;
public class javaStudy06 {
public static void main(String[] args) {
Employee employee = new Employee("wyz");
Class cl = null;
try {
cl = Class.forName("Employee.Employee");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Constructor econstructor = null;
Employee employee2 = null;
try {
econstructor = cl.getConstructor();
employee2 = (Employee) econstructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(employee2);
}
}
通过这个方法只能使用无参构造器,如果目标类中没有无参构造器,则会抛出异常
利用反射分析类的能力
利用反射可以检查类的结构
- java.lang.feflect包中有三个类Field(描述类的字段),Method(描述类的方法),Constructor(描述类的构造器)
- 三个类中都有getName()用于返回字段,方法,构造器的名字
- Field中有getType()用于返回字段类型的类对象
3、反射中常用方法
定义pojo类
package Reflect;
/**
* person
*/
abstract class Person{
public void sayHello(){}
}
/**
* chinese
*/
class Chinese extends Person{
private String name;
private String sex;
private int age;
public int score;
public Chinese(){}
public Chinese(String name){
this.name = name;
}
public Chinese(String name, String sex, int age){
this.name = name;
this.sex = sex;
this.age = age;
}
public void sayChina(){
System.out.println("name:"+ name +" sayChina");
}
@Override
public void sayHello() {
System.out.println("name:"+ name +"sayHello");
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Chinese{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
3.1、通过一个对象获得完整的包名和类名
public void test(){
/**
* 通过一个对象获得完整的包名和类名
*/
Class<?> chinese1 = null;
Class<?> chinese2 = null;
Class<?> chinese3 = null;
//方式一
try {
chinese1 = Class.forName("Reflect.Chinese");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式二
chinese2 = new Chinese().getClass(); //一般都用这种方法
//方式三
chinese3 = Chinese.class;
System.out.println(chinese1);
System.out.println(chinese2);
System.out.println(chinese3);
System.out.println(chinese3.getName());
//【运行结果】:
//class Reflect.Chinese
//class Reflect.Chinese
//class Reflect.Chinese
//Reflect.Chinese
}
3.2、获取其成员变量信息
public void test(){
/**
* 获取其成员变量信息
*/
*Class<?> chinese4 = null;
try {
chinese4 = Class.forName("Reflect.Chinese");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取所有 公开 的成员变量,包括继承变量,只获取public 成员变量
Field[] fields1 = chinese4.getFields();
for (Field f : fields1) {
System.out.println(f.getName());
}
System.out.println();
//获取本类中的所有成员变量,包括私有成员变量
Field[] fields2 = chinese4.getDeclaredFields();
for (Field f: fields2) {
System.out.println(f.getName());
}
//获取指定成员变量
try {
System.out.println(chinese4.getField("score"));
System.out.println(chinese4.getDeclaredField("age"));
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
//【运行结果】
/*
score
name
sex
age
score
public int Reflect.Chinese.score
private int Reflect.Chinese.age
*/
}
3.3、获取构造方法信息
3.3.1、通过反射创建实例
通过反射创建实例的方法为Constructor的newInsta方法(原Class下的newInstance方法已过时)
public void test(){
/**
* 获取构造方法信息
*
* 通过反射创建实例的方法为Constructor的newInstance方法(原来的Class下的newInstance方法已过时)
*/
Class<?> chinese5 = null;
try {
chinese5 = Class.forName("Reflect.Chinese");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取所有构造方法
Constructor<?>[] constructors = chinese5.getConstructors();
for (Constructor c: constructors) {
System.out.println(c);
}
//获取某个公开的构造方法
Constructor<?> constructor1 = null;
Chinese chinese = null;
try {
constructor1 = chinese5.getConstructor(String.class); //传入参数列表类型
chinese = (Chinese) constructor1.newInstance("shuaibi"); //通过反射新建实例
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(constructor1);
System.out.println(chinese);
chinese.sayChina();
//【运行结果】:
//public Reflect.Chinese()
//public Reflect.Chinese(java.lang.String,java.lang.String,int)
//public Reflect.Chinese(java.lang.String)
//public Reflect.Chinese(java.lang.String)
//Chinese{name='shuaibi', sex='null', age=0}
//name:shuaibisayChina
//getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
//getDeclaredMethod(方法名,int.class,String.class)
//此处省略代码
}
3.4、获取成员方法信息
这里省略代码,因为用法和获取构造方法信息一样
//getMethods()//获取所有可见的方法,包括继承的方法
//getMethod(方法名,参数类型列表)
//getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
//getDeclaredMethod(方法名,int.class,String.class)
3.5、反射调用成员变量
public void test(){
/**
* 反射调用成员变量
*
*/
Class<?> chinese6 = null;
try {
//获取类对象
chinese6 = Class.forName("Reflect.Chinese");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field age = null;
Field name = null;
Field sex = null;
try {
//获取指定成员变量
age = chinese6.getDeclaredField("age");
name = chinese6.getDeclaredField("name");
sex = chinese6.getDeclaredField("sex");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
//获取构造器对象,此处获取的是无参构造器
Constructor<?> constructor = null;
try {
constructor = chinese6.getConstructor();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//通过构造器对象创建实例
Chinese instance = null;
try{
instance =(Chinese)constructor.newInstance();
}catch(Exception e){
e.printStackTrace();
}
//设置成员变量可访问
age.setAccessible(true);
name.setAccessible(true);
sex.setAccessible(true);
try {
age.set(instance,18);
name.set(instance,"张三");
sex.set(instance,"男");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println(instance);
//【运行结果】Chinese{name='张三', sex='男', age=18}
}
3.6、反射调用成员方法
public void test(){
/**
* 反射调用成员方法
*/
//获取类对象
Class<?> chinese7 = null;
try{
chinese7 = Class.forName("Reflect.Chinese");
}catch(Exception e)
{
e.printStackTrace();
}
//获取成员方法对象
Method method = null;
try{
method = chinese7.getDeclaredMethod("sayChina");
}catch(Exception e){
e.printStackTrace();
}
//获取无参构造器对象
//创建实例
Constructor constructor = null;
Chinese instance2 = null;
try{
constructor = chinese7.getConstructor(String.class);
instance2 = (Chinese)constructor.newInstance("李四");
}catch (Exception e){
e.printStackTrace();
}
//使成员方法允许被调用
method.setAccessible(true);
try {
method.invoke(instance2);
}catch(Exception e){
e.printStackTrace();
}
//【运行结果】name:李四 sayChina
}