Java反射浅谈

    JAVA反射机制(Reflection)是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对J象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制(Reflection)。反射(Reflection)给java提供了,运行时获取一个类实例的可能,这一点非常灵活,你仅仅传一个类的全包名路径,就能通过反射(Reflection),来获取对应的类实例,我们一般会用Class类,来调用这个被反射(Reflection)的Objcet类下的,构造方法,属性,或方法等,反射(Reflection)在一些开源框架里用的非常之多,Spring,Struts,Hibnerate等都有它的影子,下面具体看看反射(Reflection)的有关概念!

一、Java反射(Reflection)的概念。
  反射(Reflection)含义:可以获取正在运行的Java对象。
二、Java反射(Reflection)的功能。
  (1) 可以判断运行时对象所属的类;
  (2) 可以判断运行时对象所具有的成员变量和方法;
  (3) 通过反射(Reflection)甚至可以调用到private的方法;
  (4) 生成动态代理。

    反射(Reflection)虽然很灵活,能够使得写的代码,变的大幅精简,所以在用的时候,一定要注意具体的应用场景,反射(Reflection)的优缺点如下:
优点:
        (1) 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性;
        (2) 与Java动态编译相结合,可以实现无比强大的功能 。
缺点:
      (1) 使用反射(Reflection)的性能较低 ;
      (2) 使用反射(Reflection)相对来说不安全 ;
      (3) 破坏了类的封装性,可以通过反射(Reflection)获取这个类的私有方法和属性 。

了解了反射的基本概念后,接下来,看看Java提供的反射(Reflection) API。

三、Java Reflection API简介。

在JDK中,主要由以下类来实现Java反射机制:
      Class类:代表一个类,位于java.lang包中。
   Field类:代表类的成员变量(成员变量也称为类的属性),位于java.lang.reflect包中。
   Method类:代表类的方法,位于java.lang.reflect包中。
   Constructor类:代表类的构造方法,位于java.lang.reflect包中。
   Array类:提供了动态创建数组,以及访问数组的元素的静态方法,位于java.lang.reflect包中。
   Package:类的包定义,位于java.lang包中。

3.1 获取Class对象。
    要想使用反射,首先需要获得待操作的类所对应的Class对象。
所有类的对象其实都是Class的实例。
    获取Class对象的3种方式:
1.使用Class类的静态方法。( 一般尽量采用这种形式)例如:  

try{
          Class<?>  demo1=Class.forName("com.xinxing.Demo");
        }catch(Exception e){
            e.printStackTrace();
        }
2.使用类的.class语法。如:
 Class<?> demo3=Demo.class;
3.使用对象的getClass()方法。如:
Class<?> demo2=new Demo().getClass();
下面通过代码使用以上3种方式获取一个类的Class对象,代码示例:

(1) 在com.xinxing包中,新建一个Demo类,具体实现如下所示,

package com.xinxing;

public class Demo {
	
	private int id;
	private String name;
	private int age;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

}
(2) 新建一个Hello类,代码具体如下,

public class Hello {
	
	public static void main(String[] args) {
	Class<?> demo1=null;
        Class<?> demo2=null;
        Class<?> demo3=null;
        try{
            demo1=Class.forName("com.xinxing.Demo");
        }catch(Exception e){
            e.printStackTrace();
        }
        demo2=Demo.class;
        demo3=new Demo().getClass();    
    System.out.println("类名称   "+demo1.getName());
}
} 
System.out.println("类名称 "+demo2.getName()); System.out.println("类名称 "+demo3.getName()); }}

 运行结果截图如下, 

3.2 获取对象的属性。获取Class对象的属性常用的有2种,

(1) public Field getField(String name)  throws NoSuchFieldException, SecurityException

(2) public Field getDeclaredField(String name)   throws NoSuchFieldException,  SecurityException

方法(1)和方法(2)的区别是:方法(1)只能获取类的public 字段;方法(2)是可以获取一个类的所有字段。下面分别列举一下,方法(1)和(2)的使用,具体代码如下,Demo类的实现如上所示,其中'id'属性是私有的(private),

(1) 方法1,

public static void main(String[] args) {
		Class<?> demo1=null;
      
        try{
            //一般尽量采用这种形式
            demo1=Class.forName("com.xinxing.Demo");
            Field field=demo1.getField("id");
			System.out.println("field名称   "+field.getName());
        }catch(Exception e){
            e.printStackTrace();
        }
		}
