四种获取Class实例的方法

  1. 调用运行时类的属性
  2. 通过运行时类的对象,调用getClass()
  3. 调用Class静态方法:forName(String classPath) 开发中最常用
  4. 使用类的加载器:ClassLoader (了解就行)
package day_12_29;

import org.junit.Test;

/**
* @author soberw
* @Classname ReflectionTest
* @Description 反射之获取Class的实例的四种方式
* @Date 2021-12-29 20:44
*/
public class ReflectionTest {
//获取Person类
@Test
public void test() {
//1.调用运行时类的属性
Class<Person> clazz1 = Person.class;
System.out.println(clazz1); //2. 通过运行时类的对象,调用getClass()
Person p1 = new Person();
Class<? extends Person> clazz2 = p1.getClass();
System.out.println(clazz2); //3. 调用Class静态方法:forName(String classPath) 开发中最常用
Class<?> clazz3 = null;
try {
clazz3 = Class.forName("day_12_29.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(clazz3); //4. 使用类的加载器:ClassLoader (了解就行)
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class<?> clazz4 = null;
try {
clazz4 = classLoader.loadClass("day_12_29.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(clazz4); } }
//将要获取到的类
class Person { }

定义测试结构

获取属性结构

获取类中的属性:

getFields():获取当前运行时类以及所有父类的声明为public访问权限的属性

getDeclaredFields():获取当前运行时类中声明的所有属性(与权限修饰无关,且不包含父类中声明的属性)

获取属性的内部结构:

1.getModifiers():获取权限修饰符,返回值为int类型,对应的是修饰符的值,可通过Modifier.toString(...)获得

2.getType():数据类型,返回Class类型,可通过.getName()获得全类名

3.getName():返回变量名,String类型

package day_12_30.reflection.test;

import day_12_30.reflection.java.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier; /**
* @author soberw
* @Classname FieldTest
* @Description 获取当前运行时类的属性结构
* @Date 2021-12-30 14:54
*/
public class FieldTest {
//获取当前运行时类(Class实例)
Class<Person> clazz = Person.class; @Test
public void test1(){
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
/*
public int day_12_30.reflection.java.Person.id
public double day_12_30.reflection.java.Creature.weight
*/
}
System.out.println(); Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
/*
private java.lang.String day_12_30.reflection.java.Person.name
int day_12_30.reflection.java.Person.age
public int day_12_30.reflection.java.Person.id
*/
} }
//权限修饰符 数据类型 变量名
@Test
public void test2(){
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
//1.权限修饰符
int modifier = f.getModifiers();
System.out.print(Modifier.toString(modifier) + "\t"); //2.数剧类型
Class<?> type = f.getType();
System.out.print(type.getName() + "\t"); //3,变量名
String name = f.getName();
System.out.print(name); System.out.println();
}
/*
private java.lang.String name
int age
public int id
*/
}
}

获取方法结构

获取类中的方法:

getMethods():获取当前运行时类以及所有父类的声明为public访问权限的方法

getDeclaredMethods():获取当前运行时类中声明的所有方法(与权限修饰无关,且不包含父类中声明的)

注意:重写的方法也能获取到

获取方法的内部结构:

-    @Xxxx
- 权限修饰符 返回值类型 方法名(参数类型1 形参名1,...) throws XxxException{}

1.getAnnotations() 获取方法的全部声明注解,返回为Annotation[]数组

2.getModifiers()获取方法的权限修饰符

3.getReturnType()获取返回值类型,可通过.getName()获得具体名字

4.getName()方法名

5.getParameterTypes():形参列表。返回为通过Class[]数组。.getName()获得具体名字

6.getExceptkionTypes(): 获得跑出的异常类型。返回为通过Class[]数组。.getName()获得具体名字

package day_12_30.reflection.test;

import day_12_30.reflection.java.Person;
import org.junit.Test; import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier; /**
* @author soberw
* @Classname MethodTest
* @Description 获取运行时类的方法结构
* @Date 2021-12-30 15:05
*/
public class MethodTest {
Class<Person> clazz = Person.class;
@Test
public void test1(){
Method[] methods = clazz.getMethods();
for (Method m : methods) {
System.out.println(m);
}
/*
public java.lang.String day_12_30.reflection.java.Person.toString()
public int day_12_30.reflection.java.Person.compareTo(java.lang.String)
public int day_12_30.reflection.java.Person.compareTo(java.lang.Object)
public void day_12_30.reflection.java.Person.info()
public java.lang.String day_12_30.reflection.java.Person.display(java.lang.String,int) throws java.lang.NullPointerException,java.lang.ClassCastException
public void day_12_30.reflection.java.Creature.eat()
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
*/
System.out.println();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
/*
public java.lang.String day_12_30.reflection.java.Person.toString()
public int day_12_30.reflection.java.Person.compareTo(java.lang.String)
public int day_12_30.reflection.java.Person.compareTo(java.lang.Object)
public void day_12_30.reflection.java.Person.info()
public java.lang.String day_12_30.reflection.java.Person.display(java.lang.String,int) throws java.lang.NullPointerException,java.lang.ClassCastException
private static void day_12_30.reflection.java.Person.showDesc()
private java.lang.String day_12_30.reflection.java.Person.show(java.lang.String)
*/
}
/*
@Xxxx
权限修饰符 返回值类型 方法名(参数类型1 形参名1,...) throws XxxException{}
*/
@Test
public void test2(){
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
//1.获取注解
Annotation[] annotations = m.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}
//2,权限修饰符
System.out.print(Modifier.toString(m.getModifiers()) + "\t");
//3.返回值类型
System.out.print(m.getReturnType().getName()+"\t");
//4.方法名
System.out.print(m.getName());
System.out.print("( ");
//5.形参列表
Class<?>[] parameterTypes = m.getParameterTypes();
if(!(parameterTypes == null && parameterTypes.length == 0)){
for(int i = 0;i < parameterTypes.length;i++){
if(i == parameterTypes.length - 1){
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
}
}
System.out.print(" )");
//6.抛出的异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
if(exceptionTypes.length > 0){
System.out.print("throws ");
for(int i = 0;i < exceptionTypes.length;i++){
if(i == exceptionTypes.length - 1){
System.out.print(exceptionTypes[i].getName());
break;
} System.out.print(exceptionTypes[i].getName() + ",");
}
}
System.out.println();
}
/*
public java.lang.String toString( )
public int compareTo( java.lang.String args_0 )
public volatile int compareTo( java.lang.Object args_0 )
public void info( )
public java.lang.String display( java.lang.String args_0,int args_1 )throws java.lang.NullPointerException,java.lang.ClassCastException
@day_12_30.reflection.java.MyAnnotation("soberw")
private java.lang.String show( java.lang.String args_0 )
private static void showDesc( )
*/
} }

获取构造器结构(包括父类泛型)

获取当前运行类中的构造器

1.getConstructors():获取当前运行时类中声明为public的构造器

2.getDelaredConstructors():获取当前运行时类中声明的所有的构造器

获取父类(也可以是带泛型的)——比较常用

1.getSuperclass():获取运行时类的父类

2.getGenericSuperclass():获取运行时的带泛型的父类

3.获取运行时类的带泛型的父类的泛型,在上一步之后,得到一个返回值为Type类型的返回值

​ 调用其getActualTypeArguments()方法获得Type[]即所有泛型的类型,在通过getName()

​ 取名字

    @Test
public void test1(){
Constructor<?>[] constructors = clazz.getConstructors();
for (Constructor<?> c : constructors) {
System.out.println(c);
/*
public day_12_30.reflection.java.Person(java.lang.String,int)
public day_12_30.reflection.java.Person()
*/
}
System.out.println();
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor<?> d : declaredConstructors) {
System.out.println(d);
/*
public day_12_30.reflection.java.Person(java.lang.String,int)
private day_12_30.reflection.java.Person(java.lang.String)
public day_12_30.reflection.java.Person()
*/
}
}
/**
* 获取父类(包括带泛型的,以及其泛型)
*/
@Test
public void test3(){
Class<? super Person> superclass = clazz.getSuperclass();
System.out.println(superclass);
//class day_12_30.reflection.java.Creature //获取运行时类的带泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
//day_12_30.reflection.java.Creature<java.lang.String> //获取运行时类的带泛型的父类的泛型
//转换为参数化类型,即为泛型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
//获取泛型的参数
Type[] actualTypeArguments = paramType.getActualTypeArguments();
for (Type a : actualTypeArguments) {
//两种都可
//System.out.println(a.getTypeName());
System.out.println(((Class<?>)a).getName());
//java.lang.String
}
}

获取实现的接口

获取运行时类实现的接口(以及泛型)

getInterfaces()返回Class[] ,实现的所有接口,不包括父类实现的

getGenericInterfaces():返回运行时类直接实现的接口的类型

获取运行时类的父类实现的接口

getSuperclass().getInterfaces()

@Test
public void test4(){
//获取运行时类实现的接口
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> c : interfaces) {
System.out.println(c);
/*
interface day_12_30.reflection.java.MyInterface
interface java.lang.Comparable
*/
}
System.out.println();
//获取运行时类的父类实现的接口
Class<?>[] interfaces1 = clazz.getSuperclass().getInterfaces();
for (Class<?> c : interfaces1) {
System.out.println(c);
//interface java.io.Serializable
}
System.out.println();
//返回运行时类直接实现的接口的类型。
Type[] genericInterfaces = clazz.getGenericInterfaces();
for (Type g : genericInterfaces) {
System.out.println(g.getTypeName());
/*
day_12_30.reflection.java.MyInterface
java.lang.Comparable<java.lang.String>
*/
}
}

