java 反射机制详解编程语言

  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

注意:反射是在运行的时候进行的,不是在编译的时候运行的。

反射的功能

Java反射机制主要提供了以下功能

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;生成动态代理。

API简介

在这里先看一下sun为我们提供了那些反射机制中的类:

  — java.lang.Class;        代表一个类

  — java.lang.reflect.Constructor; 代表类的构造方法 

  — java.lang.reflect.Field;        代表类的成员变量(成员变量也称为类的属性)

  — java.lang.reflect.Method;  代表类的方法

  — java.lang.reflect.Array;  提供了动态创建数组,以及访问数组的元素的静态方法

注意:java中无论生成某个类的多少对象, 这些对象都会对应于同一个Class对象。

 

方法介绍

方法关键字

含义

getDeclaredMethods()

获取所有的方法

getReturnType()

获得方法的放回类型

getParameterTypes()

获得方法的传入参数类型

getDeclaredMethod(“方法名”,参数类型.class,……)

获得特定的方法

 

 

构造方法关键字

含义

getDeclaredConstructors()

获取所有的构造方法

getDeclaredConstructor(参数类型.class,……)

获取特定的构造方法

 

 

父类和父接口

含义

getSuperclass()

获取某类的父类

getInterfaces()

获取某类实现的接口

获取Class的三种方式

1)、使用Class类的forName(String className)静态方法。改方法需要传入字符串参数,改字符串参数的值是某个类的全限定类名(必须添加完整的包名)。

Class.forName("java.lang.String");

 

2)、调用某个的class属性来获取该类对应的class对象,如

String.class

 

3)、调用某个对象的getClass方法。

String s = "aa"; 
Class<?> clazz = s.getClass();

生成对象

1)、通过不带参数的构造方法生成对象有两种方法

  a)、先获得Class对象,然后通过该Class对象的newInstance()方法直接生成即可:

  newInstance()方法可以返回一个实例,但是构造方法要是没有参数列表的,它相当于调用某个类的不带参数的构造方法,但是如果在初始化对象的时候要传参数,就要使用Constructor

Class<?> classType = String.class;
Object obj = classType.newInstance();

  b)、先获得Class对象,然后通过该对象获得相应的Constructor对象,再通过该Constructor对象的newInstance()方法生成:

Class<?> classType = object.getClass(); 
Constructor cons = classType.getConstructor(new Class[]{}); 
Object obj = cons.newInstance(new Object[]{});

 

2)、若想通过类的带参数的构造方法生成对象,只能使用下面一种方式:

   Class<?> classType = object.getClass(); 
   Constructor cons = classType.getConstructor(new Class[]{String.class,int.class}); 
   Object obj = cons.newInstance(new Object[]{"hello",3});

 

  例子

public class ReflectTester 
{ 
  
 //方法实现对Customer对象的拷贝操作 
 public Object copy(Object object) throws Exception 
 { 
  Class<?> classType = object.getClass(); 
  /*Constructor cons = classType.getConstructor(new Class[]{}); 
  
  Object obj = cons.newInstance(new Object[]{}); 
  System.out.println(obj); 
  System.out.println("-----------");*/ 
  
  //以上的两行代码等价于下面一行 
  //Object obj2 = classType.newInstance(); 
  Constructor cons2 = classType.getConstructor(new Class[]{String.class, int.class}); 
  Object obj2 = cons2.newInstance(new Object[]{"hello",3}); 
  System.out.println(obj2); 
  
  return null; 
 } 
  
 public static void main(String[] args) throws Exception { 
  ReflectTester test = new ReflectTester(); 
  test.copy(new Customer()); 
 } 
  
} 
class Customer 
{ 
 private Long id; 
  
 private int age; 
  
 private String name; 
  
 public Customer() 
 { 
  
 } 
  
 public Customer(String name,int age) 
 { 
  this.name = name; 
  this.age= age; 
 } 
 public Long getId() { 
  return id; 
 } 
 public void setId(Long id) { 
  this.id = id; 
 } 
 public int getAge() { 
  return age; 
 } 
 public void setAge(int age) { 
  this.age = age; 
 } 
 public String getName() { 
  return name; 
 } 
 public void setName(String name) { 
  this.name = name; 
 } 
  
}

 

  相对复杂的例子

import java.lang.reflect.Constructor; 
import java.lang.reflect.Field; 
import java.lang.reflect.Method; 
public class ReflectTester 
{ 
  
