初识反射
概述:
- 反射是java语言提供的一种动态获取对象属性和方法的机制。
查看有Class实例的属性
- 类
Class class1 = Object.class; - 接口
Class class2 = Comparable.class; - 数组
Class class3 = String[].class; - 枚举
Class class4 = Season.class; - 注解
Class class5 = SuppressWarnings.class; - 基本数据类型
Class class6 = int.class; - void
Class class7 = void.class;
获取class实例
- 获取class实例的方法:
- 要求编译时期已知类型 类名称.Class
- 获取对象的运行时类型 obj.getClass()
- 获取编译期间未知类型 Class.forName(“包名.类名”)
Class类的常用方法
- Class.forName 返回指定类名 name 的 Class 对象
- Class.newInstance() 返回该Class对象所表示的类或接口的实例
- Class.getClassLoader() 返回该Class对象所表示的类或接口的类加载器
@Test
public void test02() throws Exception {
//返回指定类名 name 的 Class 对象
Class class1 = Class.forName("com.jiazhong.L_反射的使用.test01.Person");
System.out.println(class1);
//调用缺省构造函数,返回该Class对象的一个实例
Class class2 = class1.newInstance().getClass();//就相当于 new
System.out.println(class2);
//返回该类的类加载器
ClassLoader classLoader = class1.getClassLoader();
System.out.println(classLoader);
}
- 查看某个类的类加载器对象
- 获取默认系统加载器 ClassLoader.getSystemClassLoader()
- 获取某个类的类加载器对象 Class.getClassLoader()
- 获取某个类的父类加载器对象 ClassLoader.getParent() 【如果是根加载器,则返回null】
@Test
public void test01() throws ClassNotFoundException {
//获取默认的系统加载器
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println(classLoader);
//查看某个类是哪个类加载器加载的
ClassLoader classLoader1 = Class.forName("com.jiazhong.L_反射的使用.test01.Person").getClassLoader();
System.out.println(classLoader1);
ClassLoader classLoader2 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader2);
//获取某个类加载器的父加载器
ClassLoader classLoader3 = classLoader.getParent();
System.out.println(classLoader3);
}
反射的使用
创建运行时类的对象 newInstance
@Test
public void test01() throws Exception {
Class clazz = Person.class;
//创建Person类的实例
Person person = (Person) clazz.newInstance();
System.out.println(person);
}
获取运行时类的完整的结构
- 获取属性
- getFields() 获取到运行时类本身及其所有的父类中声明为public权限的属性
- getDeclaredFields()获取当前运行时类中声明的所有属性
@Test
public void test02() {
Class clazz = Person.class;
//获取所有的属性和细节
//getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
Field[] fields = clazz.getFields();
//进行遍历
for (Field f : fields) {
System.out.println(f);
}
System.out.println("———————————————-");
//getDeclaredFields():获取当前运行时类中声明的所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
}
- getModifiers() 获取权限修饰符
- getType() 获取属性的类型
- getName() 获取变量名
@Test
public void test03() {
Class clazz = Person.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
//1.权限修饰符
int modifiers = f.getModifiers();
System.out.println(Modifier.toString(modifiers));
//2.数据类型
Class<?> type = f.getType();
System.out.println(type.getName());
//3.变量名
String name = f.getName();
System.out.println(name);
}
}
- 获取所有的方法以及相关的细节
- getMethods() 获取到运行时类本身及其所有的父类中声明为public权限的方法
- getDeclaredMethods() 获取当前运行时类中声明的所有方法
public void test04() {
Class clazz = Person.class;
//getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println(m);
}
System.out.println("————————————————–");
//getDeclaredMethods():获取当前运行时类中声明的所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
}
- 注解信息
- getAnnotations() 获取当前运行时类中声明的所有注解
- getModifiers() 权限修饰符
- getReturnType() 返回值类型
- getName() 方法名
- parameterTypes (形参类型1 参数1,形参类型2 参数2,…)
- getExceptionTypes() throws 异常类型1,…{}
@Test
public void test05() {
Class clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
// 1.获取方法声明的注解
Annotation[] annotations = m.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
// 2.权限修饰符
System.out.println(Modifier.toString(m.getModifiers()));
// 3.返回值类型
System.out.println(m.getReturnType().getName());
// 4.方法名
System.out.println(m.getName());
// 5.形参列表
Class<?>[] parameterTypes = m.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType.getName());
}
// 6.异常列表
Class<?>[] exceptionTypes = m.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType.getName());
}
}
}
- 获取其他结构(构造器、父类、接口、包、注解等)
- getSuperclass()获取运行时类的父类
- getInterfaces()获取运行时类实现的接口
- getPackage()获取运行时类所在的包
- getGenericSuperclass()获取运行时类的带泛型的父类
@Test
public void test06() throws Exception {
//1. getSuperclass()获取运行时类的父类
Class clazz = Class.forName("com.jiazhong.L_反射的使用.test02.Person");
Class superclass = clazz.getSuperclass();
System.out.println(superclass);
//2. getInterfaces()获取运行时类实现的接口
Class[] interfaces = clazz.getInterfaces();
for (Class c : interfaces) {
System.out.println(c);
}
//3. getPackage()获取运行时类所在的包
Package aPackage = clazz.getPackage();
System.out.println(aPackage);
//4. getGenericSuperclass()获取运行时类的带泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
}
- 获取运行时类的父类的泛型 (难)
@Test
public void test07() throws Exception {
Class clazz = Class.forName("com.jiazhong.L_反射的使用.test02.Person");
//getGenericSuperclass()获取带泛型的父类(Type是一个接口,Class实现了此接口
Type genericSuperclass = clazz.getGenericSuperclass();
//强转目前得到的泛型的类型
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
//调用getActualTypeArguments获取泛型的参数,获取到的泛型参数可能是一个数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
System.out.println(actualTypeArguments[1].getTypeName());
}
调用指定属性和方法
package com.jiazhong.L_反射的使用.test02;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
//********************如下是调用指定的属性************************
/*
* 反射的应用3-1:调用指定的属性
*
* */
//public int age = 1;
@Test
public void test01() throws Exception {
Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
//获取运行时类的指定名称的属性
Field age = clazz.getField("age");
//获取或设置此属性的值
age.set(person, 30);
System.out.println(age.get(person));
}
/// /private String name;
@Test
public void test02() throws Exception {
Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
//获取运行时类的指定名称的属性(私有化的属性使用)getDeclaredField来进行获取
Field name = clazz.getDeclaredField("name");
//setAccessible(true):确保此属性是可以访问的
name.setAccessible(true);
//获取或设置此属性的值
name.set(person, "Zhangsan");
System.out.println(name.get(person));
}
//private static String info;
@Test
public void test03() throws Exception {
Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
//获取运行时类的指定名称的属性(私有化的属性使用)getDeclaredField来进行获取
Field info = clazz.getDeclaredField("info");
//setAccessible(true):确保此属性是可以访问的
info.setAccessible(true);
//获取或设置此属性的值
//因为是类变量,我们就可以把对象名省略掉,用null来进行表示
info.set(null, "I am a boy.");
System.out.println(info.get(person));
}
//********************如下是调用指定的方法************************
/*
* 反射的应用3-2:调用指定的方法
*
* */
//private String showNation(String nation,int age)
@Test
public void test04() throws Exception {
Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
//获取运行时类的指定名称的属性(私有化的属性使用)getDeclaredMethod来进行获取
Method showNation = clazz.getDeclaredMethod("showNation", String.class, int.class);
//setAccessible(true):确保此属性是可以访问的
showNation.setAccessible(true);
//3.通过Method实例调用invoke(Object obj,Object … objs),即为对Method对应的方法的调用。
//invoke()的返回值即为Method对应的方法的返回值
//特别的:如果Method对应的方法的返回值类型为void,则invoke()返回值为null
Object invoke = showNation.invoke(person, "中国", 30);
System.out.println(invoke);
}
//public static void showInfo()
@Test
public void test05() throws Exception {
Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
//获取运行时类的指定名称的属性(私有化的属性使用)getDeclaredMethod来进行获取
Method showNation = clazz.getDeclaredMethod("showInfo");
//setAccessible(true):确保此属性是可以访问的
showNation.setAccessible(true);
//3.通过Method实例调用invoke(Object obj,Object … objs),即为对Method对应的方法的调用。
//invoke()的返回值即为Method对应的方法的返回值
//特别的:如果Method对应的方法的返回值类型为void,则invoke()返回值为null
Object invoke = showNation.invoke(null);
System.out.println(invoke);
}
//********************如下是调用指定的构造器************************
/*
* 反射的应用3-3:调用指定的构造器
*
* */
//private Person(String name, int age)
@Test
public void test06() throws Exception {
Class clazz = Person.class;
//获取运行时类的指定名称的属性(私有化的属性使用)getDeclaredMethod来进行获取
Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
//setAccessible(true):确保此属性是可以访问的
constructor.setAccessible(true);
//3.通过Constructor实例调用newInstance(Object … objs),返回一个运行时类的实例。
Person person1 = (Person) constructor.newInstance("李四", 40);
System.out.println(person1);
}
//使用Constructor替换原有的使用Class调用newInstance()的方式创建对象
@Test
public void test07() throws Exception {
Class clazz = Person.class;
//1.通过Class的实例调用getDeclaredConstructor(Class … args),获取指定参数类型的构造器
Constructor declaredConstructor = clazz.getDeclaredConstructor();
//2.设置可以进行访问
declaredConstructor.setAccessible(true);
//3.通过Constructor实例调用newInstance(Object … objs),返回一个运行时类的实例。
Person person = (Person) declaredConstructor.newInstance();
System.out.println(person);
}
}
反射的动态性
package com.jiazhong.L_反射的使用.test04;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Date;
public class ReflectTest {
//静态性 唯一的
public Person getInstance() {
return new Person();
}
//体会:反射的动态性
//举例1:造对象
public <T> T getInstance(String className) throws Exception {
Class clazz = Class.forName(className);
Constructor declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
return (T) declaredConstructor.newInstance();
}
@Test
public void test01() throws Exception {
Person p1 = getInstance();
System.out.println(p1);
/*String className = "com.jiazhong.G_面向对象高级编程.代码块.Animal";
Person p2 = getInstance(className);
System.out.println(p2);*/
String dateName = "java.util.Date";
Date p3 = getInstance(dateName);
System.out.println(p3);
}
//体会:反射的动态性
//举例2:方法的调用
public Object invoke(String className, String methodName) throws Exception {
Class clazz = Class.forName(className);
Constructor declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance();
Method declaredMethod = clazz.getDeclaredMethod(methodName);
return declaredMethod.invoke(o);
}
@Test
public void test02() throws Exception {
String className = "com.jiazhong.L_反射的使用.test04.Person";
String methodName = "show";
Object invoke = invoke(className, methodName);
System.out.println(invoke);
}
}
获取配置文件信息
- Properties
- Properties 类是 Java 中用于处理配置文件的一个实用工具类,它继承自 Hashtable 类,允许应用程序读取和写入那些可在运行时进行修改的配置文件。在 Java 中,配置文件通常以 .properties 格式存在,它们以键值对的形式存储数据。
- Properties 类提供了一系列方法来操作键值对数据。最常用的方法包括:
- getProperty(String key): 根据指定的键获取属性值。
- setProperty(String key, String value): 设置或更新属性值。
- load(InputStream inStream): 从输入流中读取属性列表。
- store(OutputStream out, String comments): 将属性列表写入输出流。
加载配置文件的两种方法
- 方式1:使用FileInputStream
- 要求:配置文件必须放置在当前module的src目录下
- my-project/
├─ module1/
│ ├─ src/
│ │ └─ config.properties
│ └─ pom.xml <- 模块根目录
└─ module2/
- 方式2:使用类加载器
- 从 Java 的类路径中查找资源,不依赖具体文件系统路径。
相对路径规则:
无前置路径(如 config.properties):默认从类路径的根目录查找。
带前置路径(如 com/example/config.properties):从对应包路径查找。 - my-project/
├─ module1/
│ ├─ src/
│ │ └─ config.properties
│ └─ pom.xml <- 模块根目录
└─ module2/
- 从 Java 的类路径中查找资源,不依赖具体文件系统路径。
@Test
public void test02() throws IOException {
Properties properties = new Properties();
//方式1:此时默认的相对路径是当前的module
//FileInputStream in = new FileInputStream("src//config.properties");
//方式2:使用类的加载器
//此时默认的相对路径是当前module的src目录
InputStream in = ReflectionTest04.class.getClassLoader().getResourceAsStream("config.properties");
properties.load(in);
//获取配置文件中的信息
String name = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println("name = " + name + ", password = " + password);
}
反射综合习题
案例:榨汪机榨水果汁,水果分别有苹果(Apple)、香蕉(Banana)、桔子(Orange)等。
提示:
1、声明(Fruit)水果接口,包含榨汁抽象方法:void squeeze();;
2、声明榨汁机(Juicer),包含运行方法:publicvoidrun(Fruit f),方法体中,调用f的榨汁方法squeeze()
3、声明各种水果类,实现水果接口,并重写squeeze();
4、在src下,建立配置文件:config.properties,并在配置文件中配上fruitName=xxx(其中xx为某种水果的全类名
5、在FruitTest测试类中,
(1)读取配置文件,获取水果类名,并用反射创建水果对象,
(2)创建榨汁机对象,并调用run(方法
package com.jiazhong.jiaocheng.reflection.exercise;
public class Apple implements Fruit{
@Override
public void squeeze() {
System.out.println("apple汁");
}
}
package com.jiazhong.jiaocheng.reflection.exercise;
public class Banana implements Fruit{
@Override
public void squeeze() {
System.out.println("banana汁");
}
}
package com.jiazhong.jiaocheng.reflection.exercise;
public class Orange implements Fruit{
@Override
public void squeeze() {
System.out.println("orange汁");
}
}
package com.jiazhong.jiaocheng.reflection.exercise;
public interface Fruit {
void squeeze();
}
package com.jiazhong.jiaocheng.reflection.exercise;
public class Juicer {
public void run(Fruit f){
f.squeeze();
}
}
package com.jiazhong.jiaocheng.reflection.exercise;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Properties;
public class FruitTest {
public static void main(String[] args) throws Exception {
Properties properties=new Properties();// 创建Properties集合对象,为了获取配置文件
InputStream in=FruitTest.class.getClassLoader().getResourceAsStream("Juicer.properties");// 创建输入流对象
properties.load(in);// 加载输入流对象
String fruit =properties.getProperty("fruitName");// 获取配置文件中 fruitName属性的值
// System.out.println(fruit);
Class<?> fruitClass= Class.forName(fruit);
Fruit fruit1= (Fruit) fruitClass.newInstance();
Juicer juicer=new Juicer();
juicer.run(fruit1);
}
}
Properties properties=new Properties();// 创建Properties集合对象,为了获取配置文件
InputStream in=FruitTest.class.getClassLoader().getResourceAsStream("Juicer.properties");// 创建输入流对象
properties.load(in);// 加载输入流对象
String fruit =properties.getProperty("fruitName");// 获取配置文件中 fruitName属性的值
// System.out.println(fruit);
Class<?> fruitClass= Class.forName(fruit);
Fruit fruit1= (Fruit) fruitClass.newInstance();
Juicer juicer=new Juicer();
juicer.run(fruit1);
}
}
评论前必须登录!
注册