反射概述 Java Reflection
- Reflection是被视为动态语言的关键, 反射机制允许程序在执行期借助于Refiection API取得任何类的内部信息, 并能直接操作任意对象的内部属性及方法
- 加载完类之后, 在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象), 这个对象就包含了完整的类的结构信息, 我们可以通过对象看到类的结构. 这个对象就像一面镜子, 透过这个镜子看到类的结构, 所以 我们形象地称之为: 反射
- Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 在运行时动态代理
- 反射相关的主要API
- java.lang.Class 代表一个类
- java.lang.reflect.Method 代表类的方法
- java.lang.reflect.Field 代表类的成员变量
- java.lang.reflect.Constructor 代表类的构造器
- …
- 哪些类型可以有Class对象
- class 外部类, 成员, 局部内部类, 匿名内部类
- interface 接口
- [] 数组
- enum 枚举
- annotation 注解@interface
- primitive type 基本数据类型
- void
使用反射前后对比
- 使用反射前
@Test
public void test1(){
Person p1 = new Person("Tom",12);//1.创建Person类的对象
p1.age = 10;//2.通过对象,调用其内部的属性和方法
System.out.println(p1.toString());//Person{name='Tom', age='10'}
p1.show();//你好,我是你男朋友
}
- 创建Person类对象
- 通过对象调用其内部属性和方法
在Person类的外部,不可以通过Person类的对象调用其内部私有结构, 比如:name, showNation() 以及私有的构造器
- 使用反射后
@Test
public void test2() throws Exception {
Class clazz = Person.class;
//1.通过反射,创建Person类的对象
Constructor cons = clazz.getConstructor(String.class, int.class);
Object obj = cons.newInstance("Tom", 12);
Person p = (Person) obj;
System.out.println(obj.toString());//Person{name='Tom', age='12'}
System.out.println(p.toString());//Person{name='Tom', age='12'}
//2.通过反射,调用对象指定的属性和方法
//调用属性
Field age = clazz.getDeclaredField("age");
age.set(p, 10);
System.out.println(p.toString());//Person{name='Tom', age='10'}
//调用方法
Method show = clazz.getDeclaredMethod("show");
show.invoke(p);//你好,我是你男朋友
//通过反射,可以调用Person类的私有结构,私有构造器,方法,属性
//调用私有的构造器
Constructor cons1 = clazz.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person p1 = (Person) cons1.newInstance("Jerry");
System.out.println(p1);//Person{name='Jerry', age='0'}
//调用私有的属性
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(p1,"韩梅梅");
System.out.println(p1.toString());//Person{name='韩梅梅', age='0'}
//调用私有的方法
Method showNation = clazz.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
String obj1 = (String) showNation.invoke(p1, "中国");//我是中国人
System.out.println(obj1);//中国
}
获取Class实例的四种方式
- 方式一: 调用运行时类的属性:
.class
Class<Person> clazz1 = Person.class;
可以写上泛型, 例如这里写了Person
- 方式二: 通过运行时类的对象
Person p1 = new Person();
Class clazz2 = p1.getClass();
- 方式三: 通用Class的静态方法:
forName
Class clazz3 = Class.forName("com.atguigu.java.Person");
- 方式四: 使用类的加载器
ClassLoader cl = A_ReflectionTest.class.getClassLoader();
Class clazz4 = cl.loadClass("com.atguigu.java.Person");
[比较] 都相等
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
System.out.println(clazz1 == clazz4);//true
类加载器ClassLoader
-
对于自定义类, 使用系统类加载器进行加载
ClassLoader classLoader = B_ClassLoaderTest.class.getClassLoader(); System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
-
调用系统类加载器的
getParent()
获取扩展类加载器ClassLoader classLoader1 = classLoader.getParent(); System.out.println(classLoader1);//sun.misc.Launcher$ExtClassLoader@28a418fc
-
调用扩展类加载器的getParent()无法获取引导类加载器, 引导类加载器主要负责加载java的核心类库,无法加载自定义类的
ClassLoader classLoader2 = classLoader1.getParent(); System.out.println(classLoader2);//null
读取配置文件的两种情况
- 情况一: 配置文件在工程下
Properties pro = new Properties();
FileInputStream fis = new FileInputStream("JDBC.properties");
//如果在src下需要加src//
//FileInputStream fis1 = new FileInputStream("src//JDBC.properties");
pro.load(fis);
String user = pro.getProperty("user");
String pass = pro.getProperty("pass");
System.out.println(user+"---"+pass);//嘿咻---abc
- 情况二: 配置文件在src下
Properties pro = new Properties();
ClassLoader classLoader = B_ClassLoaderTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("JDBC1.properties");
pro.load(is);
String user = pro.getProperty("user");
String pass = pro.getProperty("pass");
System.out.println(user+"---"+pass);//牧风---aaa
newInstance通过反射创建对应的运行时类的对象
- 煎蛋举栗
Class clazz = Person.class;
Person o = (Person) clazz.newInstance();
System.out.println(o);//Person{name='null', age='0'}
- 举栗子, 体会反射的动态性
@Test
public void test2() throws Exception {
int num = new Random().nextInt(3);
String classPath = "";
switch (num){
case 0:
classPath = "java.util.Date";
break;
case 1:
classPath = "java.lang.Object";
break;
case 2:
classPath = "com.atguigu.java.Person";
break;
}
Object obj = getInstance(classPath);
System.out.println(obj);//Thu May 27 18:24:10 CST 2021
}
public Object getInstance(String classPath) throws Exception {
//创建一个指定类的对象
//classPath:指定类的全类名
Class clazz = Class.forName(classPath);//先获取类名
return clazz.newInstance();//类名.newInstance
}
获取
- 获取属性结构
getFields()
获取当前运行时类及其父类中声明为public访问权限的属性
Class clazz = Person.class;
Field[] fields = clazz.getFields();
for (Field f : fields){
System.out.println(f);
//public int com.atguigu.java1.Person.id
//public double com.atguigu.java1.Creature.weight
//出来的时候只出子类和父类的public
}
- 获取属性结构
getDeclaredFields()
获取当前运行时类中声明的所有属性 (没有父类
Class clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields){
System.out.println(f);
//private java.lang.String com.atguigu.java1.Person.name
//int com.atguigu.java1.Person.age
//public int com.atguigu.java1.Person.id
}
- 获取权限修饰符
getModifiers()
Class clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields){
int modifiers = f.getModifiers();
System.out.print(Modifier.toString(modifiers));
}
- 获取数据类型
getType()
Class type = f.getType();
- 获取变量名
getName()
String fName = f.getName();
- 获取方法
getMethods()
获取当前运行时类及其所有父类中声明为public权限的方法
Class clazz = Person.class;
Method[] methods = clazz.getMethods();
for (Method m : methods){
System.out.println(m);
}
[这里出现了m, 用于后面的例子]
- 获取方法
getDeclaredMethods()
获取当前运行时类中声明的所有方法 (不包含父类
Method[] declaredMethods = clazz.getDeclaredMethods();
- 获取方法声明的注解
getAnnotations()
Class clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods){
Annotation[] annos = m.getAnnotations();
for (Annotation a : annos){
System.out.println(a);
}
}
- 获取权限修饰符
getModifiers()
System.out.print(Modifier.toString(m.getModifiers()));
- 获取返回值类型
getReturnType()
System.out.print(m.getReturnType().getName());
- 获取方法名
getName()
System.out.print(m.getName());
- 获取形参列表
getParameterTypes()
Class[] parameterTypes = m.getParameterTypes();
- 获取异常
getExceptionTypes()
Class[] exceptionTypes = m.getExceptionTypes();
- 获取构造器
getDeclaredConstructors()
和getConstructors()
Class clazz = Person.class;
//所有构造器
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor c : constructors){
System.out.println(c);
}
System.out.println();
//自己的构造器
Constructor[] constructors1 = clazz.getDeclaredConstructors();
for (Constructor c : constructors1){
System.out.println(c);
}
- 获取运行时的父类
getSuperclass()
Class superclass = clazz.getSuperclass();
- 获取带泛型的父类
getActualTypeArguments()
Class clazz = Person.class;
Type superclass = clazz.getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) superclass;
//获取泛型的类型
Type[] actualTypeArguments = paramType.getActualTypeArguments();
//方式一
System.out.println(actualTypeArguments[0].getTypeName());//java.lang.String
//方式二
System.out.println(((Class) actualTypeArguments[0]).getName());//java.lang.String
- 获取运行时自己类接口
getInterfaces()
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for (Class c : interfaces){
System.out.println(c);
}
- 获取运行时父类接口
getSuperclass().getInterfaces()
Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
for (Class c : interfaces1){
System.out.println(c);
}
- 获取运行时类所在的包
getPackage()
Class clazz = Person.class;
Package aPackage = clazz.getPackage();
System.out.println(aPackage);
- 获取类的注解
getAnnotations()
Annotation[] annotations = clazz.getAnnotations();
属性结构(public) | getFields() | 方法名 | getName() |
---|---|---|---|
属性结构(自己) | getDeclaredFields() | 形参列表 | getParameterTypes() |
权限修饰符 | getModifiers() | 异常 | getExceptionTypes() |
数据类型 | getType() | 注解 | getAnnotations() |
变量名 | getName() | 构造器(public) | getConstructors() |
方法(public) | getMethods() | 构造器(自己) | getDeclaredConstructors() |
方法(自己) | getDeclaredMethods() | 父类 | getSuperclass() |
方法声明的注解 | m.getAnnotations() | 带泛型的父类 | getActualTypeArguments() |
权限修饰符 | getModifiers() | 接口 | getInterfaces() |
返回值类型 | getReturnType() | 包 | getPackage() |
调用
- 属性
@Test
public void testField() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//获取指定的属性,要求运行时类中属性声明为public,通常不采用此方法
Field id = clazz.getField("id");
//设置当前属性的值
id.set(p, 1001);
//获取当前属性的值
int pId = (int)id.get(p);
System.out.println(pId);//1001
}
@Test
public void testField1() throws Exception{
Class clazz = Person.class;
Person p = (Person) clazz.newInstance();
Field name = clazz.getDeclaredField("name");
name.setAccessible(true);
name.set(p,"慢慢");
System.out.println(name.get(p));//慢慢
}
- 方法
@Test
public void test1() throws Exception{
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//参数1:方法名 参数2:形参列表
Method show = clazz.getDeclaredMethod("show", String.class);
//私有开锁
show.setAccessible(true);
//参数1:方法的调用者 参数2:实参
show.invoke(p,"CHN");//我的国籍是CHN
//返回值
Object returnValue = show.invoke(p,"CHN");
System.out.println(returnValue);//CHN
//如何调用静态方法
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
Object returnVal = showDesc.invoke(Person.class);
System.out.println(returnVal);//null
}
- 构造器
@Test
public void test2() throws Exception{
Class clazz = Person.class;
//private Person(String name)
//1.获取构造器
Constructor con = clazz.getDeclaredConstructor(String.class);
//2.保证可访问
con.setAccessible(true);
//调用此构造器,创建运行时类的对象
Object tom = con.newInstance("Tom");
System.out.println(tom);//Person{name='Tom', age=0, id=0}
}
私有的要用.setAccessible(true)