13. 反射
Java 是一门面向对象的语言,万事万物皆对象,哪么某个类也应该是某个类的对象,那是哪个类的对象代表某个类呢?答案是:Class 类,这个就是反射的核心,即如果我们拿到某个类的 Class 对象,就得到了相应的类,这样,我们就可以访问这个类中的任何内容了。
JDK 中跟反射相关的所有的 API 类都集中在 java.lang.reflect
包中,该包提供类和接口,以获得关于类和对象的反射信息。
13.1 得到某个类的Class类的对象
/**
* 1、Java中某个具体的类,就是Class类的一个对象而已。
* 所以,我们要得到某个具体的类,只需要得到这个类的Class对象即可。
* <p>
* 问题:如何得到某个类的Class类的对象?
* 有如下三种方法可以得到:
* 1、类名.class
* 2、对象.getClass()
* 3、Class.forName("要加载的类名") [最常用]
*/
@Test
public void test01() throws ClassNotFoundException {
Class<Student> c1 = Student.class;
System.out.println("c1 = " + c1);
Student student = new Student();
Class<? extends Student> c2 = student.getClass();
System.out.println("c2 = " + c2);
Class<?> c3 = Class.forName("com.hzit.vo.Student");
System.out.println("c3 = " + c3);
}
13.2 获取构造方法
/**
* 2、通过Class对象获取到类之后,如何获取构造方法?
*/
@Test
public void test02() throws ClassNotFoundException {
// 得到学生类的Class对象(相当于得到学生类Student)
Class<?> c = Class.forName("com.hzit.vo.Student");
/**
* 第一种:查看所有的公有的构造方法
*/
// 得到这个类的所有的公有的构造方法
Constructor<?>[] constructors = c.getConstructors();
findConstructors(constructors);
/**
* 第二种:查看所有的构造方法
*/
Constructor<?>[] declaredConstructors = c.getDeclaredConstructors();
findConstructors(declaredConstructors);
}
private void findConstructors(Constructor<?>[] constructors) {
System.out.println("Student类的构造方法如下:");
System.out.println("------------------------------------------");
for (Constructor<?> constructor : constructors) {
// 获取这个构造方法的参数类型
Class<?>[] parameterTypes = constructor.getParameterTypes();
StringBuilder builder;
// 判断这个构造方法是否有参
if (parameterTypes.length > 0) {
// 获取构造方法是访问修饰符的权限
int modifiers = constructor.getModifiers();
String modifire = "";
switch (modifiers) {
case 1:
modifire = "public";
break;
case 2:
modifire = "private";
break;
case 3:
modifire = "";
break;
case 4:
modifire = "protected";
break;
default:
modifire = "非法的修饰符";
break;
}
builder = new StringBuilder(modifire + " Student(");
for (Class<?> parameterType : parameterTypes) {
// 获取参数的类型名字
String typeName = parameterType.getTypeName();
// 输出构造方法
builder.append(typeName);
builder.append(",");
}
// 去除最后一个逗号
builder.deleteCharAt(builder.length() - 1);
builder.append(")");
} else {
// 无参
builder = new StringBuilder("public Student()");
}
System.out.println(builder.toString());
}
}
13.3 得到某个具体的构造方法(得到公有的和私有的)
/**
* 3、得到某个具体的构造方法(得到公有的和私有的)
*/
@Test
public void test03() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 得到学生类的Class对象(相当于得到学生类Student)
Class<?> c = Class.forName("com.hzit.vo.Student");
/**
* 得到公有的构造方法并构造学生对象
*/
// 得到公有的构造方法
Constructor<?> constructor = c.getConstructor(int.class, String.class);
// 构造一个学生对象
Object o1 = constructor.newInstance(1001, "张三");
System.out.println("o1 = " + o1);
/**
* 得到任意修饰符修饰的构造方法并构造学生对象
*/
// 得到任意的构造方法
Constructor<?> constructor1 = c.getDeclaredConstructor(int.class, String.class, String.class);
// 设置除公有public之外的访问修饰符能够访问的权限
constructor1.setAccessible(true);
Object o2 = constructor1.newInstance(1002, "李四", "男");
System.out.println("o2 = " + o2);
}
13.4 普通方法的访问–访问得到所有的方法
/**
* 4、普通方法的访问----访问得到所有的方法
*/
@Test
public void test04() throws ClassNotFoundException {
// 得到学生类的Class对象(相当于得到学生类Student)
Class<?> c = Class.forName("com.hzit.vo.Student");
/**
* 得到所有的公有的方法、继承过来的方法
*/
System.out.println("Student类的所有的公有的成员方法和继承过来的方法如下:");
System.out.println("---------------------------------");
Method[] methods = c.getMethods();
// 遍历方法
for (Method method : methods) {
String name = method.getName();
System.out.println(name);
}
System.out.println("-----------------------------------------");
/**
* 得到所有的方法(不能得到继承过来的方法)
*/
System.out.println("Student类的所有的成员方法如下:");
System.out.println("---------------------------------");
Method[] declaredMethods = c.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
String name = declaredMethod.getName();
System.out.println(name);
}
}
13.5 普通方法的访问–访问得到某个具体的方法并调用
/**
* 5、普通方法的访问----访问得到某个具体的方法并调用
*/
@Test
public void test05() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// 得到学生类的Class对象(相当于得到学生类Student)
Class<?> c = Class.forName("com.hzit.vo.Student");
/**
* 调用共有的方法
*/
// 得到公有的方法并执行
Method welcome = c.getMethod("welcome");
// 得到一个学生类的对象
Object o = c.newInstance();
// 调用方法
welcome.invoke(o);
/**
* 调用私有的方法
*/
// 得到私有的方法
Method sayHello = c.getDeclaredMethod("sayHello");
// 得到一个学生对象(上面已经创建了)
// 设置除公有public之外的访问修饰符能够访问的权限
sayHello.setAccessible(true);
// 调用方法
sayHello.invoke(o);
System.out.println("------------------------");
Method sayHi = c.getDeclaredMethod("sayHi");
// 为sname属性设置值
Method setSname = c.getMethod("setSname", String.class);
setSname.invoke(o,"张三");
// 设置除公有public之外的访问修饰符能够访问的权限
sayHi.setAccessible(true);
// 调用方法
sayHi.invoke(o);
}
13.6 反射过程中利用字段读写值
/**
* 6、反射过程中利用字段读写值
*/
@Test
public void test06() throws ClassNotFoundException {
// 得到学生类的Class对象(相当于得到学生类Student)
Class<?> c = Class.forName("com.hzit.vo.Student");
/**
* 获取所有的公有的字段
*/
Field[] fields = c.getFields();
findFields(fields);
System.out.println("-------------------------");
/**
* 获取所有的声明字段
*/
Field[] declaredFields = c.getDeclaredFields();
findFields(declaredFields);
}
private void findFields(Field[] fields) {
for (Field field : fields) {
String name = field.getName();
System.out.println(name);
}
}
13.7 为字段赋值
/**
* 7、为字段赋值
*/
@Test
public void test07() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
// 得到学生类的Class对象(相当于得到学生类Student)
Class<?> c = Class.forName("com.hzit.vo.Student");
// 得到一个学生类的对象
Object o = c.newInstance();
// 获取某个非公有的字段
Field sname = c.getDeclaredField("sname");
// 设置此字段可访问,凡是非公有的字段必须要设置此选项
sname.setAccessible(true);
// 设置字段的值
sname.set(o,"王二麻子");
System.out.println("o = " + o);
}