反射(Reflect)
1· 什么是是反射
1.1 反射的介绍
不是正常编程中出现的机制
框架底层源码会经常使用
可以解决代码通用性问题
学习要求:
1.什么是反射,为什么要有反射,它能解决的问题
2.反射中有常用的类,类中的方法的使用
3.使用反射封装一些通用性比较强的代码
反射机制:
通过java语言占用的反射机制,可以操作字节码文件
有点类似于黑客的技术(读写字节码文件)
通过反射机制可以操作代码片段(class文件)
1.2 相关包
反射机制位于java.lang.reflect.*包下
反射机制相关的类有哪些?
java.lang.Class:
代表整个字节码文件,代表一个类型,代表整个类
java.lang.reflect.Method:
代表字节码中的方法字节码,代表类中的方法
java.lang.reflect.Constructor:
代表字节码中的构造方法字节码,代表类中的构造方法
java.lang.reflect.Field:
代表字节码中的属性字节码,代表类中的成员变量(静态变量+实例变量)
以一个bean类为例介绍:
public class User {
// Field
int no;
// Constructor
public User() {
}
public User (int no) {
this.no = no;
}
// Method
public void setNo(int no) {
this.no = no;
public int getNo () {
return no ;
}
}
2. Class
2.1 获取实例
要操作一个类的字节码,需要首先获取到这个类的字节码
怎么获取java.lang.Class实例?
三种方式
1.Class c = Class.forName(“完整类名包名”);
2.Class c = 对象.getClass()
3.Class c = 任何类型.class;
/*
Class.forName()
1.静态方法
2.方法的参数是一个字符串
3.字符串需要的是一个完整类名
4.完整类名必须带有包名,java.lang包也不能省略
*/
//方式1
Class c1 = null;
Class c2 = null;
try {
c1 = Class.forName("java.lang.String");//c1代表String.class文件,或者说c1代表String类
c2 = Class.forName("java.util.Date");//以此类推
Class c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方式2
//java中任何一个对象都有一个方法:getClass()
String s = "abc";
Class x = s.getClass();
System.out.println(c1 == x);//true
//字节码文件装载到jvm中的时候只装载一份,c1和x都装载这个文件
Date date = new Date();
Class y = date.getClass();
System.out.println(c2 == y);
//方式3:java语言中任何一种类型,包括基本数据类型,他都有.class属性
Class z = String.class;
Class m = int.class;
Class n = Date.class;
System.out.println(z == x);
2.2 使用实例化对象
通过反射机制,获取Class,通过Class实例化对象
获取到Class能干什么
通过Class的newInstance()方法来实例化对象
注意:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造才可以
try {
//通过反射机制,获取Class,通过Class实例化对象
Class c = Class.forName("Reflect.Bean.User");//c代表user类型
//newInstance()这个方法会调用User这个类的无参数构造方法,完成对象的创建
//重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的
Object o = c.newInstance();
System.out.println(o);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
3. Field
3.1 反射Student类当中所有的Field
public static void main(String[] args) throws Exception {
//获取整个类
Class s = Class.forName("java.lang.String");
String sd = s.getName();
System.out.println("完整类名"+sd);
String simpleName = s.getSimpleName();
System.out.println("简类名"+simpleName);
//获取类中所有的public修饰的Field
Field[] fields = s.getFields();
System.out.println(fields.length);//测试数组中只有一个元素
//取出这个Field
Field f = fields[0];
//取出这个Field它的名字
String name = f.getName();
System.out.println(name);
//获取所有的Field
Field[] fs = s.getDeclaredFields();
for(Field field :fs){
//获取属性的修饰符列表
int modifiers = field.getModifiers();
String ms = Modifier.toString(modifiers);//将数字转化为类型字符串
System.out.println(modifiers+":"+ms);
//获取属性类型
Class type = field.getType();
String n = type.getSimpleName();
System.out.print(n+":");
//获取属性名字
System.out.println(field.getName());
}
}
3.2 通过反射机制,反编译一个类的属性Field
public static void main(String[] args) throws Exception {
//拼接字符串
StringBuilder s = new StringBuilder();
Class studentClass = Class.forName("java.lang.Integer");
s.append(Modifier.toString(studentClass.getModifiers())+" class "+studentClass.getSimpleName()+"{\n");
Field[] fields = studentClass.getDeclaredFields();
for (Field field:fields){
s.append("\t");
s.append(Modifier.toString(field.getModifiers()));
s.append(" ");
s.append(field.getType().getSimpleName());
s.append(" ");
s.append(field.getName());
s.append(";\n");
}
s.append("}");
System.out.println(s);
}
3.3 通过反射机制访问对象属性(必须掌握)
public static void main(String[] args) throws Exception {
//使用反射机制,怎么去访问一个对象的属性(set get)
Class studentClass = Class.forName("Reflect.Bean.Student");
Object obj = studentClass.newInstance();//obj就是Student对象(底层调用无参构造方法)
//获取a属性的值(根据属性名称获取Field)
Field a = studentClass.getDeclaredField("a");
//给obj对象(Student对象)的a赋值
a.set(obj,111);
/*
赋值三要素:对象,属性,值
反射机制让代码复杂了,但是更灵活了
*/
//读取a属性的值
//两个要素:获取obj对象no的值
System.out.println(a.get(obj));
//可以访问私有的属性吗?
studentClass.getDeclaredField("a");
//打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会)
//这样设置完之后,在外部也是可以访问private
a.setAccessible(true);
//给a属性赋值
a.set(obj,1321);
//获取a属性的值
System.out.println(a.get(obj));
}
4. Method
4.1 反射Method(了解内容)
public static void main(String[] args) throws Exception{
//获取类
Class userClass = Class.forName("Reflect.Bean.UserService");
//获取所有的Method(包括私有的)
Method[] method = userClass.getDeclaredMethods();
System.out.println(method.length);
for (Method m : method){
//获取修饰符列表
System.out.print(Modifier.toString(m.getModifiers())+" ");
//获取方法的返回值类型
System.out.print(m.getReturnType().getSimpleName()+ " ");
//获取方法名
System.out.print(m.getName());
//方法的修饰符列表
Class[] parameterTypes = m.getParameterTypes();
System.out.print("(");
for(Class p : parameterTypes){
System.out.print(p.getSimpleName()+" ");
}
System.out.println(")");
}
}
4.2 反编译一个类的方法(了解内容)
public static void main(String[] args) throws Exception{
StringBuilder s = new StringBuilder();
Class userClass = Class.forName("Reflect.Bean.UserService");
s.append(Modifier.toString(userClass.getModifiers())+" class "+userClass.getSimpleName()+"{\n");
Method[] methods = userClass.getDeclaredMethods();
for (Method method:methods){
s.append("\t");
s.append(Modifier.toString(method.getModifiers()));
s.append(" ");
s.append(method.getReturnType().getSimpleName());
s.append(" ");
s.append(method.getName());
s.append("(");
Class[] parameterTypes = method.getParameterTypes();
for (Class p : parameterTypes){
s.append(p.getSimpleName());
s.append(",");
}
//删除指定下标位置上的字符
if(parameterTypes.length > 0){
s.deleteCharAt(s.length() - 1);
}
s.append(")");
s.append("{}\n");
}
s.append("}");
System.out.println(s);
}
4.3 通过反射机制如何去调用一个对象的方法(必须掌握)
public static void main(String[] args) throws Exception{
//通过反射机制如何调用一个对象的方法
Class userClass = Class.forName("Reflect.Bean.UserService");
//创建对象
Object obj = userClass.newInstance();
//获取Method
Method method = userClass.getDeclaredMethod("login", String.class, String.class);
//调用方法
/*
调用方法有几个要素?
对象,方法名,实参列表,返回值
*/
//反射机制中最重要的一个方法,必须记住
Object retValue = method.invoke(obj, "admin", "123");
System.out.println(retValue);
}
5. 小结
反射机制,让代码很具有通用性,可变化的内容都是写到配置文件当中,将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,但是java代码不需要做任何改动。这就是反射的魅力所在之处。
以上均为上课时当堂笔记和当堂所写代码,记录下来以助理解记忆
本文介绍了Java反射机制,包括反射的概念、应用场景、如何获取Class实例、如何通过反射实例化对象、访问Field和Method。反射提供了操作字节码的能力,增强了代码的通用性和灵活性,允许在运行时动态创建对象并调用方法。
1272

被折叠的 条评论
为什么被折叠?



