Java的反射

                    版权声明:版权声明:本文为博主原创文章,转载请注明出处。                        https://blog.youkuaiyun.com/lililuni/article/details/83449088                    </div>
                                                <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-3019150162.css">
                                    <div id="content_views" class="markdown_views prism-tomorrow-night">
                <!-- flowchart 箭头图标 勿删 -->
                <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                    <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                </svg>
                                        <p>&nbsp;&nbsp;学到spring框架的时候,发现反射思想很重要,故特此写下此文,以加深理解。</p>

1:反射概述

  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
  实际上,我们创建的每一个类也都是对象,即类本身是java.lang.Class类的实例对象。这个实例对象称之为类对象,也就是Class对象。那么,Class对象又是什么对象呢?


2:Class对象特点

  下图是Class类的api(图片来自于Java基础之—反射(非常重要)

在这里插入图片描述
   从图中可以得出以下几点:

  1. Class 类的实例对象表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有很多的实例,每个类都有唯一的Class对象。
  2. Class 类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机自动构造的。也就是说我们不需要创建,JVM已经帮我们创建了。
  3. Class 对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法

3:反射的使用

  假设我们现在有一个Hero类

package pojo;
public class Hero {
	public String name; //姓名
    public float hp; //血量
    public float armor; //护甲
    public int moveSpeed; //移动速度
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1:获取类对象

获取类对象有3种方式

  1. Class.forName()常用
  2. Hero.class
  3. new Hero().getClass()

在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样。(此处准确是在ClassLoader下,只有一个类对象)

示例:

package pojo;
public class ObjectTest {
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    String className <span class="token operator">=</span> <span class="token string">"pogo.Hero"</span><span class="token punctuation">;</span>
	<span class="token keyword">try</span> <span class="token punctuation">{</span>
    	<span class="token comment">//获取类对象的第一种方式</span>
        Class <span class="token class-name">pClass1</span> <span class="token operator">=</span> Class<span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">//获取类对象的第二种方式</span>
        Class <span class="token class-name">pClass2</span> <span class="token operator">=</span> Hero<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">;</span>
        <span class="token comment">//获取类对象的第三种方式</span>
        Class <span class="token class-name">pClass3</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hero</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>pClass1<span class="token operator">==</span>pClass2<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//输出true</span>
        System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>pClass1<span class="token operator">==</span>pClass3<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//输出true</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ClassNotFoundException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// TODO Auto-generated catch block</span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

  三种方式中,常用第一种,第二种需要导入类的包,依赖太强,不导包就抛编译错误。第三种对象都有了还要反射干什么。一般都第一种,一个字符串可以传入也可写在配置文件中等多种方法。


2 利用反射机制创建对象

基本步骤
  与传统的通过new 来获取对象的方式不同反射机制,反射会先拿到Hero的“类对象”,然后通过类对象获取“构造器对象”再通过构造器对象创建一个对象,具体步骤:

1.获取类对象 Class class = Class.forName("pojo.Hero");
2.获取构造器对象 Constructor con = clazz.getConstructor(形参.class);
3 获取对象 Hero hero =con.newInstance(实参);

上面是最简单的获取方法,当Hero的构造方法不是无参构造方法时,获取构造器对象略有不同,见下面测试:

构造方法不同时,获取构造器对象的方法

示例:

  1. Hero类添加6种构造方法
//---------------构造方法-------------------
	//(默认的构造方法)
	Hero(String str){
		System.out.println("(默认)的构造方法 s = " + str);
	}
<span class="token comment">//无参构造方法</span>
<span class="token keyword">public</span> <span class="token function">Hero</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"调用了公有、无参构造方法执行了。。。"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//有一个参数的构造方法</span>
<span class="token keyword">public</span> <span class="token function">Hero</span><span class="token punctuation">(</span><span class="token keyword">char</span> name<span class="token punctuation">)</span><span class="token punctuation">{</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"姓名:"</span> <span class="token operator">+</span> name<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//有多个参数的构造方法</span>
<span class="token keyword">public</span> <span class="token function">Hero</span><span class="token punctuation">(</span>String name <span class="token punctuation">,</span><span class="token keyword">float</span> hp<span class="token punctuation">)</span><span class="token punctuation">{</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"姓名:"</span><span class="token operator">+</span>name<span class="token operator">+</span><span class="token string">"血量:"</span><span class="token operator">+</span> hp<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//受保护的构造方法</span>
<span class="token keyword">protected</span> <span class="token function">Hero</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> n<span class="token punctuation">)</span><span class="token punctuation">{</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"受保护的构造方法 n = "</span> <span class="token operator">+</span> n<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">//私有构造方法</span>
<span class="token keyword">private</span> <span class="token function">Hero</span><span class="token punctuation">(</span><span class="token keyword">float</span> hp<span class="token punctuation">)</span><span class="token punctuation">{</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"私有的构造方法   血量:"</span><span class="token operator">+</span> hp<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  1. 通过反射机制获取对象
package test;
public class ConstructorTest {
<span class="token comment">/*
 * 通过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)
 */</span>

 
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> Exception <span class="token punctuation">{</span>
	<span class="token comment">//1.加载Class对象</span>
	Class <span class="token class-name">clazz</span> <span class="token operator">=</span> Class<span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span><span class="token string">"pojo.Hero"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	
	
	<span class="token comment">//2.获取所有公有构造方法</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"**********************所有公有构造方法*********************************"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	Constructor<span class="token punctuation">[</span><span class="token punctuation">]</span> conArray <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getConstructors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span><span class="token punctuation">(</span>Constructor c <span class="token operator">:</span> conArray<span class="token punctuation">)</span><span class="token punctuation">{</span>
		System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	
	
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"************所有的构造方法(包括:私有、受保护、默认、公有)***************"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	conArray <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getDeclaredConstructors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span><span class="token punctuation">(</span>Constructor c <span class="token operator">:</span> conArray<span class="token punctuation">)</span><span class="token punctuation">{</span>
		System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>c<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"*****************获取公有、无参的构造方法*******************************"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	Constructor con <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getConstructor</span><span class="token punctuation">(</span>null<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">//1&gt;、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型</span>
	<span class="token comment">//2&gt;、返回的是描述这个无参构造函数的类对象。</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"con = "</span> <span class="token operator">+</span> con<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">//调用构造方法</span>
	Object obj <span class="token operator">=</span> con<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	
	
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"******************获取私有构造方法,并调用*******************************"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	con <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getDeclaredConstructor</span><span class="token punctuation">(</span><span class="token keyword">float</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>con<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">//调用构造方法</span>
	con<span class="token punctuation">.</span><span class="token function">setAccessible</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//暴力访问(忽略掉访问修饰符)</span>
	obj <span class="token operator">=</span> con<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

输出:

**********************所有公有构造方法*********************************
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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

总结:

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是对象,不是类对象

示例:

  1. 新增HeroPlus类
package pojo;
public class HeroPlus {
	public String name;
    public float hp;
    public int damage;
    public int id;
<span class="token keyword">public</span> String <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setName</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token function">HeroPlus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
     
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token function">HeroPlus</span><span class="token punctuation">(</span>String string<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    name <span class="token operator">=</span>string<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> String <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">"Hero [name="</span> <span class="token operator">+</span> name <span class="token operator">+</span> <span class="token string">"]"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isDead</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// TODO Auto-generated method stub</span>
    <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">attackHero</span><span class="token punctuation">(</span>HeroPlus h2<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>name<span class="token operator">+</span> <span class="token string">" 正在攻击 "</span> <span class="token operator">+</span> h2<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  1. 获取属性并修改
package test;
public class ParaTest {
	 public static void main(String[] args) {
         HeroPlus h =new HeroPlus();
         //使用传统方式修改name的值为garen
         h.name = "garen";
     <span class="token keyword">try</span> <span class="token punctuation">{</span>
         <span class="token comment">//获取类HeroPlus的名字叫做name的字段</span>
         Field f1<span class="token operator">=</span> h<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getDeclaredField</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token comment">//修改这个字段的值</span>
         f1<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>h<span class="token punctuation">,</span> <span class="token string">"teemo"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
         <span class="token comment">//打印被修改后的值</span>
         System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>h<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
          
     <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
         <span class="token comment">// TODO Auto-generated catch block</span>
         e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token punctuation">}</span>

}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

补充
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 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HeroPlus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 
 <span class="token keyword">try</span> <span class="token punctuation">{</span>
     <span class="token comment">// 获取这个名字叫做setName,参数类型是String的方法</span>
     Method m <span class="token operator">=</span> h<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token string">"setName"</span><span class="token punctuation">,</span> String<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token comment">// 对h对象,调用这个方法</span>
     m<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>h<span class="token punctuation">,</span> <span class="token string">"盖伦"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token comment">// 使用传统的方式,调用getName方法</span>
     System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>h<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

 <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
     <span class="token comment">// TODO Auto-generated catch block</span>
     e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
 <span class="token punctuation">}</span>

}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

5: 获取main方法并使用

示例:

  1. HeroPlus 新增main方法
public static void main(String[] args) {
		System.out.println("执行main方法");
	}

 
  • 1
  • 2
  • 3
  1. 通过下面步骤获取main方法1
package test;
public class MainTest {
	public static void main(String[] args) {
		try {
			//1、获取HeroPlus对象的字节码
			Class clazz = Class.forName("pojo.HeroPlus");
		<span class="token comment">//2、获取main方法,第一个参数:方法名称,第二个参数:方法形参的类型,</span>
		 Method methodMain <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token string">"main"</span><span class="token punctuation">,</span> String<span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token comment">//3、调用main方法</span>
		<span class="token comment">// methodMain.invoke(null, new String[]{"a","b","c"});</span>
		<span class="token comment">//第一个参数,对象类型,因为方法是static静态的,所以为null可以,第二个参数是String数组,这里要注意在jdk1.4时是数组,jdk1.5之后是可变参数</span>
		<span class="token comment">//这里拆的时候将  new String[]{"a","b","c"} 拆成3个对象。所以需要将它强转。</span>
		 methodMain<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>null<span class="token punctuation">,</span> <span class="token punctuation">(</span>Object<span class="token punctuation">)</span><span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">{</span><span class="token string">"a"</span><span class="token punctuation">,</span><span class="token string">"b"</span><span class="token punctuation">,</span><span class="token string">"c"</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//方式一</span>
		<span class="token comment">// methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二</span>
		
	<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	
	
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

4 : 反射的其他用处

  反射非常强大,但是学习了之后,会不知道该如何使用,反而觉得还不如直接调用方法来的直接和方便2

  通常来说,需要在学习了Spring 的依赖注入,反转控制之后,才会对反射有更好的理解,但是刚学到这里的同学,不一定接触了Spring,所以在这里举两个例子,来演示一下反射的一种实际运用。

1:通过反射运行配置文件内容

  1. 首先准备两个业务类
package service;
public class Service1 {
    public void doService1(){
        System.out.println("业务方法1");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
package service;
public class Service2 {
	public void doService2(){
        System.out.println("业务方法2");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 当需要从第一个业务方法切换到第二个业务方法的时候,使用非反射方式,必须修改代码,并且重新编译运行,才可以达到效果
package service;
public class CommonTest {
	  public static void main(String[] args) {
		  //new Service1().doService1();
		  //必须重新修改代码
	        new Service2().doService2();
	    }
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  1. 使用反射方式则方便很多
  1. 首先准备一个配置文件,就叫做spring.txt吧, 放在src目录下。
    里面存放的是类的名称,和要调用的方法名。首先准备一个配置文件,就叫做spring.txt吧, 放在src目录下。里面存放的是类的名称,和要调用的方法名。
  2. 在测试类Test中,首先取出类名称和方法名,然后通过反射去调用这个方法。
  3. 当需要从调用第一个业务方法,切换到调用第二个业务方法的时候,不需要修改一行代码,也不需要重新编译,只需要修改配置文件spring.txt,再运行即可。

示例:
spring.txt内容

class=reflection.Service1
method=doService1

 
  • 1
  • 2

测试类

package service;
public class ReflectTest {
	@SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) throws Exception {
    <span class="token comment">//从spring.txt中获取类名称和方法名称</span>
    File springConfigFile <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">File</span><span class="token punctuation">(</span><span class="token string">"H:\\eclpise-workspace\\reflect-demo\\src\\spring.txt"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Properties springConfig<span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Properties</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    springConfig<span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">FileInputStream</span><span class="token punctuation">(</span>springConfigFile<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    String className <span class="token operator">=</span> <span class="token punctuation">(</span>String<span class="token punctuation">)</span> springConfig<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"class"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    String methodName <span class="token operator">=</span> <span class="token punctuation">(</span>String<span class="token punctuation">)</span> springConfig<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"method"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     
    <span class="token comment">//根据类名称获取类对象</span>
    Class <span class="token class-name">clazz</span> <span class="token operator">=</span> Class<span class="token punctuation">.</span><span class="token function">forName</span><span class="token punctuation">(</span>className<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//根据方法名称,获取方法对象</span>
    Method m <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span>methodName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//获取构造器</span>
    Constructor c <span class="token operator">=</span> clazz<span class="token punctuation">.</span><span class="token function">getConstructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//根据构造器,实例化出对象</span>
    Object service <span class="token operator">=</span> c<span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">//调用对象的指定方法</span>
    m<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>service<span class="token punctuation">)</span><span class="token punctuation">;</span>
     
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

2:通过反射越过泛型检查

  泛型是在编译期间起作用的。在编译后的.class文件中是没有泛型的。所有比如T或者E类型啊,本质都是通过Object处理的。所以可以通过使用反射来越过泛型。

示例:

package test;
public class GenericityTest {
	public static void main(String[] args) throws Exception{
ArrayList<span class="token generics function"><span class="token punctuation">&lt;</span>String<span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token operator">&lt;</span><span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"this"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"is"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">//	strList.add(5);报错</span>

<span class="token comment">/********** 越过泛型检查    **************/</span>

<span class="token comment">//获取ArrayList的Class对象,反向的调用add()方法,添加数据</span>
Class <span class="token class-name">listClass</span> <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> 
<span class="token comment">//获取add()方法</span>
Method m <span class="token operator">=</span> listClass<span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token string">"add"</span><span class="token punctuation">,</span> Object<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//调用add()方法</span>
m<span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>list<span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">//遍历集合</span>
<span class="token keyword">for</span><span class="token punctuation">(</span>Object obj <span class="token operator">:</span> list<span class="token punctuation">)</span><span class="token punctuation">{</span>
	System<span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

反射部分先记录到这。
接下来计划认真理解下spring的依赖注入和反转控制!

GitHub源码:java反射


  1. Java基础之—反射(非常重要) ↩︎

  2. 有什么用
    后记:
      本文部分内容引用自csdn的敬业的小码哥How2jJava,如有侵权,请联系我 ↩︎

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e44c3c0e64.css" rel="stylesheet">
                </div>
### Java反射机制使用教程及常见问题 Java反射机制是一种强大的工具,允许程序在运行时动态地检查和操作类、接口、字段和方法等内部信息[^1]。以下是关于Java反射机制的详细教程以及一些常见的问题。 #### 1. 反射机制的基本概念 Java反射机制是Java语言中一种动态访问、检测和修改自身的能力,主要作用是在运行时获取类的完整结构信息并对其进行操作[^2]。通过反射,可以实现以下功能: - 动态创建对象。 - 动态调用方法。 - 动态访问字段。 - 动态处理注解。 #### 2. 核心类与API Java反射的核心类位于`java.lang.reflect`包中,主要包括以下几类: - `Class`:表示类的运行时类对象,可以通过`Class.forName(String className)`或`Object.getClass()`获取。 - `Field`:表示类的成员变量。 - `Method`:表示类的方法。 - `Constructor`:表示类的构造方法。 #### 3. 使用示例 以下是一个简单的反射机制使用示例,展示了如何通过反射创建对象并调用方法。 ```java import java.lang.reflect.Method; public class ReflectionExample { public static void main(String[] args) throws Exception { // 获取目标类的Class对象 Class<?> cls = Class.forName("com.example.MyClass"); // 创建目标类的实例 Object obj = cls.getDeclaredConstructor().newInstance(); // 获取目标类的方法 Method method = cls.getMethod("myMethod", String.class); // 调用目标类的方法 method.invoke(obj, "Hello Reflection"); } } ``` #### 4. 性能问题 反射机制虽然强大,但在性能上存在一定的开销。例如,在大量调用反射方法时,其性能可能显著低于直接调用[^4]。因此,在实际开发中应权衡使用反射的必要性。 #### 5. 常见问题 - **安全性问题**:反射可以访问私有成员,这可能导致破坏封装性[^1]。 - **性能问题**:反射调用方法的性能比普通方法调用低[^4]。 - **异常处理**:反射操作容易抛出多种异常,如`ClassNotFoundException`、`NoSuchMethodException`等,需要妥善处理。 #### 6. 实际应用场景 Java反射机制在许多实际场景中发挥了重要作用,包括但不限于框架设计、动态代理、依赖注入、测试工具和序列化/反序列化等[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值