运行截图如下,


可以看出,因为属性‘id’的修饰符是私有的(private),所以通过,getField()方法获取不到私有的(private)属性。

(2) 方法2,

public static void main(String[] args) {
		Class<?> demo1=null;
        try{
            //一般尽量采用这种形式
            demo1=Class.forName("com.xinxing.Demo");
            Field field=demo1.getDeclaredField("id");
			System.out.println("field名称   "+field.getName());
        }catch(Exception e){
            e.printStackTrace();
        }
	}
运行结果截图如下,


可以看出,可以获取到属性名称,所以通过,getDeclaredField()方法是可以获取到私有属性的。

ps:

	public void setAccessible(boolean flag)
                   throws SecurityException
	在java的反射使用中,如果字段是私有的,那么必须要对这个字段设置 Field.setAccessible(true),这样才可以正常使用。
	Field.setAccessible(true) 并不是将方法的访问权限改成了public,而是取消java的权限控制检查。所以即使是public方法,其accessible 。
3.3 获取方法。
(1) 获取类的所有方法,代码如下,
public static void main(String[] args) {
        Class<?> demo1=null;
        try{
            //一般尽量采用这种形式
            demo1=Class.forName("com.xinxing.Demo");
            //返回class对象所对应的类或接口中,所声明的所有方法的数组(包括私有方法)
            Method[] methods = demo1.getDeclaredMethods();
            //遍历输出所有方法声明
            for(Method method : methods)
            {
                System.out.println(method);
            }
            
        }catch(Exception e){
            e.printStackTrace();
        }
    }
运行结果截图如下,

可以看到,Demo类中的所有方法全部都打印出来了。

(2) 获取类的某一个方法,代码如下,

public static void main(String[] args) {
		Class<?> demo1=null;
        try{
            //一般尽量采用这种形式
            demo1=Class.forName("com.xinxing.Demo");
            String fieldName="id";
            String getMethodName="get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); 
            Method method =demo1.getMethod(getMethodName);
	        System.out.println(method);
        }catch(Exception e){
            e.printStackTrace();
        }
	}
运行结果截图如下,


PS:获取没有参数的方法时,getMethod(String name,
                        Class<?>... parameterTypes),第二个参数可以不写;获取有参数的方法时,第二个参数是参数类型,例如‘ getMethod("getId",  int.class )’。

通过set设置值,然后get方法获取值,代码如下,

public static void main(String[] args) {
		Class<?> demo1=null;
		Demo demo=new Demo();
        try{
            //一般尽量采用这种形式
            demo1=Class.forName("com.xinxing.Demo");
            String fieldName="name";
            String getMethodName="set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); 
            Method method =demo1.getMethod(getMethodName,String.class);
            method.setAccessible(true);
            String[] inArgs ={"xinxingdemo"}; 
            method.invoke(demo,inArgs);//调用set方法设置值
            String getMethodName1="get"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1); 
            Method method1 =demo1.getMethod(getMethodName1);
            Object object=(Object)method1.invoke(demo);//调用get方法获取值
	        System.out.println(object);
        }catch(Exception e){
            e.printStackTrace();
        }
	}
运行结果截图如下,



四、总结。

综上所述,常用的返回API:

4.1 获取Class对象的属性:

(1) public Field getField(String name)

   只能获取类的public 字段。
(2) public Field getDeclaredField(String name)
    获取一个类的所有字段。

4.2 getDeclaredMethods(),

返回所有方法

4.3  setAccessible() ,
  如果字段是私有的,那么必须要对这个字段设置 Field.setAccessible(true),这样才可以正常使用。              
   Field.setAccessible(true) 并不是将方法的访问权限改成了public,而是取消java的权限控制检查。所以即使是public方法,其accessible 。

4.4   getMethod(),

获取具体的某一个方法。

4.5     invoke(),

反射调用类的方法,有参数的话,需要参数参数。PS:参数为一个对象数组。

4.6  Constructor<?> cons[]=demo.getConstructors(),
  取得全部的构造函数。

4.7  Class<?> intes[]=demo.getInterfaces()。

 获取所有的接口。

4.8Class<?> temp=demo.getSuperclass(),

 取得父类。

4.9   Class<?> type = field[i].getType(),

属性类型。

4.10 newInstance(),

生成一个对象。   

4.11 getPackage(),

获取包。  

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值