参考链接:
Java 反射 -超详细讲解(附源码)_皮卡卡西的博客-CSDN博客_反射java
java.lang.reflect.Field.getAnnotation()方法示例 -java.lang.reflect包教程™
文章一
反射 概述: 反射不需要程序员自己实现,都是底层框架或者JVM去使用的一个技术. 专门用来解析 .class文件里 的所有数据 (公开的,私有的) 2,原理 把解析 到的 .class里的数据 封装成了Class工具类 3怎么获取Class对象 Class对象是 封装了.class文件里的数据 ,,可以通过Class对象提供的种方法解析数据 static Class<?> forName(String className) 类名.class 对象.getClass()
反射 测试获取Class对象 public class C1 {public static void main(String[] args) throws ClassNotFoundException { method();//获取Class对象 } //获取Class对象--用来解析.class文件里的所有数据 public static void method() throws ClassNotFoundException { //参数是类的全路径 -- 包名.类名 Class c = Class.forName("java.lang.String"); Class c2 = String.class; Class c3 = new String().getClass(); System.out.println(c); System.out.println(c2); System.out.println(c3); } }
反射Student类里的所有信息import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; public class C1_Student { public static void main(String[] args) throws Exception { //1,获取Student类的Class对象 Class s = Student.class; //method(s);//解析 构造方法 //method2(s);//解析 成员变量 //method3(s);//解析 成员方法 //method4(s);//用反射 创建对象 //method5(s);//用反射 设置变量的值 method6(s);//用反射 执行方法 } //用反射 执行方法 public static void method6(Class s) throws Exception { //获取指定的方法 public void test(int a) Method m = s.getMethod("test", int.class); Object o = s.newInstance(); //invoke(m,n)--m是对象--n是要给方法传入的参 m.invoke(o,50);//执行方法 } //用反射 设置变量的值 public static void method5(Class s) throws Exception { //TODO public String name ; Field f = s.getField("name"); Object o = s.newInstance(); //set(m,n)--m是对象--n是想要设置啥值 f.set(o,"jack");//设置值 System.out.println( f.get(o) );//获取值 } //用反射 创建对象 public static void method4(Class s) throws Exception{ //用反射new --自动调用无参构造 Object o = s.newInstance(); Student s2 = (Student) o ;//向下转型,目的是使用子类的特有功能 s2.show();//使用了Student类里功能 } //解析Student.class文件中的 成员方法 //getMethods() getMethod() -- 获取自己和父类的所有 公开的方法 public static void method3(Class s) throws NoSuchMethodException { //获取 所有方法 Method[] ms = s.getMethods(); //遍历数组,获取每个方法m for (Method m : ms) { System.out.println( m.getName() );//获取方法名 Class[] c = m.getParameterTypes();//获取参数类型 System.out.println( Arrays.toString(c) ); } //TODO 获取 特定的方法 public void test(int a) Method m = s.getMethod("test", int.class); System.out.println( m.getName() ); } //解析Student.class文件中的 成员变量 //getFields() getField() --获取公开的 public static void method2(Class s) throws Exception { //获取所有 成员变量们~~~~ Field[] fs = s.getFields(); //遍历,得到每个成员变量f for (Field f : fs){ //获取变量名 System.out.println(f.getName()); //获取变量类型 System.out.println(f.getType().getName()); } //根据属性名获取属性 Field f = s.getField("name"); //获取属性类型 System.out.println(f.getType().getName()); } //解析Student.class文件中的构造方法 //getConstructors() getConstructor()--获取公开的 public static void method(Class s) throws NoSuchMethodException { //获取 所有的构造方法 存入Constructor[] Constructor[] cs = s.getConstructors(); //遍历数组,得到每个构造方法c for (Constructor c: cs ) { //获取构造方法的 名称 System.out.println(c.getName()); //TODO 解析构造方法的 参数的类型 Class[] cc =c.getParameterTypes(); System.out.println(cc); } //TODO 获取指定的构造方法 --public Student(int age) //getConstructor()的参数是 构造方法的参数类型 的Class对象 Constructor con = s.getConstructor(int.class); System.out.println(con.getName()+"--"); } }
暴力反射 --1,概述 专门用来 反射 类中的 公开数据 和 私有数据 --2,新的API --普通反射 -- 只能获取public的 getMethod() getMethods() getField() getFields() getConstructor() getConstructors() --暴力反射 --除了public的甚至连private都可以获取 getDeclaredMethod() getDeclaredMethods() getDeclaredField() getDeclaredFields() getDeclaredConstructor() getDeclaredConstructors()
--创建Person类public class Person { private String name; int age; public char sex; private void show(){ System.out.println("show.."); } void test(int a){ System.out.println("test.."+a); } }
--创建测试类import java.lang.reflect.Field; import java.lang.reflect.Method; public class Test3_Person { public static void main(String[] args) throws Exception { // method();//暴力反射 成员变量 method2();//暴力反射 成员方法 } //TODO 暴力反射成员方法 public static void method2() throws Exception { Class c = Person.class; //暴力反射--获取所有方法 Method[] ms = c.getDeclaredMethods(); //遍历数组,获取每个方法m for (Method m : ms) { //获取方法名 System.out.println(m.getName()); } //TODO 获取指定的方法 Method m = c.getDeclaredMethod("show"); Object oo = c.newInstance(); m.setAccessible(true);//开启 私有资源的 访问权限 m.invoke(oo); } //TODO 暴力反射成员变量 public static void method() throws Exception { Class c = Person.class; //暴力反射--获取所有属性,包括 public的private的default的 Field[] fs = c.getDeclaredFields(); //遍历数组,得到每个属性f for (Field f : fs) { //获取属性名 System.out.println( f.getName() ); } //只获取一个私有的属性 Field f = c.getDeclaredField("name"); Object o = c.newInstance(); //对私有的属性操作抛出异常:IllegalAccessException f.setAccessible(true);//开启私有的访问权限 f.set(o,"jack");//设置值 System.out.println( f.get(o) );//获取值 } }
反射和暴力反射的区别总结: 1, 普通反射 和 暴力反射 的区别 ? 暴力反射是可以获取public的甚至private 普通反射只能获取public的 2, 怎么使用暴力反射? 用对API ( getDeclaredXxx() ) 设置访问权限( setAccessible(true) ) 3, getDeclaredXxx() 和 getXxx() 的区别?? getXxx() 获取public资源 -- 获取自己的方法和父类的方法 getDeclaredXxx() 获取所有资源 --只获取自己的方法
文章2
Java 反射 -超详细讲解(附源码)_皮卡卡西的博客-CSDN博客_反射java
1:反射概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
实际上,我们创建的每一个类也都是对象,即类本身是java.lang.Class类的实例对象。这个实例对象称之为类对象,也就是Class对象。那么,Class对象又是什么对象呢?
2:Class对象特点
下图是Class类的api(图片来自于Java基础之—反射(非常重要)_敬业小码哥的博客-CSDN博客_反射)
从图中可以得出以下几点:
- Class 类的实例对象表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有很多的实例,每个类都有唯一的Class对象。
- Class 类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机自动构造的。也就是说我们不需要创建,JVM已经帮我们创建了。
- Class 对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法
3:反射的使用
假设我们现在有一个Hero类
package pojo;
public class Hero {
public String name; //姓名
public float hp; //血量
public float armor; //护甲
public int moveSpeed; //移动速度
}
1:获取类对象
获取类对象有3种方式
- Class.forName()(常用)
- Hero.class
- new Hero().getClass()
在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样。(此处准确是在ClassLoader下,只有一个类对象)
示例:
package pojo;
public class ObjectTest {
public static void main(String[] args) {
String className = "pogo.Hero";
try {
//获取类对象的第一种方式
Class pClass1 = Class.forName(className);
//获取类对象的第二种方式
Class pClass2 = Hero.class;
//获取类对象的第三种方式
Class pClass3 = new Hero().getClass();
System.out.println(pClass1==pClass2);//输出true
System.out.println(pClass1==pClass3);//输出true
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
三种方式中,常用第一种,第二种需要导入类的包,依赖太强,不导包就抛编译错误。第三种对象都有了还要反射干什么。一般都第一种,一个字符串可以传入也可写在配置文件中等多种方法。
2 利用反射机制创建对象
基本步骤
与传统的通过new 来获取对象的方式不同反射机制,反射会先拿到Hero的“类对象”,然后通过类对象获取“构造器对象”再通过构造器对象创建一个对象,具体步骤:
1.获取类对象 Class class = Class.forName("pojo.Hero");
2.获取构造器对象 Constructor con = clazz.getConstructor(形参.class);
3 获取对象 Hero hero =con.newInstance(实参);
上面是最简单的获取方法,当Hero的构造方法不是无参构造方法时,获取构造器对象略有不同,见下面测试:
构造方法不同时,获取构造器对象的方法
示例:
Hero类添加6种构造方法
//---------------构造方法-------------------
//(默认的构造方法)
Hero(String str){
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造方法
public Hero(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
public Hero(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Hero(String name ,float hp){
System.out.println("姓名:"+name+"血量:"+ hp);
}
//受保护的构造方法
protected Hero(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Hero(float hp){
System.out.println("私有的构造方法 血量:"+ hp);
}
- 通过反射机制获取对象
package test;
public class ConstructorTest {
/*
* 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
*
* 1.获取构造方法:
* 1).批量的方法:
* public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
* 2).获取单个的方法,并调用:
* public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
*
* 2.创建对象
* Constructor对象调用newInstance(Object... initargs)
*/
public static void main(String[] args) throws Exception {
//1.加载Class对象
Class clazz = Class.forName("pojo.Hero");
//2.获取所有公有构造方法
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("*****************获取公有、无参的构造方法*******************************");
Constructor con = clazz.getConstructor(null);
//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
//2>、返回的是描述这个无参构造函数的类对象。
System.out.println("con = " + con);
//调用构造方法
Object obj = con.newInstance();
System.out.println("******************获取私有构造方法,并调用*******************************");
con = clazz.getDeclaredConstructor(float.class);
System.out.println(con);
//调用构造方法
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
obj = con.newInstance(100);
}
}
输出:
**********************所有公有构造方法*********************************
public pojo.Hero(java.lang.String,float)
public pojo.Hero(char)
public pojo.Hero()
************所有的构造方法(包括:私有、受保护、默认、公有)***************
private pojo.Hero(float)
protected pojo.Hero(boolean)
public pojo.Hero(java.lang.String,float)
public pojo.Hero(char)
public pojo.Hero()
pojo.Hero(java.lang.String)
*****************获取公有、无参的构造方法*******************************
con = public pojo.Hero()
调用了公有、无参构造方法执行了。。。
******************获取私有构造方法,并调用*******************************
private pojo.Hero(float)
私有的构造方法 血量:100.0
总结:
1.获取构造器对象方法:
1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
2).获取单个的方法:
public Constructor getConstructor(Class… parameterTypes): 获取单个的"公有的"构造方法
public Constructor getDeclaredConstructor(Class…parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
3: 获取成员变量并使用
基本步骤
1.获取HeroPlus类的对象
new方法/第2章中的方法
h
2. 获取属性Field f1 = h.getDeclaredField("属性名")
3. 修改属性f1.set(h,实参)
,注意这里的h是对象,不是类对象
示例:
- 新增HeroPlus类
package pojo;
public class HeroPlus {
public String name;
public float hp;
public int damage;
public int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroPlus(){
}
public HeroPlus(String string) {
name =string;
}
@Override
public String toString() {
return "Hero [name=" + name + "]";
}
public boolean isDead() {
// TODO Auto-generated method stub
return false;
}
public void attackHero(HeroPlus h2) {
System.out.println(this.name+ " 正在攻击 " + h2.getName());
}
}
- 获取属性并修改
package test; public class ParaTest { public static void main(String[] args) { HeroPlus h =new HeroPlus(); //使用传统方式修改name的值为garen h.name = "garen"; try { //获取类HeroPlus的名字叫做name的字段 Field f1= h.getClass().getDeclaredField("name"); //修改这个字段的值 f1.set(h, "teemo"); //打印被修改后的值 System.out.println(h.name); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
补充:
getField和getDeclaredField的区别
getField 只能获取public的,包括从父类继承来的字段。
getDeclaredField 可以获取本类所有的字段,包括private的,但是 不能获取继承来的字段。 (注: 这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))
4: 获取成员方法并使用
1 获取HeroPlus类的对象 h
2 获取成员方法:
public Method getMethod(String name ,Class<?>… parameterTypes):获取"公有方法";(包含了父类的方法也包含Object类)
public Method getDeclaredMethods(String name ,Class<?>… parameterTypes) :获取成员方法,包括私有的(不包括继承的)
参数解释:
name : 方法名;
Class … : 形参的Class类型对象
3 调用方法
Method --> public Object invoke(Object obj,Object… args):
参数说明:
obj : 要调用方法的对象;
args:调用方式时所传递的实参;
示例:
package test;
public class MethodTest {
public static void main(String[] args) {
HeroPlus h = new HeroPlus();
try {
// 获取这个名字叫做setName,参数类型是String的方法
Method m = h.getClass().getMethod("setName", String.class);
// 对h对象,调用这个方法
m.invoke(h, "盖伦");
// 使用传统的方式,调用getName方法
System.out.println(h.getName());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5: 获取main方法并使用
示例:
- HeroPlus 新增main方法
public static void main(String[] args) {
System.out.println("执行main方法");
}
- 通过下面步骤获取main方法1
package test;
public class MainTest {
public static void main(String[] args) {
try {
//1、获取HeroPlus对象的字节码
Class clazz = Class.forName("pojo.HeroPlus");
//2、获取main方法,第一个参数:方法名称,第二个参数:方法形参的类型,
Method methodMain = clazz.getMethod("main", String[].class);
//3、调用main方法
// methodMain.invoke(null, new String[]{"a","b","c"});
//第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数
//这里拆的时候将 new String[]{"a","b","c"} 拆成3个对象。所以需要将它强转。
methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
// methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二
} catch (Exception e) {
e.printStackTrace();
}
}
}
4 : 关于反射的用法举例
反射非常强大,但是从上面的记录来看,反而觉得还不如直接调用方法来的直接和方便2。
通常来说,需要在学习了Spring 的依赖注入,反转控制之后,才会对反射有更好的理解,所以先这里举两个例子,来演示一下反射的一种实际运用3。
1:通过反射运行配置文件内容
首先准备两个业务类
package service;
public class Service1 {
public void doService1(){
System.out.println("业务方法1");
}
}
package service;
public class Service2 {
public void doService2(){
System.out.println("业务方法2");
}
}
- 当需要从第一个业务方法切换到第二个业务方法的时候,使用非反射方式,必须修改代码,并且重新编译运行,才可以达到效果
package service;
public class CommonTest {
public static void main(String[] args) {
//new Service1().doService1();
//必须重新修改代码
new Service2().doService2();
}
}
- 使用反射方式则方便很多
1 首先准备一个配置文件,就叫做spring.txt吧, 放在src目录下。
里面存放的是类的名称,和要调用的方法名。首先准备一个配置文件,就叫做spring.txt吧, 放在src目录下。里面存放的是类的名称,和要调用的方法名。
2 在测试类Test中,首先取出类名称和方法名,然后通过反射去调用这个方法。
3 当需要从调用第一个业务方法,切换到调用第二个业务方法的时候,不需要修改一行代码,也不需要重新编译,只需要修改配置文件spring.txt,再运行即可。
示例:
spring.txt内容
class=reflection.Service1
method=doService1
测试类
package service;
public class ReflectTest {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) throws Exception {
//从spring.txt中获取类名称和方法名称
File springConfigFile = new File("H:\\eclpise-workspace\\reflect-demo\\src\\spring.txt");
Properties springConfig= new Properties();
springConfig.load(new FileInputStream(springConfigFile));
String className = (String) springConfig.get("class");
String methodName = (String) springConfig.get("method");
//根据类名称获取类对象
Class clazz = Class.forName(className);
//根据方法名称,获取方法对象
Method m = clazz.getMethod(methodName);
//获取构造器
Constructor c = clazz.getConstructor();
//根据构造器,实例化出对象
Object service = c.newInstance();
//调用对象的指定方法
m.invoke(service);
}
}
2:通过反射越过泛型检查
泛型是在编译期间起作用的。在编译后的.class文件中是没有泛型的。所有比如T或者E类型啊,本质都是通过Object处理的。所以可以通过使用反射来越过泛型。
示例:
package test;
public class GenericityTest {
public static void main(String[] args) throws Exception{
ArrayList<String> list = new ArrayList<>();
list.add("this");
list.add("is");
// strList.add(5);报错
/********** 越过泛型检查 **************/
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = list.getClass();
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(list, 5);
//遍历集合
for(Object obj : list){
System.out.println(obj);
}
}
}
GitHub源码:java反射
-
深入分析Java方法反射的实现原理
后记:
本文部分内容引用自csdn的敬业的小码哥和How2jJava,如有侵权,请联系我 ↩︎
文章3
java.lang.reflect.Field.getAnnotation()方法示例 -java.lang.reflect包教程™
获取注解类然后强转成目标类
作者: 初生不惑
如果存在这样的注释,则
java.lang.reflect.Field.getAnnotation(Class <T> annotationClass)
方法返回指定类型的元素的注释,否则返回为null
。声明
以下是
java.lang.reflect.Field.getAnnotation(Class <T> annotationClass)
方法的声明。public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
Java
参数
- annotationClass - 如果给定的注释类为
null
。返回值
- 该元素的注释指定的注释类型,如果存在于此元素,否则返回
null
。异常
- NullPointerException - 如果指定的对象为
null
,该字段为实例字段。例子
以下示例显示
java.lang.reflect.Field.getAnnotation(Class<T> annotationClass)
方法的用法。import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Field; public class GetAnnotation { public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Field field = SampleClass.class.getField("sampleField"); Annotation annotation = field.getAnnotation(CustomAnnotation.class); if(annotation instanceof CustomAnnotation){ CustomAnnotation customAnnotation = (CustomAnnotation) annotation; System.out.println("name: " + customAnnotation.name()); System.out.println("value: " + customAnnotation.value()); } } } @CustomAnnotation(name="SampleClass", value = "Sample Class Annotation") class SampleClass { @CustomAnnotation(name="sampleClassField", value = "Sample Field Annotation") public String sampleField; public String getSampleField() { return sampleField; } public void setSampleField(String sampleField) { this.sampleField = sampleField; } } @Retention(RetentionPolicy.RUNTIME) @interface CustomAnnotation { public String name(); public String value(); }
//原文出自【易百教程】,商业转载请联系作者获得授权,非商业转载请保留原文链接:https://www.yiibai.com/javareflect/javareflect_field_getannotation.html
让我们编译并运行上面的程序,这将产生以下结果 -
name: sampleClassField value: Sample Field Annotation
//原文出自【易百教程】,商业转载请联系作者获得授权,非商业转载请保留原文链接:https://www.yiibai.com/javareflect/javareflect_field_getannotation.html
文章四
package com.xgj.master.ioc.reflect;
public class Car {
private String brand ;
private String color;
private int speed;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
/**
*
* @Title:Car
* @Description:默认构造函数
*/
public Car(){
}
/**
*
* @Title:Car
* @Description:带参构造函数
* @param brand
* @param color
* @param speed
*/
public Car(String brand ,String color ,int speed){
this.brand = brand;
this.color = color;
this.speed = speed;
}
public void introduceCar(){
System.out.println("Car : " + this.brand + " , " + this.color + " , " + this.speed);
}
}
-----------------------------------
package com.xgj.master.ioc.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest {
public static Car initCarByDefaultConstrut() throws Exception {
// (1)通过类装载器获取Car类对象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class claz = loader.loadClass("com.xgj.master.ioc.reflect.Car");
// (2)获取类的默认构造函数,并通过它实例化Car
Constructor constructor = claz.getDeclaredConstructor(null);
Car car = (Car) constructor.newInstance();
// (3)通过反射方法设置属性
Method method = claz.getMethod("setBrand", String.class);
method.invoke(car, "BMW");
Method method2 = claz.getMethod("setColor", String.class);
method2.invoke(car, "black");
Method method3 = claz.getMethod("setSpeed", int.class);
method3.invoke(car, 100);
return car;
}
public static void main(String[] args) throws Exception {
initCarByDefaultConstrut().introduceCar();
}
}
-----------------------------------
©著作权归作者所有:来自51CTO博客作者小小工匠的原创作品,请联系作者获取转载授权,否则将追究法律责任
Java-Java反射
https://blog.51cto.com/u_15239532/5204285