获取所在包

getPackage()

@Test
public void test5(){
Package aPackage = clazz.getPackage();
System.out.println(aPackage);
//package day_12_30.reflection.java
}

获取注解

注解要想通过反射获得,必须生命周期为运行时RUNTIME的注解

getAnnotations() 返回一个数组,因为可能多个注解Annotation[]

 @Test
public void test6(){
Annotation[] annotations = clazz.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
//@day_12_30.reflection.java.MyAnnotation("soberw")
}
}

获取并创建指定构造器

分为三步走:

  1. 获取指定的构造器getDeclaredConstrutor():参数:指定构造器的参数列表(这里我们一般都会调用无参的),返回值为Constructor类型
  2. 保证构造器是可访问的setAccessible(true):设置为true,私有的也能调用
  3. 调用构造器创建运行时类的对象newInstance():可变形参,默认为空参

获取指定属性

首先第一步:必须先通过构造器去声明一个运行时类的对象

获取声明为public 的属性(不常用)

getField(String name)获取属性(必须是public)

set(两个参数)第一个为指定的对象,第二个为设置的值

get(一个参数)获取指定对象的当前属性值

获取并操作运行时类中的指定的属性(比较常用)

同样三步走:

  1. 获取运行时类中指定的变量名的属性getDeclaredField(),返回值为Field类型

  2. 保证当前属性是可访问的:setAccessible(true)

  3. 获取、设置指定对象的此属性值

    set(两个参数)第一个为指定的对象,第二个为设置的值

    get(一个参数)获取指定对象的当前属性值

