1.什么是反射机制
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
2.反射机制
3.Class类的介绍
概念:Class 类的实例表示正在运行的 Java 应用程序中的类和接口
我们理解: Class类,用它获取的对象,就是正在执行的.class字节码对象.
4.Class 创建的三种方式
方式1:
Class clazz = 类.class属性; MyTick.class (就代表的是Class 类型的对象)
方式2:
1)创建对象
2)Class clazz = 对象.getClass();
方式3:
Class clazz = Class.forName("类的完全路径名");
测试代码:
public class ClazzTest {
@Test
public void testfun() throws ClassNotFoundException {
//1.方式1:获取字节码对象 格式:Class clazz = 类.class属性;
Class clazz01 = Person.class;
System.out.println(clazz01);
//2.方式2:获取字节码对象 格式: 1)创建对象 2)Class clazz = 对象.getClass();
Person p = new Person();
Class clazz2 = p.getClass();
System.out.println(clazz2);
//3.方式3:获取字节码对象 格式:Class clazz = Class.forName("类的完全路径名");
Class clazz3 = Class.forName("com.it.clazz.Person");
System.out.println(clazz3);
}
}
Class对象的特点:
该对象在内存中只创建一次. 通过几种方式获取的对象都是同一个对象. 它们的地址值一样.
5.Class类的常用方法
第一组方法:
static Class forName(String className) 静态方法,作用是获取Class对象
ClassLoader(类加载器) getClassLoader() 返回该类的类加载器。
T newInstance() 创建此 Class 对象所表示的类的一个新实例。
String getSimpleName(); 获得简单类名,只是类名,没有包
String getName(); 获取完整类名,包含包名+类名
第二组方法:
Constructor<T> getConstructor(Class<?>... parameterTypes) 获取构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
获取构造方法对象(可以获取私有的构造方法)
第三组方法:
Method getMethod(String name, Class<?>... parameterTypes) 获取方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
可以获取私有的方法对象
第四组方法:
Field getField(String name) 获取属性对象
Field getDeclaredField(String name) 可以获取私有的属性
构造方法的练习:
* 需求1:
* 使用Class 获取构造方法对象.Student
* 调用构造方法对象的newIntances方法,创建对象.
@Test
public void test01() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取student的字节码对象
Class clazz = Student.class;
//2.获取构造方法对象
//Constructor<T> getConstructor(Class<?>... parameterTypes) 获取构造方法对象
Constructor constructor = clazz.getConstructor();
//3.构造方法调用newIntances方法创建对象
// T newInstance(Object... initargs)
Student stu = (Student) constructor.newInstance();
stu.fun();
}
* 需求2:
* 使用Class获取有参数的构造方法对象 Student
* 调用有参数的构造方法对象,创建对象;
@Test
public void test02() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取student的字节码对象
Class clazz = Student.class;
//2.获取有参构造方法对象
// //Constructor<T> getConstructor(Class<?>... parameterTypes) 获取构造方法对象
Constructor constructor = clazz.getConstructor(int.class, String.class);
//3.调用newIntance创建对象
Student stu = (Student) constructor.newInstance(2, "老王");
System.out.println(stu);
}
* 需求3:
* 使用Class 获取私有的构造方法 Student
* 并且创建对象
* 暴力反射获取私有构造
@Test
public void test03() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取student的字节码对象
Class clazz = Student.class;
//2.获取构造方法对象
Constructor cons = clazz.getDeclaredConstructor();
//3.去除私有权限
cons.setAccessible(true);
//4.调用newIntance方法创建对象
Student student = (Student) cons.newInstance();
student.fun();
}
Method类:
描述:Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
Method可以表述类中的方法. 可以将方法变成对象.我们可以调用它的方法,让方法被调用.
1.如何获取Method对象
我们可以通过Class类的方法来获取Method对象.
第三组方法:
Method getMethod(String name, Class<?>... parameterTypes) 获取方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
可以获取私有的方法对象
2.Method类中的常用方法
使用method对象调用原来的方法.
Object invoke(Object obj, Object... args)
3.Method 类的代码操作
public class MethodAPI {
//1.我们使用Method 类中的方法,调用一个无参的public的方法.
@Test
public void test01() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1)获取Student类的字节码对象
Class clazz = Student.class;
//2)调用:Method getMethod(String name, Class<?>... parameterTypes) 获取方法对象 , 来获取方法对象
Method methodObj = clazz.getMethod("fun1");
//3)调用:Object invoke(Object obj, Object... args) 调用该方法,让fun1方法执行
methodObj.invoke(clazz.newInstance());
}
@Test
public void test02() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class clazz = Class.forName("com.it.classapi.Student");
Method method = clazz.getDeclaredMethod("fun2");
method.setAccessible(true);
method.invoke(clazz.newInstance());
}
// 3.我们调用一个有参数,有返回值的public方法 (调用方法,获取返回值,打印返回值)
@Test
public void test03() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//快速补全:
Class clazz = Student.class;
// public String fun3(String name,int age){
Method method = clazz.getMethod("fun3", String.class, int.class); //反射阶段
String str = (String) method.invoke(clazz.newInstance(), "柳岩", 18);
System.out.println(str);
}
//4.调用一个有参数,有返回值的private方法
@Test
public void test04() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//1.创建Student字节码对象
Class clazz = Student.class;
//2.getDeclaredMethod(String name, Class<?>... parameterTypes) 参数1:方法名称 参数2: 参数的字节码对象
Method method = clazz.getDeclaredMethod("fun4", String.class, int.class);
//3.去除私有权限
method.setAccessible(true);
//4.调用
String str = (String) method.invoke(clazz.newInstance(), "迪丽热巴", 18);
System.out.println(str);
}
}
3.属性类Field
概念:
Field 提供有关类或接口的单个字段的信息.
Field 是我们类中的成员的变量的描述.
如何创建: Class对象的方法创建
Field getField(String name) 获取属性对象public
Field getDeclaredField(String name) 可以获取私有的属性
常用方法:
Object get(Object obj) 可以获取对象的属性对象 , 参数(当前类对象,举例来说就是student对象)
void set(Object obj, Object value) 给属性对象设置值; 参数对象(Student对象) 参数2:具体参数值
练习:
public class FieldAPI {
@Test
public void test0() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
// 1)获取Student的字节码对象
Class clazz = Student.class;
// 2) clazz对象调用 getField(String name) 获取属性对象public , 参数字段名称 useranme ===> fieldUserNameObj
// clazz对象调用 getField(String name) 获取属性对象public , 参数字段名称 age ====> fieldAgeObj
Field fieldUserNameObj = clazz.getField("username");
Field fieldAgeObj = clazz.getField("age");
//3)给对象fieldUserNameObj 调用 void set(Object obj, Object value) 给username属性设置
// 给对象fieldUserNameObj 调用 void set(Object obj, Object value) 给age属性设置
Student stu = (Student) clazz.newInstance();
fieldUserNameObj.set(stu,"柳岩"); // stu.setUserName("liuyan");
fieldAgeObj.set(stu,18); // stu.setAge(18);
//4)获取属性值
//调用Object get(Object obj) 参数:哪个类的属性,哪个类的对象 student ; 返回值: 我们设置的属性值
String username = (String) fieldUserNameObj.get(stu); //stu.getUserName("username');
int age = (int) fieldAgeObj.get(stu); ///stu.getAge("age");
System.out.println(username);
System.out.println(age);
}
// 3.给Student的private属性设置值
// 4.使用反射获取 private的属性值
@Test
public void test02() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
//1.获取Student的字节码对象
Class clazz = Class.forName("com.it.classapi.Student");
//2.调用 getDeclaredField(String name)
Field idField = clazz.getDeclaredField("id");
Field nameField = clazz.getDeclaredField("name");
//3.去除私有权限
idField.setAccessible(true);
nameField.setAccessible(true);
//4.设置属性值
Student stu = (Student) clazz.newInstance();
idField.set(stu,12);
nameField.set(stu,"唐嫣");
//5.获取属性
int id = (int) idField.get(stu);
String name = (String) nameField.get(stu);
System.out.println(id);
System.out.println(name);
}
}
6.反射练习:
需求: 类加载器加载配置文件信息, 反射读取配置信息创建对象,并调用方法执行.
代码实现:
public interface Person {
void eat();
void sleep();
}
学生类
public class Student implements Person{
@Override
public void eat() {
System.out.println("学生吃饭");
}
@Override
public void sleep() {
System.out.println("学生睡觉");
}
}
老师类
public class Teacher implements Person {
@Override
public void eat() {
System.out.println("老师吃饭..");
}
@Override
public void sleep() {
System.out.println("老师睡觉..");
}
}
配置文件: demo.properties
classpath=com.it.reflect_demo.Teacher
method=eat
测试类:
public class ReflectTest {
@Test
public void test01() throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
//1.获取ReflectTest 字节码对象 ,目的是获取类加载器
Class clazz = ReflectTest.class;
//2.获取类加载器
ClassLoader classLoader = clazz.getClassLoader();
//3.调用类加载器的getResourceAsStream 读取配置文件 demo.properties
InputStream inputStream = classLoader.getResourceAsStream("demo.properties");
//4.创建Properties对象
Properties properties = new Properties();
//5.调用集合的load方法加载流
properties.load(inputStream);
//6.获取集合中的数据
String classpath = properties.getProperty("classpath");
String method = properties.getProperty("method");
//System.out.println(classpath + " "+ method);
//7.创建新的字节码对象
Class clazzNew = Class.forName(classpath);
//8.获取方法对象
Method methodFieldObj = clazzNew.getDeclaredMethod(method);
//9.调用方法
methodFieldObj.invoke(clazzNew.newInstance());
}
}