JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

java基础——Java反射详解

wys521 2025-02-13 14:42:57 精选教程 23 ℃ 0 评论

作者 | 山丘i

来源 |
cnblogs.com/mengd/p/13400005.html

一、反射概述

1. java.lang.Class:是反射的源头

我们创建一个类,通过编译,生成对应的.calss文件,之后使用java.exe加载(jvm的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓存区,那么这个运行时类的本身就是一个class的实例

  • 每一个运行时类只加载一次
  • 有了Class实例以后,我们才可以进行如下的操作:
    • 创建对应的运行时类的对象(重点)
    • 可以获取对象的运行时类的完整结构(属性、方法、构造器、内部类、、、)(理解)
    • 调用对应的运行时类的指定的结构(属性、方法)(重点)

在反射以前,如何创建一个类的对象,并调用其中的方法属性

public?void?test1()?{
????Person p =?new?Person();
????p.setAge(10);
????p.setName("AA");
????p.show();
????System.out.println(p);
??}


有了反射,可以通过反射创建一个类的对象,并调用其中的方法,下面详细说

public?void?test2() throws Exception?{
????
????Class clazz = Person.class;
????
????//1.创建clazz对应的运行时类Person类的对象
????Person p = (Person)clazz.newInstance();
????System.out.println(p);
????
????//2.通过反射调用运行时类的指定属性,public name的修改方式
????Field f1 = clazz.getField("name");
????f1.set(p,?"LiuDaHua");
????System.out.println(p);
????
????//private age的方式
????Field f2 = clazz.getDeclaredField("age");
????f2.setAccessible(true);
????f2.set(p,?20);
????System.out.println(p);
????
????//3.通过反射调用运行时类的指定方法 public修饰的
????Method m1 = clazz.getMethod("show");
??????// 执行
????m1.invoke(p);
??????// 带参数的方法
????Method m2 = clazz.getMethod("display", String.class);
????m2.invoke(p,?"cn");
????
??}


回到顶部

二、如何获取Class的实例


1.调用运行时类本身的.class属性


Class clazz = Person.class;
System.out.println(clazz.getName());
????
Class clazz1 = String.class;
System.out.println(clazz1.getName());


2.通过运行时类的对象获取

Person p =?new?Person();
Class clazz2 = p.getClass();
System.out.println(clazz.getName());


3.通过Class的静态方法获取,通过此方式,体会反射的动态性


String className =?"com.atguigu.java.Person";
????
Class clazz4 = Class.forName(className);
System.out.println(clazz4);


4.通过类的加载器

ClassLoader classLoader =?this.getClass().getClassLoader();
Class clazz5 = classLoader.loadClass(className);
System.out.println(clazz5.getName());

整个代码


public?void?test4() throws Exception?{
????//1.调用运行时类本身的.class属性
????Class clazz = Person.class;
????System.out.println(clazz.getName());
????
????Class clazz1 = String.class;
????System.out.println(clazz1.getName());
????
????//2.通过运行时类的对象获取
????Person p =?new?Person();
????Class clazz2 = p.getClass();
????System.out.println(clazz.getName());
????
????//3.通过Class的静态方法获取,通过此方式,体会反射的动态性
????String className =?"com.atguigu.java.Person";
????
????Class clazz4 = Class.forName(className);
????System.out.println(clazz4);
????
????
????//4.通过类的加载器
????ClassLoader classLoader =?this.getClass().getClassLoader();
????Class clazz5 = classLoader.loadClass(className);
????System.out.println(clazz5.getName());
??}


回到顶部

三、创建运行时类对象


1. 获取Class的实例

通常直接使用类名.class , 例如Person.class

当然了,上面的几种方法都是可以的


String?className =?"com.atguigu.java.Person";
Class?clazz = Class.forName(className);


2.创建运行时类对象

创建对应的运行时类的对象,使用的是newInstance(),实际上就是运用了运行时类的空参数的构造器

要想能够创建成功

  • 要求对应的运行时类要有空参数的构造器
  • 构造器的权限修饰符的权限要足够


Object obj = clazz.newInstance();//调用的是空参构造器
Person p = (Person)obj;
System.out.println(p);


全部代码


public?void?test1() throws Exception?{
??// 获取Class实例
???????Class clazz = Person.class;
????
????//创建对应的运行时类的对象,使用的是newInstance(),实际上就是运用了运行时类的空参数的构造器
????//要想能够创建成功,①要求对应的运行时类要有空参数的构造器,②构造器的权限修饰符的权限要足够
????Object obj = clazz.newInstance();//调用的是空参构造器
????Person p = (Person)obj;
????System.out.println(p);
??}


回到顶部

四、通过反射获取类的完整结构


1.获取运行时类的属性

1.getFields() 返回 :表示公共字段的 Field 对象的数组,只能获取运行时类中以及父类中声明的为public的属性

Field[] fiels = clazz.getFields();
for(int?i=0;i


2.getDeclaredFields() :获取运行时类本身声明的所有的属性,包括私有的


Field[] fiels1 = clazz.getDeclaredFields();
for(int?i=0;i


2.获取属性的各个部分的内容

权限修饰符 变量类型 变量名

1.获取每个属性的权限修饰符


Field[] field = clazz.getDeclaredFields();
??for(Field i:field) {
??//1.获取每个属性的权限修饰符
????int?a = i.getModifiers();
????String str1 = Modifier.toString(a);
????System.out.print(str1+" ");
??}


2.获取属性的变量类型


Field[] field = clazz.getDeclaredFields();
????for(Field i:field) {
????//2.获取属性的变量类型
????Class?type?= i.getType();
????System.out.print(type+" ");
??}


3.获取属性名


Class clazz = Person.class;
????Field[] field = clazz.getDeclaredFields();
????for(Field i:field) {
????//3.获取属性名
????System.out.print(i.getName());
????System.out.println();
??}


3.获取运行时类的方法(重点)

1.getMethods() 获取运行时类及其父类中所有声明为public的方法


Class clazz = Person.class;
Method[] m1 = clazz.getMethods();
??for(Method m:m1) {
??System.out.println(m);
??}


2.getDeclaredMethods() 获取运行时类本身声明的所有的方法


Method[] methods = clazz.getDeclaredMethods();
??for(int?i=0;i


4.获取方法的各个部分的内容

注解 权限修饰符 返回值类型 方法名 形参列表 异常

1.注解


Class clazz = Person.class;
????
??Method[] m1 = clazz.getMethods();
??for(Method m:m1) {
??Annotation[] an = m.getAnnotations();
??for(Annotation a:an) {
??????System.out.println(a);
??}
}


2.权限修饰符


int?a = m.getModifiers();
String str1 = Modifier.toString(a);
System.out.print(str1+" ");


3.返回值类型

Class return1 = m.getReturnType();
System.out.print(return1+" ");


4.方法名

System.out.print(m.getName()+" ");

5.形参列表

System.out.print("(");
Class[]?params?= m.getParameterTypes();
for(Class p :?params) {
??System.out.print(p.getName());
}
System.out.println(")"+" ");


6.抛的异常

Class[] ex = m.getExceptionTypes();
??for(Class e:ex) {
????System.out.print(e.getName());
??}
?// for(int i=0;i


5.获取构造器


@Test
??public?void?test5()?throws?Exception?{
????
????Class clazz = Class.forName("com.atguigu.java.Person");
????
????Constructor[] cons = clazz.getDeclaredConstructors();
????for(Constructor c : cons) {
??????System.out.println(c);
????}
????
??
??}


6.获取运行时类的父类


@Test
??public?void?test6()?{
????Class clazz = Person.class;
????Class super1 = clazz.getSuperclass();
????System.out.println(super1);
??}


7.获取带泛型的父类


@Test
??public?void?test7()?{
????Class clazz = Person.class;
????Type type1 = clazz.getGenericSuperclass();
????System.out.println(type1);
??}


8.获取父类的泛型(重点)


@Test
??public?void?test8()?{
????Class clazz = Person.class;
????Type type1 = clazz.getGenericSuperclass();
????
????ParameterizedType param= (ParameterizedType)type1;
????Type[] ars = param.getActualTypeArguments();
????System.out.println((Class)ars[0]);
??}


9.获取实现的接口


@Test
??public?void?test9()?{
????Class clazz = Person.class;
????Class[] i = clazz.getInterfaces();
????for(Class a:i) {
??????System.out.println(a);
????}
??}


10.获取所在的包


@Test
??public?void?test10()?{
????Class clazz = Person.class;
????Package p = clazz.getPackage();
????System.out.println(p);
??}


全部代码如下:


package com.atguigu.java;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.junit.Test;

/**
?* 通过反射获取类的完整结构
?*
?* @author MD
?*
?*/
public?class?TestField?{

??
??/**
???* 1.获取运行时类的属性
???*/
??@Test
??public?void?test1()?{
????Class clazz = Person.class;
????
????//1.getFields() 返回 :表示公共字段的 Field 对象的数组
????// 只能获取运行时类中以及父类中声明的为public的属性
// Field[] fiels = clazz.getFields();
// for(int i=0;i


回到顶部

五、调用运行时类的指定结构


1.调用运行时类指定的属性并赋值

1. 获取指定的属性


getField(String?fieldName):获取运行时类中声明为public的指定的属性名为fieldName的属性
Field?name = clazz.getField("name");


2.创建运行时类的对象

Person p = (Person) clazz.newInstance();
System.out.println(p);

3.将运行时类的指定属性赋值

name.set(p,?"Jerry");
System.out.println(p);

给age赋值,private需要注意

getDeclareField(String?fieldName):获取运行时类中指明为filedName的属性


Field age = clazz.getDeclaredField("age");
??//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作
??age.setAccessible(true);//私有的设置成可以访问的
??age.set(p,1);
??System.out.println(p);


给id赋值,默认的修饰符


Field id = clazz.getDeclaredField("id");
??id.set(p,10);
??System.out.println(p);


2.调用运行时类中指定的方法

1.getMethod(String methodName,Class...params)获取指定的public方法,方法名,参数列表

Class?clazz = Person.class;
Method?m1 = clazz.getMethod("show");

2.创建运行时类的对象


Person?p =(Person)clazz.newInstance();


3.和属性相似,这里是invoke关键字里面是对象和参数列表,或许还有返回值,用Object接收

Object returnVal = m1.invoke(p);
System.out.println(returnVal);//没返回值的打印为null


4.获取toString()有返回值的

Method m2 = clazz.getMethod("toString");
Object returnVal1 = m2.invoke(p);
System.out.println(returnVal1);


5.获取display()带参数的

Method m3 = clazz.getMethod("display",String.class);
m3.invoke(p,?"china");


6.获取info()静态的方法

Method m4 = clazz.getMethod("info");
m4.invoke(Person.class);


7.获取Test() 私有的带参数的有返回值的

Method m5 = clazz.getDeclaredMethod("Test",String.class,Integer.class);
m5.setAccessible(true);
Object?o = m5.invoke(p,"测试",5);
System.out.println(o);


3.调用指定的构造器,创建类对象


public?void?test3() throws InstantiationException, Exception?{
????Class clazz = Person.class;
????Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
????cons.setAccessible(true);
????Person p = (Person)cons.newInstance("迪丽热巴",20);
????System.out.println(p);

????
??}


全部代码

package?com.atguigu.java;

import?java.lang.reflect.Constructor;
import?java.lang.reflect.Field;
import?java.lang.reflect.Method;

import?org.junit.Test;

/**
?* ******调用对应的运行时类的指定的结构(属性、方法)
?*?@author?MD
?*
?*/
public?class?TestField1?{
??/**
???* 调用运行时类指定的属性
???*?@throws?Exception
???*?@throws?NoSuchFieldException
???*/
??
??@Test
??public?void?test1()?throws?Exception?{
????Class clazz = Person.class;
????
????//1.获取指定的属性
????//getField(String fieldName):获取运行时类中声明为public的指定的属性名为fieldName的属性
????Field name = clazz.getField("name");
????//2.创建运行时类的对象
????Person p = (Person) clazz.newInstance();
????System.out.println(p);
????//3.将运行时类的指定属性赋值
????name.set(p,?"Jerry");
????System.out.println(p);
????
????//给age赋值,private需要注意
????//getDeclareField(String fieldName):获取运行时类中指明为filedName的属性
????Field age = clazz.getDeclaredField("age");
????//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作
????age.setAccessible(true);//私有的设置成可以访问的
????age.set(p,1);
????System.out.println(p);
????????
????//给id赋值,默认的修饰符
????Field id = clazz.getDeclaredField("id");
????id.set(p,10);
????System.out.println(p);
????
??}
????
??/**
???* 调用运行时类中指定的方法
???*?@throws?Exception
???*?@throws?NoSuchMethodException
???*/
??@Test
??public?void?test2()?throws?NoSuchMethodException, Exception?{
????Class clazz = Person.class;
????
????//getMethod(String methodName,Class...params)获取指定的public方法,方法名,参数列表
????Method m1 = clazz.getMethod("show");
????
????//创建运行时类的对象
????Person p =(Person)clazz.newInstance();
????
????//和属性相似,这里是invoke关键字里面是对象和参数列表,或许还有返回值,用Object接收
????Object returnVal = m1.invoke(p);
????System.out.println(returnVal);
????????
????//获取toString()有返回值的
????Method m2 = clazz.getMethod("toString");
????Object returnVal1 = m2.invoke(p);
????System.out.println(returnVal1);
????
????//获取display()带参数的
????Method m3 = clazz.getMethod("display",String.class);
????m3.invoke(p,?"china");
????????
????//获取info()静态的方法
????Method m4 = clazz.getMethod("info");
????m4.invoke(Person.class);
????????
????//获取Test() 私有的带参数的有返回值的
????Method m5 = clazz.getDeclaredMethod("Test",String.class,Integer.class);
????m5.setAccessible(true);
????Object o = m5.invoke(p,"测试",5);
????System.out.println(o);
??}
??
??
??/**
???* 调用指定的构造器,创建类对象
???*?@throws?Exception
???*?@throws?InstantiationException
???*/
??
??@Test
??public?void?test3()?throws?InstantiationException, Exception?{
????Class clazz = Person.class;
????Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
????cons.setAccessible(true);
????Person p = (Person)cons.newInstance("迪丽热巴",20);
????System.out.println(p);
??}
}


回到顶部

六、ClassLoader

类加载器是用来把类(class)装载进内存

1.获取一个系统类加载器

ClassLoader loader1 = ClassLoader.getSystemClassLoader();
System.out.println(loader1);


2.获取系统类加载器的父类加载器,即扩展类加载器

ClassLoader loader2 = loader1.getParent();
System.out.println(loader2);


3.获取扩展类加载器的父类加载器,即引导类加载器,加载的是核心库,打印为null

ClassLoader loader3 = loader2.getParent();
System.out.println(loader3);


4.测试当前类由哪个类加载器进行加载

Class clazz1 = Person.class;
ClassLoader loader4 = clazz1.getClassLoader();
System.out.println(loader4);//系统类加载器


1. 描述一下JVM加载class文件的原理机制?

JVM中类的装载是由ClassLoader和它的子类来实现的,

Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表