 //方法实现对Customer对象的拷贝操作 
 public Object copy(Object object) throws Exception 
 { 
  Class<?> classType = object.getClass(); 
 
  Object ObjectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{}); 
  
  //获得成员变量 
  
  Field[] fields = classType.getDeclaredFields(); 
  for(Field field : fields) 
  { 
   String name = field.getName(); 
    
   String firstLetter = name.substring(0,1).toUpperCase(); //将属性的首字母转换为大写 
    
   String getMethodName = "get" + firstLetter + name.substring(1); 
    
   String setMethodName = "set" + firstLetter + name.substring(1); 
    
   Method getMethod = classType.getMethod(getMethodName, new Class[]{}); 
    
   Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()}); 
    
   Object value = getMethod.invoke(object, new Object[]{}); 
    
   setMethod.invoke(ObjectCopy, new Object[]{value}); 
    
  } 
  
  
  return ObjectCopy; 
 } 
  
 public static void main(String[] args) throws Exception { 
  Customer customer = new Customer("tom",20); 
  
  customer.setId(1L); 
  
  ReflectTester test = new ReflectTester(); 
  
  Customer cus = (Customer)test.copy(customer); 
  
  System.out.println(cus.getAge()+","+cus.getName()+","+cus.getId()); 
 } 
  
} 
class Customer 
{ 
 private Long id; 
  
 private int age; 
  
 private String name; 
  
 public Customer() 
 { 
  
 } 
  
 public Customer(String name,int age) 
 { 
  this.name = name; 
  this.age= age; 
 } 
 public Long getId() { 
  return id; 
 } 
 public void setId(Long id) { 
  this.id = id; 
 } 
 public int getAge() { 
  return age; 
 } 
 public void setAge(int age) { 
  this.age = age; 
 } 
 public String getName() { 
  return name; 
 } 
 public void setName(String name) { 
  this.name = name; 
 } 
  
}

  注意:Integer.TYPE返回的是int,而Integer.class返回的是Integer类所对应的Class对象。

反射生成多维数组

import java.lang.reflect.Array; 
/** 
 * 
 * 用反射构造一个多维数组 
 * 
 */ 
public class ArrayTester2 { 
 public static void main(String[] args) { 
  int[] dims = new int[]{5,10,15}; 
  
  //newInstance()方法的第二个参数是代表生成数组的维度,所以生成的数组维度为5,10,15,长宽高 
  Object array = Array.newInstance(Integer.TYPE,dims); 
  
  //arrayObj是一个二维的数组 
  Object arrayObj = Array.get(array,3); 
  
  Class<?> classType = arrayObj.getClass().getComponentType(); 
  
  //arrayObj是一个一维的数组 
  arrayObj = Array.get(arrayObj, 5); 
  
  Array.setInt(arrayObj, 10, 37); 
  
  int[][][] arrayCast = (int[][][])array; 
  
  System.out.println(arrayCast[3][5][10]); 
 } 
}

 

反射访问私有(private)的方法

  private 限制的方法没有办法在另外的类中使用,但可以使用反射进行使用。而getMethod()方法只能获取public的方法。如果要使用private的方法就要使用 getDeclaredMethod()方法。

例子1、获取privete方法、

public class PrivateTest { 
 private String sayHello(String name) 
 { 
    return "hello" + name; 
 } 
}
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
public class TestPrivate { 
 public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { 
  PrivateTest p = new PrivateTest(); 
  
  Class<?> classType = p.getClass(); 
  
  Method method = classType.getDeclaredMethod("sayHello", new Class[]{String.class}); 
  
  method.setAccessible(true); //压制java的访问控制检查 
  
  String str = (String)method.invoke(p, new Object[]{"aaa"}); 
  
  System.out.println(str); 
  
 } 
  
}

 

例子2、改变private的属性

public class Private2 { 
 private String name = "zhangsan"; 
  
 public String getName() 
 { 
  return name; 
 } 
}
/** 
 * 
 * 将Private2中的private属性name的值变为李四 
 * 
 */ 
public class TestPrivate2{ 
  
 public static void main(String[] args) throws Exception 
 { 
  Private2 p = new Private2(); 
  
  Class<?> classType = p.getClass(); 
  
  Field field = classType.getDeclaredField("name"); 
  
  field.setAccessible(true); 
  
  field.set(p, "lisi"); 
  
  System.out.println(p.getName()); 
 } 
  
}

 

  致谢:感谢您的阅读!

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/15134.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论