1.反射是什么,有什么作用?
反射---在程序运行的过程中,我们可以得到某个类的对象,可以调用某个类中的任何一个变量/方法,
这种动态获取信息的过程就是反射。
当我们在没有见过某个类的情况下,仅凭一个完整的类名,就可以获取到整个类的所有信息。
反射的使用场景:
1.jdbc加载数据库驱动
2.Servlet的web.xml配置
3.Spring框架
2.实例对象与反射对象的相互转换?
实例对象-----就是我们通过类创建的对象
反射对象-----通过反射机制得到的类对象
例如: 反射就是一面镜子,镜子前面的你就是实例对象,通过镜子得到的镜子里面的你就是反射对象。
反射对象是一个Class类型的对象
Class---不是创建类的关键字,表示一个类,所以反射对象是一个Class类型的对象
public final class Class<T>
1.通过实例对象得到反射对象
package com.wangxing.test1;
public class TestMain {
public static void main(String[] args) {
// 得到反射对象
// 1.通过实例对象得到反射对象[实例对象的getClass()方法]
Student stu = new Student();
Class stuClass = stu.getClass();
// 2.通过Class类的forName(包名.类名)——括号内的参数是包名+类名书写格式是包名.类名
try {
Class stuClass2 = Class.forName("com.wangxing.test1.Student");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.通过反射对象得到实例对象
package com.wangxing.test1;
public class TestMain {
public static void main(String[] args) {
// 通过反射对象得到实例化对象【反射对象的newInstance()方法】
// 用这个方法得到的实例化对象是Object类型的,要进行类型转换
try {
Class stuclass2 = Class.forName("com.wangxing.test1.Student");
Student stu2 = (Student) stuclass2.newInstance();
stu2.test1();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.通过反射对象得到构造方法\成员变量\成员方法
Constructor<?>[] | getConstructors() 得到构造方法 | |
Field[] | getDeclaredFields() 得到成员变量 | |
Method[] | getDeclaredMethods() 得到成员方法 | |
Class<?>[] | getInterfaces() 得到接口。 | |
Class<? super T> | getSuperclass() 得到父类。 | |
Package | getPackage() 得到包对象。 | |
int | getModifiers() Java语言修饰符 Modifier的toString(int mod) | |
String | getName() 得到类名称 |
4.反射的应用
package com.wangxing.test1;
public class Student extends Person implements MyTestInterface {
private String stuname;
private int stuage;
public Student(){}
public Student(String name,int age){
this.stuname=name;
this.stuage=age;
}
public void test1(){
System.out.println("Student类的无参实例方法");
}
public String testString (String args){
return "hello";
}
}
根据类名还原上面的类
package com.wangxing.test1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
//通过反射得到与Studnet类一样的java类
public class TestMain2 {
// 因为获得类名时,会连包名一起获得,所以自己创建一个截取类名的方法
public static String testName(String classname) {
return classname.substring(classname.lastIndexOf(".") + 1);
}
public static void main(String[] args) throws Exception {
// 得到反射对象
Class stuclass1 = Class.forName("com.wangxing.test1.Student");
// 得到包的定义
// 得到Student类的包名
// 通过getPackage()方法得到包对象,再通过getName()方法获得包名
String pagename = stuclass1.getPackage().getName();
String packageinfo = "package" + pagename + ";";
System.out.println(packageinfo);
// 得到Student类的定义
// 类的修饰符
// 通过getModifiers()方法得到修饰符对应的数字。再通过Modifier.toString(int a)方法转换为字符串
String classxiushifu = Modifier.toString(stuclass1.getModifiers());
// 类名
String leiming = testName(stuclass1.getName());
// 得到父类的类名
// 先通过getSuperclass()方法得到父类反射对象,再通过getName()得到父类类名
String supername = testName(stuclass1.getSuperclass().getName());
// 得到接口的名称
// 通过getInterfaces()方法得到所有被实现的接口的反射对象。放在数组中
Class interfacerr[] = stuclass1.getInterfaces();
// 创建StringBuilder对象处理字符串,因为多个接口时要考虑追加的问题
StringBuilder interinfo = new StringBuilder();
for (Class inter : interfacerr) {
String intername = testName(inter.getName());
// 多个接口时,都是跟随在后面,用逗号隔开的。故用来处理字符串的类要可追加的
interinfo.append(intername + ",");
}
// 最后一个接口后面多一个逗号,所以要删除
interinfo.deleteCharAt(interinfo.length() - 1);
String classinfo = classxiushifu + " class " + leiming + " extends " + supername + " implements "
+ interinfo.toString() + " {";
System.out.println(classinfo);
// 得到类中的成员变量
// 得到所有成员变量,并保存在数组中
Field fieldarr[] = stuclass1.getDeclaredFields();
// 循环遍历成员变量
for (Field field : fieldarr) {
// 得到变量的修饰符
String fieldxiushifu = Modifier.toString(field.getModifiers());
// 得到变量类型名称
// 先通过getType()方法获得类型对象,再通过getName()获得名称
String fieldleixing = testName(field.getType().getName());
// 得到变量名称
String fieldname = field.getName();
String fieldinfo = fieldxiushifu + " " + fieldleixing + " " + fieldname + ";";
System.out.println("\t" + fieldinfo);
}
// 得到类中的构造方法
// 得到所有构造方法,并保存在数组中
Constructor constructorarr[] = stuclass1.getConstructors();
// 循环遍历构造方法
for (Constructor con : constructorarr) {
// 得到构造方法的修饰符
String conxiu = Modifier.toString(con.getModifiers());
// 得到构造方法的名称
String conname = testName(con.getName());
// 构造方法中的参数可能有多个,并用逗号隔开。所以创建
// StringBuilder对象来处理字符串,使其可以追加
StringBuilder canshu = new StringBuilder();
// 得到所有的参数类型,并保存入数组
Class contype[] = con.getParameterTypes();
// 这里必须判断保存所有参数的数组大小,若=0,就会出现下面异常
// java.lang.StringIndexOutOfBoundsException: String index out of
// range: -1
if (contype.length != 0) {
for (Class typeclass : contype) {
// 得到参数的类型名称
String typename = testName(typeclass.getName());
// 将所有参数拼接起来
canshu.append(typename + " name,");
}
// 最后一个参数后面会多一个逗号,所以要删掉
canshu.deleteCharAt(canshu.lastIndexOf(","));
}
String coninfo = conxiu + " " + conname + "(" + canshu.toString() + "){}";
System.out.println("\t" + coninfo);
}
// 得到实例方法
// 得到所有实例方法,并保存在数组中
Method methodarr[] = stuclass1.getDeclaredMethods();
// 循环遍历
for (Method meth : methodarr) {
// 得到实例方法的修饰符
String methxiu = Modifier.toString(meth.getModifiers());
// 得到返回类型的名称
String methreturn = testName(meth.getReturnType().getName());
// 得到方法名称
String methname = meth.getName();
// 实例方法中的参数可能有多个,并用逗号隔开。所以创建
// StringBuilder对象来处理字符串,使其可以追加
StringBuilder canshu = new StringBuilder();
// 得到所有的参数类型,并保存入数组
Class methodcanshutype[] = meth.getParameterTypes();
// 这里必须判断保存所有参数的数组大小,若=0,就会出现下面异常
// java.lang.StringIndexOutOfBoundsException: String index out of
// range: -1
if (methodcanshutype.length != 0) {
for (Class typeclass : methodcanshutype) {
String typename = testName(typeclass.getName());
canshu.append(typename + "args,");
}
canshu.deleteCharAt(canshu.lastIndexOf(","));
}
String methodinfo = methxiu + " " + methreturn + " " + methname + "(" + canshu.toString() + "){}";
System.out.println("\t" + methodinfo);
}
System.out.println("}");
}
}