获取并运行指定方法

通过getMethod(String name,Class c)获取的实际开发中并不常用,因为只能获取public的,不再细说

获取并操作运行时类的指定的方法(比较常用)

首先第一步:必须先通过构造器去声明一个运行时类的对象

接下来四步走:

  1. getDeclaredMethod(): 参数1:指明获取方法的名称。参数2:指明方法形参列表(因为存在重载情况),返回值为Method类型

  2. 保证当前属性是可访问的:setAccessible(true)

  3. 调用invoke()以运行此方法,参数1:方法的调用者(一般为声明的对象) 参数2:方法实参(传入参数,若无参则为空)

  4. 返回值,invoke()方法可以有返回值,Object类型的

若原方法无返回值(void),则返回null

若原方法有返回值,则invoke()会返回指定的类型

另外注意

  • 若是调用类的静态方法,我们同样需要先声明对象,然后通过名字得到对应方法
  • 只是在指定调用者的时候,不能再指定为声明的对象,而是运行类本身,或者写为null
package day_12_30.reflection.test;

import day_12_30.reflection.java.Person;
import org.junit.Test; import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method; /**
* @author soberw
* @Classname ReflectionTest
* @Description 调用运行时类中指定的结构:属性、方法、构造器
* @Date 2021-12-30 15:52
*/
public class ReflectionTest {
Class<Person> clazz = Person.class; //构造器
@Test
public void test1() throws Exception {
Constructor<Person> constructor = clazz.getDeclaredConstructor();
Person person = constructor.newInstance();
System.out.println(person);
//Person{name='null', age=0, id=0} //获取私有构造器
Constructor<Person> declaredConstructor = clazz.getDeclaredConstructor(String.class);
//将访问权限打开
declaredConstructor.setAccessible(true);
Person soberw = declaredConstructor.newInstance("soberw");
System.out.println(soberw);
//Person{name='soberw', age=0, id=0}
} //属性
@Test
public void test2() throws Exception {
//第一步: 一定要先创建对象
Person person = clazz.getDeclaredConstructor().newInstance();
Field pname = clazz.getDeclaredField("name");
pname.setAccessible(true);
pname.set(person, "soberw");
System.out.println(pname.get(person));
//soberw
} //方法
@Test
public void test3() throws Exception {
Person person = clazz.getDeclaredConstructor().newInstance();
Method show = clazz.getDeclaredMethod("show", String.class);
show.setAccessible(true);
Object invoke = show.invoke(person, "中国");
//我的国籍是中国
System.out.println(invoke);
//中国
//调用静态方法
Method showDesc = clazz.getDeclaredMethod("showDesc");
showDesc.setAccessible(true);
Object val1 = showDesc.invoke(null);
//我是一个可爱的人
Object val2 = showDesc.invoke(clazz);
//我是一个可爱的人
Object val3 = showDesc.invoke(Person.class);
//我是一个可爱的人
System.out.println(val1);
//null
System.out.println(val2);
//null
System.out.println(val3);
//null
}
}

