📋 个人简介
- 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜
- 📝 个人主页:馆主阿牛🔥
- 🎉 支持我:点赞👍+收藏⭐️+留言📝
- 📣 系列专栏:java 小白到高手的蜕变🍁
- 💬格言:要成为光,因为有怕黑的人!🔥
目录
- 📋 个人简介
- 前言
- 通过反射创建对应的运行时类对象
- 通过反射获取运行时类的内部结构(了解)
- 提供结构丰富的People
- 获取运行时类的属性结构
- 获取运行时类的方法结构
- 获取运行时类的构造器结构
- 获取运行时类的父类以及父类的泛型
- 获取运行时类的接口,包,注解等
- 通过反射调用运行时类的内部结构(重要)
- 调用运行时类中的指定构造器
- 调用运行时类中的指定属性
- 调用运行时类中的指定方法
- 结语
前言
本篇我将总结如何使用反射调用类的内部结构!
通过反射创建对应的运行时类对象
public static void main(String[] args) throws Exception {
Class<People> cl = People.class;
// newInstance():调用此方法创建对应的运行时类对象
// java9之后,这个方法过期了,应使用getConstructor().newInstance()
// 也就是先调用空参构造器,然后newInstance()创建对象
People obj = cl.getConstructor().newInstance();
System.out.println(obj);
}
要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限得够。通常,设置为 public 。
在 javabean 中要求提供一个 public 的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用 super ()时,保证父类有此构造器
通过反射获取运行时类的内部结构(了解)
提供结构丰富的People
这里提供一个结构丰富的People类用于下面的测试!
package java反射;
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
// 父类
class Creature<T> implements Serializable{
private char sex;
public double weight;
private void breath(){
System.out.println("呼吸");
}
public void eat(){
System.out.println("吃东西");
}
}
// 接口
interface Myinterface{
void info();
}
// 注解
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, MODULE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String value() default "hello";
}
// 子类
@MyAnnotation(value="hi")
public class People extends Creature<String> implements Comparable<String>,Myinterface {
private String name;
int age;
public int id;
public People(){
}
@MyAnnotation(value="aniu")
private People(String name) {
this.name = name;
}
People(String name, int age) {
this.name = name;
this.age = age;
}
@MyAnnotation
private void show(String nation){
System.out.println("国籍:" + nation);
}
public String display(String interests){
return interests;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(String o) {
return 0;
}
@Override
public void info() {
System.out.println("我是一个人!");
}
}
这个结构中有继承,注解,接口,泛型,以及不同权限的属性和方法等,接下类我们通过反射来获取这些结构学习!
获取运行时类的属性结构
public static void main(String[] args) {
Class cls = People.class;
// 获取属性结构
// getFields():获取当前运行时类及其父类中声明为public的访问权限的属性
Field[] fields = cls.getFields();
for (Field item:fields){
System.out.println(item);
}
System.out.println("------------------------------------");
// getDeclaredFields():获取当前运行时类中生申明的所有属性(不包含父类中的属性)
Field[] declaredFields = cls.getDeclaredFields();
for (Field item:declaredFields){
System.out.println(item);
// 属性的权限修饰符 数据类型 变量名 也可单独获取到
// 1.权限修饰符
int modifiers = item.getModifiers();
System.out.print(Modifier.toString(modifiers) + "\t");
// 2.数据类型
Class type = item.getType();
System.out.print(type.getName() + "\t");
// 3.变量名
String name = item.getName();
System.out.print(name);
System.out.println("\n");
}
}
获取运行时类的方法结构
public static void main(String[] args) {
Class cls = People.class;
// getMethods() 获取当前运行时类以及父类中声明为public的方法
Method[] methods = cls.getMethods();
for(Method m:methods){
System.out.println(m);
}
System.out.println("--------------------------");
// getDeclaredMethods() 获取当前运行时类声明的所有方法(不包含父类)
Method[] declaredMethods = cls.getDeclaredMethods();
for(Method m:declaredMethods){
System.out.println(m);
// 方法也可以获取方法申明的注解 权限修饰符 返回值类型 方法名 形参列表 抛出的异常
// 这里我只写一下获取方法的注解
Annotation[] annotations = m.getAnnotations();
for(Annotation a : annotations){
System.out.println(a);
}
}
}
获取运行时类的构造器结构
和上面的一样
getConstructors()和getDeclaredConstructors();,我不再写案例!
获取运行时类的父类以及父类的泛型
package java反射;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* @Author:Aniu
* @Date:2023/1/17 21:35
* @description 获取运行时类的父类以及父类的泛型
*/
public class Demo4 {
public static void main(String[] args) {
Class<People> cls = People.class;
// getSuperclass() 获取运行时类的父类
Class<? super People> superclass = cls.getSuperclass();
System.out.println(superclass);
System.out.println("--------------");
// getGenericSuperclass() 获取运行时类的带泛型的父类
Type genericSuperclass = cls.getGenericSuperclass();
System.out.println(genericSuperclass);
System.out.println("--------------");
// 获取运行时类的带泛型的父类的泛型
ParameterizedType genericSuperclass1 = (ParameterizedType) genericSuperclass;
Type[] actualTypeArguments = genericSuperclass1.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
}
}
获取运行时类的接口,包,注解等
package java反射;
import java.lang.annotation.Annotation;
/**
* @Author:Aniu
* @Date:2023/1/17 21:43
* @description 获取运行时类的接口,包,注解等
*/
public class Demo5 {
public static void main(String[] args) {
Class<People> cls = People.class;
// getInterfaces() 获取运行时类实现的接口 ,获取父类实现的接口:cls.getSuperclass().getInterfaces();
Class<?>[] interfaces = cls.getInterfaces();
for(Class c : interfaces){
System.out.println(c);
}
System.out.println("------------------");
// getPackage() 获取运行时类所在的包
Package aPackage = cls.getPackage();
System.out.println(aPackage);
System.out.println("------------------");
// getAnnotations() 获取运行时类的注解
Annotation[] annotations = cls.getAnnotations();
for(Annotation a : annotations){
System.out.println(a);
}
}
}
通过反射调用运行时类的内部结构(重要)
调用运行时类中的指定构造器
package java反射;
import java.lang.reflect.Constructor;
/**
* @Author:Aniu
* @Date:2023/1/19 17:00
* @description 调用运行时类中的指定构造器
*/
public class Demo8 {
public static void main(String[] args) throws Exception {
Class<People> cls = People.class;
// 1.获取指定构造器
// getDeclaredConstructor 参数:构造器的参数列表
Constructor<People> declaredConstructor = cls.getDeclaredConstructor(String.class);
// 2.保证此构造其实可访问的
declaredConstructor.setAccessible(true);
// 3.调用此构造器创建对象
People p = declaredConstructor.newInstance("aniu");
System.out.println(p);
}
}
jdk9之后我们用这种方式创建运行时类的对象!即调用空参构造器创建运行时类的对象!
调用运行时类中的指定属性
package java反射;
import java.lang.reflect.Field;
/**
* @Author:Aniu
* @Date:2023/1/19 16:15
* @description 调用运行时类中的指定属性
*/
public class Demo6 {
public static void main(String[] args) throws Exception {
Class<People> cls = People.class;
// 创建运行时类的对象
People p = cls.getConstructor().newInstance();
// 获取指定的属性 getField()要求运行时类的属性权限修饰符为public
// 通常不用此方法
Field id = cls.getField("id");
// 设置当前属性的值
// set(): 参数:1:指明设置那个对象的属性 参数2:将此属性值设置为多少
id.set(p,10);
// 获取当前属性的值
// get(): 参数1:获取那个对象当前的属性值
int pid = (int) id.get(p);
System.out.println(pid);
System.out.println("--------------");
// 1.获取指定的属性 通常用getDeclaredField
Field name = cls.getDeclaredField("name");
// 2.保证当前属性是可访问的 (对于private和默认权限的属性,设置和获取之前都要加这个)
name.setAccessible(true);
// 3.设置指定对象的此属性值
name.set(p,"aniu");
// 4.获取指定对象的此属性值
String s = (String) name.get(p);
System.out.println(s);
}
}
调用运行时类中的指定方法
package java反射;
import java.lang.reflect.Method;
/**
* @Author:Aniu
* @Date:2023/1/19 16:39
* @description 调用运行时类中的指定方法
*/
public class Demo7 {
public static void main(String[] args) throws Exception {
Class<People> cls = People.class;
// 创建运行时类的对像
People p = cls.getConstructor().newInstance();
// 1.获取指定的某个方法 getMethod只能获取public
// getDeclaredMethod所有权限方法都可获取。参数一:指明获取的方法的名称 参数二:指明获取的方法的形参列表
Method show = cls.getDeclaredMethod("show", String.class);
// 2. 保证当前方法可访问
show.setAccessible(true);
// 3. 调用方法
// invoke() 参数一:方法的调用者 方法二:给方法的参数
// invoke() 方法的返回值即为调用的类中方法的返回值
Object c = show.invoke(p, "China");
System.out.println(c);
}
}
那如何调用静态方法呢?我给People类加一个静态方法:
public static void print(){
System.out.println("我是阿牛!");
}
Method print = cls.getDeclaredMethod("print");
print.setAccessible(true);
print.invoke(People.class); // 静态方法可以用类名直接调用
结语
如果你觉得博主写的还不错的话,可以关注一下当前专栏,博主会更完这个系列的哦!也欢迎订阅博主的其他好的专栏。
🏰系列专栏
👉软磨 css
👉硬泡 javascript
👉flask框架快速入门