`
kavy
  • 浏览: 890639 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java反射

 
阅读更多

java的反射可以绕过访问权限,访问到类的非公有方法和成员。可能这点会引起安全性的讨论。反射的使用帮助解决很多复杂的问题,其运行时的类型检查,动态调用,代理的实现等,反射为我们写程序带来了很大的灵活性,很多功能都是基于反射。

利用反射还可以访问内部类、匿名内部类的私有属性。

 

 

 

下面提供一种利用安全管理器及反射访问类非公有方法和成员的方法。

 

 

 

 

Java 运行时依靠一种安全性管理器来检验调用代码对某一特定的访问而言是否有足够的权限。具体来说,安全性管理器是 java.lang.SecurityManager 类或扩展自该类的一个类,且它在运行时检查某些应用程序操作的权限。换句话说,所有的对象访问在执行自身逻辑之前都必须委派给安全管理器,当访问受到安全性管理器的控制,应用程序就只能执行那些由相关安全策略特别准许的操作。因此安全管理器一旦启动可以为代码提供足够的保护。默认情况下,安全性管理器是没有被设置的,除非代码明确地安装一个默认的或定制的安全管理器,否则运行时的访问控制检查并不起作用。我们可以通过这一点在运行时避开 Java 的访问控制检查,达到我们访问非公有成员变量或方法的目的。为能访问我们需要的非公有成员,我们还需要使用 Java 反射技术。Java 反射是一种强大的工具,它使我们可以在运行时装配代码,而无需在对象之间进行源代码链接,从而使代码更具灵活性。在编译时,Java 编译程序保证了私有成员的私有特性,从而一个类的私有方法和私有成员变量不能被其他类静态引用。然而,通过 Java 反射机制使得我们可以在运行时查询以及访问变量和方法。由于反射是动态的,因此编译时的检查就不再起作用了。

下面的代码演示了如何利用安全性管理器与反射机制访问私有变量。

// 获得指定变量的值
public static Object getValue(Object instance, String fieldName) throws IllegalAccessException, NoSuchFieldException {
Field field = getField(instance.getClass(), fieldName);
// 参数值为true,禁用访问控制检查
field.setAccessible(true);
return field.get(instance);
}
// 该方法实现根据变量名获得该变量的值
public static Field getField(Class thisClass, String fieldName) throws NoSuchFieldException {
if (thisClass == null) {
   throw new NoSuchFieldException("Error field !");
}
}
 
 

其中 getField(instance.getClass(), fieldName) 通过反射机制获得对象属性,使用set方法可以重新设置变量的值,如field.set(instance, newValue); 。如果存在安全管理器,方法首先使用 this Member.DECLARED 作为参数调用安全管理器的 checkMemberAccess 方法,这里的 this this 类或者成员被确定的父类。 如果该类在包中,那么方法还使用包名作为参数调用安全管理器的 checkPackageAccess 方法。 每一次调用都可能导致 SecurityException。当访问被拒绝时,这两种调用方式都会产生 securityexception 异常

setAccessible(true) 方法通过指定参数值为 true 来禁用访问控制检查,从而使得该变量可以被其他类调用。我们可以在我们所写的类中,扩展一个普通的基本类 java.lang.reflect.AccessibleObject 类。这个类定义了一种 setAccessible 方法,使我们能够启动或关闭对这些类中其中一个类的实例的接入检测。这种方法的问题在于如果使用了安全性管理器,它将检测正在关闭接入检测的代码是否允许这样做。如果未经允许,安全性管理器抛出一个例外。

除访问私有变量,我们也可以通过这个方法访问私有方法。

public static Method getMethod(Object instance, String methodName, Class[] classTypes) throws NoSuchMethodException {
Method accessMethod = getMethod(instance.getClass(), methodName, classTypes);
// 参数值为true,禁用访问控制检查
accessMethod.setAccessible(true);
return accessMethod;
}
private static Method getMethod(Class thisClass, String methodName, Class[] classTypes) throws NoSuchMethodException {
if (thisClass == null) {
   throw new NoSuchMethodException("Error method !");
}
try {
   return thisClass.getDeclaredMethod(methodName, classTypes);
} catch (NoSuchMethodException e) {
   return getMethod(thisClass.getSuperclass(), methodName, classTypes);
}
}
 
 

获得私有方法的原理与获得私有变量的方法相同。当我们得到了函数后,需要对它进行调用,这时我们需要通过 invoke() 方法来执行对该函数的调用,代码示例如下:

public static Object invokeMethod(Object instance, String methodName, Object arg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Object[] args = new Object[1];
args[0] = arg;
return invokeMethod(instance, methodName, args);
}
// 调用含多个参数的方法
public static Object invokeMethod(Object instance, String methodName, Object[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
Class[] classTypes = null;
if (args != null) {
   classTypes = new Class[args.length];
   for (int i = 0; i < args.length; i++) {
    if (args[i] != null) {
     classTypes[i] = args[i].getClass();
    }
   }
}
return getMethod(instance, methodName, classTypes).invoke(instance, args);
}
 
 

利用安全管理器及反射,可以在不修改源码的基础上访问私有成员,为测试带来了极大的方便。尤其是在编译期间,该方法可以顺利地通过编译。但同时该方法也有一些缺点。第一个是性能问题,用于字段和方法接入时反射要远慢于直接代码。第二个是权限问题,有些涉及 Java 安全的程序代码并没有修改安全管理器的权限,此时本方法失效。

 

 

常见问题:

 

 

java反射调用静态方法

 

Class c;
c = Class.forName("class name");
Method m = c.getMethod("method name", new Class[] { int.class, int.class, int.class, int.class });
m.invoke(c, new Object[] { 1, 2, 3, 4 });
 
 

 

利用反射取得泛型信息

 

一、传统通过反射取得函数的参数和返回值

import java.lang.reflect.Method;

public class Foo {
public static void main(String[] args) throws Exception {
   Method[] methods = Foo.class.getDeclaredMethods();
   for (Method method : methods) {
    Class[] paramTypeList = method.getParameterTypes();

    Class returnType = method.getReturnType();
    System.out.println(returnType);
    for (Class clazz : paramTypeList) {
     System.out.println(clazz);
    }
    System.out.println();
   }
}

public static String test1(String str) {
   return null;
}

public static Integer test2(String str, Integer i) {
   return null;
}

}

 
 
二、在有泛型的时候,取得参数和返回值的集合类的泛型信息

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.List;

public class Foo {
public static void main(String[] args) throws Exception {
   Method[] methods = Foo.class.getDeclaredMethods();
   for (Method method : methods) {
    System.out.println(" returnType: ");
    Type returnType = method.getGenericReturnType();
    if (returnType instanceof ParameterizedType) {
     Type[] types = ((ParameterizedType) returnType).getActualTypeArguments();
     for (Type type : types) {
      System.out.println(type);
     }
    }
    System.out.println(" paramTypeType: ");
    Type[] paramTypeList = method.getGenericParameterTypes();
    for (Type paramType : paramTypeList) {
     if (paramType instanceof ParameterizedType) {
      Type[] types = ((ParameterizedType) paramType).getActualTypeArguments();
      for (Type type : types) {
       System.out.println(type);
      }
     }
    }
   }
}

public static List<String> test3(List<Integer> list) {
   return null;
}

private static Map<String, Double> test4(Map<String, Object> map) {
   return null;
}

}

准备一个演示类

 

 

Java代码 复制代码 收藏代码
  1. package my;   
  2. public class Data {   
  3.     private static int data;   
  4.     private String name;   
  5.     private Data(){   
  6.            
  7.     }   
  8.     private Data(int data,String name){   
  9.         this.data = data;   
  10.         this.name = name;   
  11.     }   
  12.     private void showName(){   
  13.         System.out.println("Name is:"+name);   
  14.     }   
  15.     private static void showData(){   
  16.         System.out.println("Data is:"+getData());   
  17.     }   
  18.     private static int getData(){   
  19.         return data;   
  20.     }   
  21.     private void setData(int data){   
  22.         this.data = data;   
  23.     }   
  24.     private void setString(String name){   
  25.         this.name = name;   
  26.     }   
  27. }  
package my;
public class Data {
	private static int data;
	private String name;
	private Data(){
		
	}
	private Data(int data,String name){
		this.data = data;
		this.name = name;
	}
	private void showName(){
		System.out.println("Name is:"+name);
	}
	private static void showData(){
		System.out.println("Data is:"+getData());
	}
	private static int getData(){
		return data;
	}
	private void setData(int data){
		this.data = data;
	}
	private void setString(String name){
		this.name = name;
	}
}

 

2.具体访问步骤

 

 

Java代码 复制代码 收藏代码
  1. package my;   
  2. import java.lang.reflect.Constructor;   
  3. import java.lang.reflect.Field;   
  4. import java.lang.reflect.InvocationTargetException;   
  5. import java.lang.reflect.Method;   
  6. public class Start {   
  7.     public static void main(String[] args) {   
  8.         try {   
  9.             Class dataType = Class.forName("my.Data");   
  10.             // 访问私用的构造方法来创建对象实例   
  11.             Constructor constructor = dataType   
  12.                     .getDeclaredConstructor(new Class[] { int.class,   
  13.                             String.class });   
  14.             constructor.setAccessible(true);//访问私有成员方法,这句很关键   
  15.             Data data = (Data) constructor.newInstance(new Object[] {   
  16.                     new Integer(50), new String("hello") });   
  17.             // 开始访问私有的静态方法showData来打印对象信息   
  18.             Method showDataMethod = dataType.getDeclaredMethod("showData",   
  19.                     new Class[] {});   
  20.             showDataMethod.setAccessible(true);   
  21.             showDataMethod.invoke(nullnew Object[] {});//output:Data is:50   
  22.                
  23.             //开始访问私有方法showName来打印对象信息   
  24.             Method showNameMethod = dataType.getDeclaredMethod("showName",   
  25.                     new Class[] {});   
  26.             showNameMethod.setAccessible(true);   
  27.             showNameMethod.invoke(data, new Object[] {});//output:Name is:hello   
  28.             // 开始访问的setData方法来更改对象信息   
  29.             Method setDataMethod = dataType.getDeclaredMethod("setData",   
  30.                     new Class[] { int.class });   
  31.             setDataMethod.setAccessible(true);   
  32.             setDataMethod.invoke(data, new Object[]{new Integer(100)});//设置data域 为100   
  33.                
  34.             //开始访问静态私有的成员变量   
  35.             Field dataField = dataType.getDeclaredField("data");   
  36.             dataField.setAccessible(true);   
  37.             System.out.println(dataField.getInt(data));//output:100   
  38.             dataField.setInt(null200);//再次修改私有成员data的值   
  39.             System.out.println(dataField.getInt(data));//output:200   
  40.                
  41.             //开始访问私有成员变量   
  42.             Field nameField = dataType.getDeclaredField("name");   
  43.             nameField.setAccessible(true);   
  44.             nameField.set(data,new String("Fuck!"));//修改私有变量name的值   
  45.             showNameMethod.invoke(data, new Object[] {});//Name is:Fuck!   
  46.                
  47.         } catch (ClassNotFoundException e) {   
  48.             e.printStackTrace();   
  49.         } catch (SecurityException e) {   
  50.             e.printStackTrace();   
  51.         } catch (NoSuchMethodException e) {   
  52.             e.printStackTrace();   
  53.         } catch (IllegalArgumentException e) {   
  54.             e.printStackTrace();   
  55.         } catch (InstantiationException e) {   
  56.             e.printStackTrace();   
  57.         } catch (IllegalAccessException e) {   
  58.             e.printStackTrace();   
  59.         } catch (InvocationTargetException e) {   
  60.             e.printStackTrace();   
  61.         } catch (NoSuchFieldException e) {   
  62.             e.printStackTrace();   
  63.         }   
  64.     }   
  65. }  
package my;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Start {
	public static void main(String[] args) {
		try {
			Class dataType = Class.forName("my.Data");
			// 访问私用的构造方法来创建对象实例
			Constructor constructor = dataType
					.getDeclaredConstructor(new Class[] { int.class,
							String.class });
			constructor.setAccessible(true);//访问私有成员方法,这句很关键
			Data data = (Data) constructor.newInstance(new Object[] {
					new Integer(50), new String("hello") });
			// 开始访问私有的静态方法showData来打印对象信息
			Method showDataMethod = dataType.getDeclaredMethod("showData",
					new Class[] {});
			showDataMethod.setAccessible(true);
			showDataMethod.invoke(null, new Object[] {});//output:Data is:50
			
			//开始访问私有方法showName来打印对象信息
			Method showNameMethod = dataType.getDeclaredMethod("showName",
					new Class[] {});
			showNameMethod.setAccessible(true);
			showNameMethod.invoke(data, new Object[] {});//output:Name is:hello
			// 开始访问的setData方法来更改对象信息
			Method setDataMethod = dataType.getDeclaredMethod("setData",
					new Class[] { int.class });
			setDataMethod.setAccessible(true);
			setDataMethod.invoke(data, new Object[]{new Integer(100)});//设置data域 为100
			
			//开始访问静态私有的成员变量
			Field dataField = dataType.getDeclaredField("data");
			dataField.setAccessible(true);
			System.out.println(dataField.getInt(data));//output:100
			dataField.setInt(null, 200);//再次修改私有成员data的值
			System.out.println(dataField.getInt(data));//output:200
			
			//开始访问私有成员变量
			Field nameField = dataType.getDeclaredField("name");
			nameField.setAccessible(true);
			nameField.set(data,new String("Fuck!"));//修改私有变量name的值
			showNameMethod.invoke(data, new Object[] {});//Name is:Fuck!
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
	}
}

 

 

 

 

 

 

 

import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public interface MyInterface {
  ConcurrentMap<String, String> map=new ConcurrentHashMap<String, String>();
}

class MyImpl implements MyInterface{
 private MyImpl(){
  map.put("f", "dgd");
  map.put("c", "nia");
 }
 
 public void PrintMap(){
  Iterator it=map.keySet().iterator();
  while(it.hasNext()){
   String ss=(String)it.next();
   System.out.println(ss+":"+map.get(ss));
  }
 }
}

 

 

public static void main(String[] args) throws Exception {
  Class dataType = Class.forName("com.jensen.study.reflection.MyImpl");
  Constructor constructor = dataType
    .getDeclaredConstructor(new Class[] { });
  constructor.setAccessible(true);// 访问私有成员方法,这句很关键
  MyImpl data = (MyImpl) constructor.newInstance(new Object[] {
     });
  
  Field mapField = dataType.getInterfaces()[0].getDeclaredField("map");
  mapField.setAccessible(true);
  ConcurrentMap<String, String> map=null;
  
  map=(ConcurrentMap<String, String>)mapField.get(new Object());
  
  Iterator it=map.keySet().iterator();
  System.out.println("---------------------");
  while(it.hasNext()){
   String ss=(String)it.next();
   System.out.println(ss+":"+map.get(ss));
  }
  System.out.println("---------------------");
   map.put("haha", "dafkasdfjkas");
  
  
  
   Method setDataMethod = dataType.getDeclaredMethod("PrintMap",
     new Class[] {  });
   setDataMethod.setAccessible(true);
   setDataMethod.invoke(data, new Object[] {});// 设置data域
            
  
  
  

分享到:
评论

相关推荐

    java反射 java反射 java反射java反射

    Java反射是Java编程语言中的一个重要特性,它允许程序在运行时动态地获取类的信息并操作类的对象。在Java中,反射机制提供了强大的能力,包括在运行时检查类的结构、创建对象实例、调用方法以及访问和修改字段值。...

    java反射,获取所有属性、方法以及List集合类

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建对象、获取类...

    JAVA反射机制的入门代码

    Java反射机制是Java编程语言中的一个强大特性,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。这个特性使得Java具有了高度的灵活性和动态性,尤其是在处理元数据、创建对象、调用私有方法...

    JAVA 反射机制应用

    Java反射机制是Java语言提供的一种强大功能,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射机制的核心类是java.lang.Class,它代表了运行时的类信息。通过Class对象,我们...

    java 反射得到某个方法

    在本文中,我们将深入探讨如何使用Java反射来获取并执行某个特定的方法。 首先,我们需要了解Java反射的基本概念。`java.lang.Class`类是反射的核心,它代表了Java中的每一个类。我们可以通过以下方式获取到一个...

    Java反射性能测试分析

    ### Java反射性能测试分析 #### 引言 Java反射机制是Java编程语言中一个强大的特性,它允许程序在运行时动态地访问、检测和修改类、接口、字段和方法等对象。然而,反射操作通常会引入额外的开销,这在性能敏感的...

    Java反射机制总结

    ### Java反射机制总结 #### 反射的概念与起源 反射的概念最早由Smith于1982年提出,指的是程序能够访问、检测并修改其自身状态或行为的能力。这一概念的提出迅速引起了计算机科学领域的广泛关注,并在之后的研究中...

    Java反射经典实例

    Java反射是Java编程语言中的一个强大特性,它允许运行时的程序访问并操作类、接口、字段和方法等信息,即使这些信息在编译时并未明确知晓。在Java中,反射通常通过`java.lang.Class`类和相关的API来实现。本实例将...

    java反射-英文版反射规范

    ### Java反射机制详解 #### 一、概述 Java反射机制是一种强大的编程技术,它允许运行时检查类的信息并操作对象的内部结构。本篇将基于Sun公司的官方文档《Java™ Core Reflection API and Specification》(1997年...

    反射实例-JAVA反射机制

    ### 反射实例—JAVA反射机制 #### 一、反射概念及原理 反射在计算机科学领域,特别是程序设计中,是指程序有能力访问、检测和修改其自身的结构和行为。这一概念最早由Smith于1982年提出,并迅速应用于各种编程语言...

    java反射.pdf

    ### Java反射机制详解 #### 一、什么是Java反射? Java反射是Java编程语言的一个特性,它允许运行时检查和操作程序结构(类、字段、方法等)。反射的主要用途包括但不限于:动态实例化对象、访问私有成员、调用...

    java 反射 调用私有方法(有参数私有方法)获取私有属性值

    Java反射是Java语言提供的一种强大的动态类型特性,它允许程序在运行时检查类、接口、字段和方法的信息,并且能够动态地创建对象和调用方法。这个能力使得开发者可以突破静态类型的束缚,实现一些在编译时期无法完成...

    java反射源代码

    Java反射是Java编程语言中的一个强大特性,它允许在运行时检查类、接口、字段和方法的信息,并且能够在运行时动态地创建对象和调用方法。这个特性使得Java具有高度的灵活性,尤其在处理框架、插件系统以及元数据驱动...

    java 反射机制例子

    ### Java反射机制详解 #### 一、反射的基本概念与历史背景 反射的概念最早由Smith在1982年提出,其核心思想是程序有能力访问、检测甚至修改自身的状态和行为。这种能力一经提出,迅速成为了计算机科学领域的研究...

    java 反射 报错 no such method exception

    ### Java反射机制与NoSuchMethodException详解 在Java编程中,反射是一种强大的机制,允许程序在运行时检查和修改自身结构和行为。然而,当开发者尝试使用反射调用一个不存在的方法时,便会遇到`java.lang....

    java反射获取所有属性,获取所有get方法,包括子类父类

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在Java中,反射主要用于在运行时分析类和对象,包括访问私有成员、调用私有方法、创建动态代理等。...

    利用java反射将json字符串转成对象.zip

    Java反射是Java编程语言中的一个强大工具,它允许运行中的Java程序对自身进行检查并且可以直接操作程序的内部属性。在给定的“利用java反射将json字符串转成对象”的主题中,我们将深入探讨如何借助反射机制将JSON...

    Java反射机制Demo

    ### Java反射机制详解 #### 一、什么是Java反射机制? Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的...

    北大青鸟java反射机制

    Java反射机制是Java编程语言中的一个强大工具,它允许程序在运行时检查并操作类、接口、字段和方法等对象。在"北大青鸟java反射机制"的学习资料中,我们将会深入探讨这一核心特性。 首先,我们要理解反射的核心概念...

Global site tag (gtag.js) - Google Analytics