1.反射机制有什么用?
通过java的反射机制可以操作字节码文件。
反射机制的相关类在java.lang.reflect.*包下。
反射机制相关的类有:
1.java.lang.Class 代表字节码文件
2.java.lang.reflect.Method 代表字节码文件中的方法
3.java.lang.reflect.Constructor 代表字节码文件中的构造方法
4.java.lang.reflect.Field 代表字节码文件中的属性
2.获取一个类的字节码文件
要操作一个类的字节码文件,首先要获取到这个类的字节码。
第一种方式:Class c=Class.forName(“包名+类名”) 这个方法的执行会导致类加载
第二种方式:Class c=对象.getClass()
第三种方式:Class c=数据类型.clsss
public class GetReflect01 {
public static void main(String[] args) {
/**
* Class.forName()
* 1.静态方法
* 2.参数是个字符串
* 3.字符串是一个完整的类名
* 4.类名必须带有包名(有同名类)
*/
Class c1=null;
Class c3=null;
try {
c1=Class.forName("java.lang.String");
Class c2=Class.forName("java.lang.Thread");
c3=Class.forName("java.util.Date");
Class c4=Class.forName("java.lang.Integer");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//任何一个java对象都有一个方法:getClass()
String s="abc";
Class s1 = s.getClass();//s1表示String.class字节码文件
System.out.println(c1==s1);//比较两种方式获取的String.class字节码文件地址是否一样
Date d=new Date();
Class d1= d.getClass();
System.out.println(c3==d1);//比较的是对象的内存地址
//任何一种数据类型都有class属性 基本数据类型也有这个属性
Class s2=String.class;
System.out.println(s1==s2);
}
}
3.通过反射机制实例化对象
newInstance()会调用对象的无参构造方法,完成对象的创建。只会调无参构造,所以每次写实体类一定要把无参构造写起!!!
public class Reflect01 {
public static void main(String[] args) {
//通过反射机制,获取Calss,通过Class实例化对象
try {
Class user=Class.forName("com.zhouqun.reflect.User");
//newInstance()会调用对象的无参构造方法,完成对象的创建
Object o = user.newInstance();
System.out.println(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
与直接new对象比起来,理用反射创建对象更加灵活,可以通过读取配置文件来创建对象。不用修改java的源代码,实例化不同的对象,符合开闭原则。
public class Reflect02 {
public static void main(String[] args) {
//通过修改配置文件,实例化不同的对象
try {
//通过IO流读取文件
FileReader reader = new FileReader("classname.properties");
//创建属性类对象Map =左边是key =右边是value
Properties pro=new Properties();
//加载
pro.load(reader);
//关闭流
reader.close();
//通过key获取value
String className = pro.getProperty("className");
//实例化对象
Class user = Class.forName(className);
Object o = user.newInstance();
System.out.println(o);
} 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();
}
}
}
获取文件的绝对路径:各个操作系统通用(文件放在src下)
// 通过IO流读取文件
String path=Thread.currentThread().getContextClassLoader().getResource("classname.properties").getPath();
FileReader reader = new FileReader(path);
// 创建属性类对象Map =左边是key =右边是value
Properties pro=new Properties();
//加载
pro.load(reader);
//关闭流
reader.close();
还可以写成:
InputStream in=Thread.currentThread().getContextClassLoader().getResourceAsStream("classname.properties");
Properties pro=new Properties();
//加载
pro.load(in);
//关闭流
in.close();
4.资源绑定器
java.util包下提供了一个资源绑定器,便于获取属性文件(properties)中的内容,属性文件必须放在类路径下(src)
public class Boundle {
public static void main(String[] args) {
ResourceBundle bundle=ResourceBundle.getBundle("classname");
String className = bundle.getString("className");
System.out.println(className);
}
}
5.通过反射获取Field
public class Student {
public String name;
private int id;
protected String sex;
int age;
}
1.类.getFields() 获取类中修饰符为public的属性;
//获取整个类
Class student=Class.forName("com.zhouqun.bean.Student");
//获取类中的所有属性字段
Field[] fields = student.getFields();//这种方法只能获取修饰符为public的属性字段
//取出这个field
Field field=fields[0];
//获取这个属性的名字
System.out.println(field.getName());
2.类.getDeclaredFields() 获取类中所有属性
//获取整个类
Class student=Class.forName("com.zhouqun.bean.Student");
Field[] declaredFields = student.getDeclaredFields();
for (Field f:declaredFields){
System.out.println(f.getName());
}
3.类.getName 获取完整类名(包名+类名)
类.getSimpleName 获取简单类名(类名)
4.属性.getType() 获取属性的数据类型
Field[] declaredFields = student.getDeclaredFields();
for (Field f:declaredFields){
//获取字段的数据类型
Class<?> type = f.getType();
System.out.println(type);
System.out.println("获取数据类型的名字"+type.getName());
System.out.println("获取属性名"+f.getName());
}
5.属性.getModifiers 获取属性的修饰符
改方法返回的是代表修饰符编号的数字
Field[] declaredFields = student.getDeclaredFields();
for (Field f:declaredFields){
//获取字段的修饰符编号
int i= f.getModifiers();
//将编号转换成字符串
String modifierStr=Modifier.toString(i);
System.out.println(modifierStr);
}
6.通过反射机制获取、修改属性的值【get\set】
public class Reflect03 {
public static void main(String[] args) throws Exception{
//使用反射机制,去访问对象的属性
Class<?> student = Class.forName("com.zhouqun.bean.Student");
//实例化一个student对象 调用的是无参构造
Object o = student.newInstance();
//根据属性名获取name属性 只能获取修饰符为public的属性
Field name = student.getDeclaredField("name");
//通过set给student对象(obj)的name属性赋值
name.set(o,"张三");
//通过get获取student对象的name属性的值
Object o1 = name.get(o);
System.out.println(o1);
}
}
7.打破封装 setAccessible(true)
第六小节只能获取和修改public的属性,要是想修改private的属性,就需要打破封装。这是反射机制的缺点
public class Reflect03 {
public static void main(String[] args) throws Exception{
//使用反射机制,去访问对象的属性
Class<?> student = Class.forName("com.zhouqun.bean.Student");
//实例化一个student对象 调用的是无参构造
Object o = student.newInstance();
//根据属性名获取name属性 只能获取修饰符为public的属性
Field id = student.getDeclaredField("id");
//打破封装
id.setAccessible(true);
//通过set给student对象(obj)的name属性赋值
id.set(o,111);
//通过get获取student对象的name属性的值
Object o1 = id.get(o);
System.out.println(o1);
}
}
8.反射Method
public class StudentService {
public void login(String name,int age){
}
public boolean loginout(String name,int age){
return true;
}
}
public class Reflect04 {
public static void main(String[] args) throws Exception {
//获取studentService对象
Class<?> student = Class.forName("com.zhouqun.bean.StudentService");
//获取所有的Method 包括私有的
Method[] declaredMethods = student.getDeclaredMethods();
//遍历method
for (Method method:declaredMethods){
//获取修饰符列表
System.out.println(Modifier.toString(method.getModifiers()));
//获取方法的返回值
System.out.println(method.getReturnType().getSimpleName());
//获取方法名
System.out.println(method.getName());
//获取方法的参数列表(可能会有多个参数)
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class para:parameterTypes){
System.out.println(para.getSimpleName());
}
}
}
}
9.通过反射机制调用对象的方法【及其重要:invoke】
public class Reflect04 {
public static void main(String[] args) throws Exception {
//获取studentService对象
Class<?> student = Class.forName("com.zhouqun.bean.StudentService");
//new一个studentService
Object o = student.newInstance();
//获取method 分别传入方法名和参数
Method login = student.getDeclaredMethod("login", String.class, int.class);
//调用method【及其重要】
//调用o对象(studentService)的login方法,传入参数:"张三", 12 stu是返回值
Object stu = login.invoke(o, "张三", 12);
System.out.println(stu);
}
}