一、反射机制
- 反射机制的作用:通过Java语言中的反射机制可以操作字节码文件(代码片段、Class文件)。
—— 可以读和修改字节码文件 - 反射机制的相关类在
java.lang.reflect.*
包下。
二、反射机制相关的重要的类
java.lang.Class
:代表整个字节码,代表一个类型。代表整个类。java.lang.reflect.Method
:代表字节码中的方法字节码。代表类中的方法。java.lang.reflect.Constructor
:代表字节码中的构造方法字节码。代表类中的构造方法。java.lang.reflect.Field
:代表字节码中的属性字节码。代表类中的成员变量(静态变量和实例变量)
三、java.lang.Class
- 要操作一个类的字节码,首先要获取这个类的字节码文件,获取java.lang.Class实例有三种方式:
Class c = Class.forName("完整类名带包名");
如果只希望一个类的静态代码块执行,其他代码一律不执行
可以使用:Class.forName(“完整类名”);
这个方法的执行会导致类加载
,类加载
时,静态代码块执行。Class c = 对象.getClass();
Class c = 任何类型.class;
public class ReflectTest01 { public static void main(String[] args) { /* Class.forName() 1、静态方法 2、方法的参数是一个字符串。字符串需要的是一个完整类名。 3、完整类名必须带有包名。java.lang包也不能省略。 */ Class c1 = null; Class c2 = null; try { c1 = Class.forName("java.lang.String");//c1代表String.class文件(c1代表St>ring类型) c2 = Class.forName("java.util.Date");//c2代表Date类型 Class c3 = Class.forName("java.lang.Integer");//c3代表Integer类型 Class c4 = Class.forName("java.lang.System");//c4代表System类型 } catch (ClassNotFoundException e) { e.printStackTrace(); } // java中任何一个对象都有一个方法:getClass() String s = "abc"; Class x = s.getClass();//x代表的是String.class字节码文件(x代表的是String类型) System.out.println(x == c1);//true Date date = new Date(); Class y = date.getClass();//y代表Date.class字节码文件(y代表Date类型) System.out.println(y == c2);//true // 第三种方式,java语言中任何一种类型,包括基本数据类型,它都有.class属性。 Class a = String.class;//a代表String类型 Class b = Date.class;//b代表Date类型 System.out.println(a == c1);//true System.out.println(b == c2);//true } }
- 使用反射机制来实例化对象
- 获取到Class实例,可以Class的 newInstance() 方法来实例化的对象(反射机制实例化对象)
注:newInstance()方法内部实际上调用了无参构造方法,必须保证无参构造存在才可以。
- 使用反射机制实例化对象更具有灵活性
java代码不需要改动(不改变源代码),可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象。
public class ReflectTest03 { public static void main(String[] args) { // 这种方式代码就写死了。只能创建一个User类型的对象 //User user = new User(); //以下代码是灵活的,代码不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象。 //获取文件路径,较通用方法 String path = Thread.currentThread().getContextClassLoader() .getResource("com/javaSE/reflect/classinfo.properties").getPath(); //定义一个文件字符输入流 FileReader fileReader = null; try { //通过IO流读取属性配置文件 fileReader = new FileReader(path); //创建一个属性类对象Map集合 Properties properties = new Properties(); //把属性配置文件加载进Properties集合 properties.load(fileReader); //获得类名 String className = properties.getProperty("className");//com.javaSE.reflect.User //通过反射机制的方式来实例化对象 Class c = Class.forName(className);//c代表的是className对应的类 Object o = c.newInstance();//newInstance() 这个方法会调用User这个类的无参构造方法,完成对象的创建,必须保证无参构造是存在的! System.out.println(o);//com.javaSE.reflect.User@7a0ac6e3 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } finally { if (fileReader != null) { try { fileReader.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
- 获取到Class实例,可以Class的 newInstance() 方法来实例化的对象(反射机制实例化对象)
四、java.lang.reflect.Field
- 当获得类的字节码文件(Class文件),可以通过其获得Field属性
- 通过反射机制访问一个java对象的属性
public class Student { // Field翻译为字段,其实就是属性/成员 // 4个Field,分别采用了不同的访问控制权限修饰符 private String name; // Field对象 protected int age; // Field对象 boolean sex; public int no; }
public class ReflectTest05 { public static void main(String[] args) { try { //首先获取类的字节码文件(Class文件) Class studentClass = Class.forName("com.javaSE.reflect.Student"); //创建对象o Object o = studentClass.newInstance(); //获得类中的所有属性 Field[] declaredFields = studentClass.getDeclaredFields(); for (Field field : declaredFields) { //获得所有所有属性的名字 System.out.println(field.getName()); } //获得类中的no属性 Field noField = studentClass.getDeclaredField("no"); //设置o对象中的no属性 noField.set(o, 1111); //读取o对象中no属性的值 System.out.println(noField.get(o));//1111 /* 如果要获取并设置private修饰的属性 不能直接获取,直接获取会出现异常 需要先setAccessible()打破封装 */ Field nameField = studentClass.getDeclaredField("name"); nameField.setAccessible(true);//打破封装 //给name属性赋值 nameField.set(o, "张三"); //获得name属性的值 System.out.println(nameField.get(o));//张三 } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } }
五、java.lang.reflect.Method
- 当获得类的字节码文件(Class文件),可以通过其获得Method属性。
- 通过反射机制调用一个java对象的方法
/** * 用户业务类 */ public class UserService { /** * 登录方法 * @param name 用户名 * @param password 密码 * @return true表示登录成功,false表示登录失败! */ public boolean login(String name,String password){ if("admin".equals(name) && "123".equals(password)){ return true; } return false; } // 可能还有一个同名login方法 // java中怎么区分一个方法,依靠方法名和参数列表。 public void login(int i){ } /** * 退出系统的方法 */ public void logout(){ System.out.println("系统已经安全退出!"); } }
public class ReflectTest06 { public static void main(String[] args) { try { //获取UserService类的Class文件 Class userServiceClass = Class.forName("com.javaSE.reflect.UserService"); //通过反射机制创建一个UserService对象 Object o = userServiceClass.newInstance(); //通过反射机制获取类中的login方法 Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class); //通过反射机制调用login方法 Object returnValue = loginMethod.invoke(o, "admin", "123"); System.out.println(returnValue);//true } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
六、java.lang.reflect.Constructor
- 当获得类的字节码文件(Class文件),可以通过其获得Constructor属性。
- 通过反射机制调用一个java对象的构造方法
public class Vip { int no; String name; String birth; boolean sex; public Vip() { } public Vip(int no) { this.no = no; } public Vip(int no, String name) { this.no = no; this.name = name; } public Vip(int no, String name, String birth) { this.no = no; this.name = name; this.birth = birth; } public Vip(int no, String name, String birth, boolean sex) { this.no = no; this.name = name; this.birth = birth; this.sex = sex; } @Override public String toString() { return "Vip{" + "no=" + no + ", name='" + name + '\'' + ", birth='" + birth + '\'' + ", sex=" + sex + '}'; } }
public class ReflectTest07 { public static void main(String[] args) { try { //获得Vip类的Class文件 Class vipClass = Class.forName("com.javaSE.reflect.Vip"); //调用无参构造方法,可以直接使用newInstance()方法 Object o = vipClass.newInstance(); System.out.println(o);//Vip{no=0, name='null', birth='null', sex=false} //或者使用如下通用方法 //获取类中的无参构造方法 Constructor c1 = vipClass.getDeclaredConstructor(); //调用无参的构造方法 Object o1 = c1.newInstance(); System.out.println(o1);//Vip{no=0, name='null', birth='null', sex=false} //获得类中形参为四个的构造方法 Constructor c2 = vipClass.getDeclaredConstructor(int.class, String.class, String.class, boolean.class); //调用形参为四个的构造方法 Object o2 = c2.newInstance(110, "zhangsan", "1997-05-16", true); System.out.println(o2);//Vip{no=110, name='zhangsan', birth='1997-05-16', sex=true} } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
七、通过反射机制获得这个类的父类和接口
public class ReflectTest08 {
public static void main(String[] args) {
try {
//获取String的class文件
Class stringClass = Class.forName("java.lang.String");
//获得String的父类
Class superclass = stringClass.getSuperclass();
System.out.println(superclass.getName());//java.lang.Object
//获得String类的所有接口
Class[] interfaces = stringClass.getInterfaces();
for (Class in : interfaces) {
System.out.println(in.getName());
/*
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
*/
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}