浅谈Java之反射的更多相关文章

  1. 浅谈Java的反射机制和作用

    浅谈Java的反射机制和作用 作者:Java大师 欢迎转载,转载请注明出处 很多刚学Java反射的同学可能对反射技术一头雾水,为什么要学习反射,学习反射有什么作用,不用反射,通过new也能创建用户对象 ...

  2. 浅谈Java的反射的原理

    Java的编译过程 谈及反射,不得不先了解一下,java的整个编译过程,整体的java编译过程可以参考 之前的一篇 一个java文件被执行的历程 这里我们只针对 对象这一层级来讨论,一个java文件, ...

  3. 浅谈Java代理二:Cglib动态代理-MethodInterceptor

    浅谈Java代理二:Cglib动态代理-MethodInterceptor CGLib动态代理特点: 使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生 ...

  4. 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance

    浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...

  5. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  6. 浅谈Java中的equals和==(转)

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  7. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  8. 浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  9. 浅谈JAVA集合框架

    浅谈JAVA集合框架 Java提供了数种持有对象的方式,包括语言内置的Array,还有就是utilities中提供的容器类(container classes),又称群集类(collection cl ...

随机推荐

  1. 发布 vscode 插件 Cnblogs Client For VSCode 预览版

    为了方便大家使用 vscode 发布博文,我们做了一个小插件,今天发布预览版,欢迎大家试用并反馈问题与建议. 插件的英文名称是 Cnblogs Client For VSCode,简称是 vscode ...

  2. STM32时钟系统的配置寄存器和源码分析

    一.时钟系统 概述 时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令,时钟系统就是CPU的脉搏,决定cpu速率. STM32有多个时钟来源的选择,为什么 STM32 要有多个时钟源呢 ...

  3. Powershell 【控制台常用方法】

    1 function Pause(){ 2 [System.Console]::Write('按任意键继续...') 3 [void][System.Console]::ReadKey(1) 4 } ...

  4. Python常用功能函数系列总结(二)

     本节目录 常用函数一:sel文件转换 常用函数二:refwork文件转换 常用函数三:xml文档解析 常用函数四:文本分词 常用函数一:sel文件转换 sel是种特殊的文件格式,具体应用场景的话可以 ...

  5. 微信小程序base64图片保存到手机相册

    问题:base64图片不能直接用wx.saveImageToPhotosAlbum保存到手机相册 解决: 先用fs.writeFile写入本地文件,再wx.saveImageToPhotosAlbum ...

  6. Mybatis配置解析(核心配置文件)

    4.配置解析 4.1.核心配置文件 Mybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息 mybatis-config.xml properties(属性)重点 settings ...

  7. 关于jar包和war读取静态文件

    在war包中static中的静态文件,打成jar包后却读取不到,这是为什么呢,让我门看下两种读取的区别 一.war包中都取静态模板文件 public static void download(Stri ...

  8. GeoServer介绍

    GeoServer本质上是一个地图服务器,它是遵循OpenGIS Web 服务器规范的J2EE实现,通过它可以方便的将地图数据发布为地图服务,实现地理空间数据在用户之间的共享.另外,它也提供了相应的接 ...

  9. 《剑指offer》面试题30. 包含min函数的栈

    问题描述 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min.push 及 pop 的时间复杂度都是 O(1).   示例: MinStack minSt ...

  10. Discuz!X V3.4后台任意文件删除

    Discuz!X V3.4后台任意文件删除 简述 该漏洞为后台任意文件删除,需要有管理员的权限,所以说危害非常小 复现环境 docker.vulhub-master 项目地址:https://gite ...