java反射基本理论和实例
博客专区 > 文文1 的博客 > 博客详情
java反射基本理论和实例
文文1 发表于2年前
java反射基本理论和实例
  • 发表于 2年前
  • 阅读 103
  • 收藏 9
  • 点赞 1
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

摘要: java反射基本理论和实例

一、先看一下反射的概念:

              主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

             反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!

二、反射机制的作用:

              1,反编译:.class-->.java

              2,通过反射机制访问java对象的属性,方法,构造方法等;

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

               java.lang.Class;                

              java.lang.reflect.Constructor; java.lang.reflect.Field;        

              java.lang.reflect.Method;

              java.lang.reflect.Modifier;

四、具体功能实现:

                1、反射机制获取类有三种方法,我们来获取Employee类型

//第一种方式:  
Classc1 = Class.forName("Employee");  

//第二种方式:  
//java中每个类型都有class 属性.  
Classc2 = Employee.class;  
   
//第三种方式:  
//java语言中任何一个java对象都有getClass 方法  
Employeee = new Employee();  
Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)


    2、创建对象:获取类以后我们来创建它的对象,利用newInstance:     

Class c =Class.forName("Employee");  
//创建此Class 对象所表示的类的一个新实例  
Objecto = c.newInstance(); //调用了Employee的无参数构造方法.

    3,获取属性:分为所有的属性和指定的属性:

          a,先看获取所有的属性的写法:

            

//获取整个类  
Class c = Class.forName("java.lang.Integer");  
//获取所有的属性?  
//定义可变长的字符串,用来存储属性  
StringBuffer sb = new StringBuffer();  
//通过追加的方法,将每个属性拼接到此字符串中  
//最外边的public定义  
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");  
//里边的每一个属性  
for(Field field:fs){  
      sb.append("\t");//空格  
      sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
      sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字  
      sb.append(field.getName()+";\n");//属性的名字+回车  
}  
sb.append("}");       
System.out.println(sb);

       b,获取特定的属性,对比着传统的方法来学习:

public static void main(String[] args) throws Exception{  
    /* 
    User u = new User(); 
    u.age = 12; //set 
    System.out.println(u.age); //get 
    */  
              
    //获取类  
    Class c = Class.forName("User");  
    //获取id属性  
    Field idF = c.getDeclaredField("id");  
    //实例化这个类赋给o  
    Object o = c.newInstance();  
    //打破封装  
    idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。  
    //给o对象的id属性赋值"110"  
    idF.set(o, "110"); //set  
    //get  
    System.out.println(idF.get(o));  
}

  4,获取方法,和构造方法,不再详细描述,只来看一下关键字:

getDeclaredMethods() 获取所有的方法
getReturnType() 获得方法的返回类型
getParameterTypes() 获得方法的传入参数类型
getDeclaredMethod("方法名",参数类型.class,……) 获得特定的方法
getDeclaredConstructors() 获取所有的构造方法
getDeclaredConstructor(参数类型.class,……) 获取特定的构造方法
getSuperclass() 获取某类的父类
getInterfaces() 获取某类实现的接口




 这样我们就可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。

五,反射加配置文件,使我们的程序更加灵活:

assembly.load("当前程序集的名称").CreateInstance("当前命名空间名称".要实例化的类名);

这样的好处是很容易的方便我们变换数据库,例如我们将系统的数据库从SQL Server升级到Oracle,那么我们写两份D层,在配置文件的内容改一下,或者加条件选择一下即可,带来了很大的方便。           

         当然了,JAVA中其实也是一样,只不过这里的配置文件为.properties,称作属性文件。通过反射读取里边的内容。这样代码是固定的,但是配置文件的内容我们可以改,这样使我们的代码灵活了很多!

    综上为,JAVA反射的再次学习,灵活的运用它,能够使我们的代码更加灵活,但是它也有它的缺点,就是运用它会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。

下面是引用的一篇文章:

Java反射在我们Java学习的过程中是非常重要的知识点。可能有些同学认为这个学习起来不容易理解,其实就我个人而言还是比较简单,学习起来也比较容易理解。下面我给大家总结一下Java反射学习的要点,同时给出几个比较好的例子。
  1、Java反射的概念
  反射含义:可以获取正在运行的Java对象。
  2、Java反射的功能
  1)可以判断运行时对象所属的类
  2)可以判断运行时对象所具有的成员变量和方法
  3)通过反射甚至可以调用到private的方法
  4)生成动态代理
  3、实现Java反射的类
  1)Class:它表示正在运行的Java应用程序中的类和接口
  2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
  3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
  4)Method:提供关于类或接口中某个方法信息
  注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现
  4、编写Java反射程序的步骤:
  1)必须首先获取一个类的Class对象
  例如:
  Class c1 = Test.class;
  Class c2 = Class.forName(“com.reflection.Test”);
  Class c3 = new Test().getClass();
  2)然后分别调用Class对象中的方法来获取一个类的属性/方法/构造方法的结构
  注意:如果要能够正常的获取类中方法/属性/构造方法应该重点掌握如下的反射类
  Field
  Constructor
  Method
  示例:此程序例子告诉大家如何操作Class/Field/Constructor/Method等与Java反射相关的类

package com.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class TestReflection {
	private String username;
	private String password;
	private int[] age;

	public TestReflection(String username, String password, int[] age) {
		super();
		this.username = username;
		this.password = password;
		this.age = age;
	}

	public TestReflection() {
		username = "李白";
		password = "123";
		age = new int[]{10,11,12};
	}


	public void setUserName(String username) {
		this.username = username;
	}

	private void setPassWord(String password) {
		this.password = password;
	}
	
	

	public static void test01() throws ClassNotFoundException {
		//使用三种方法都可以通过反射来获取类对象Class
		Class c1 = TestReflection.class;
		Class c2 = Class.forName("com.reflection.TestReflection");
		Class c3 = new TestReflection().getClass();
		// 获取指定的包名
		String package01 = c1.getPackage().getName();
		String package02 = c2.getPackage().getName();
		String package03 = c3.getPackage().getName();
		System.out.println("package01 = " + package01);
		System.out.println("package02 = " + package02);
		System.out.println("package03 = " + package03);
		// 获取类的修饰符
		int mod = c1.getModifiers();
		String modifier = Modifier.toString(mod);
		System.out.println("modifier = " + modifier);
		// 获取指定类的完全限定名
		String className = c1.getName();
		System.out.println("className = " + className);
		// 获取指定类的父类
		Class superClazz = c1.getSuperclass();
		String superClazzName = superClazz.getName();
		System.out.println("superClazzName = " + superClazzName);
		// 获取实现的接口
		Class[] interfaces = c1.getInterfaces();
		for (Class t : interfaces) {
		    System.out.println("interfacesName = " + t.getName());
		}
		// 获取指定类的成员变量
		Field[] fields = c1.getDeclaredFields();
		for (Field field : fields) {
		    modifier = Modifier.toString(field.getModifiers()); // 获取每个字段的访问修饰符
		    Class type = field.getType(); // 获取字段的数据类型所对应的Class对象
		    String name = field.getName(); // 获取字段名
		    if (type.isArray()) { // 如果是数组类型则需要特别处理		       
		        Class tt = type.getComponentType(); //getComponentType()方法返回一个Class对象,表示数组的成员类型。如果该类不表示数组类,方法返回null.然后通过getName方法获取数组元素类型
			String arrType = type.getComponentType().getName() + "[]";//arrType 为 int[]
		        System.out.println("" + modifier + " " + arrType + " " + name + ";");
		    } else {
			System.out.println("" + modifier + " " + type + " " + name + ";");
			}
		}
		// 获取类的构造方法
		Constructor[] constructors = c1.getDeclaredConstructors();
		for (Constructor constructor : constructors) {
		    String name = constructor.getName(); // 构造方法名
		    modifier = Modifier.toString(constructor.getModifiers()); // 获取访问修饰符
		    System.out.println("" + modifier + " " + name + "(");
		    Class[] paramTypes = constructor.getParameterTypes(); // 获取构造方法中的参数
		    for (int i = 0; i < paramTypes.length; i++) {
			if (i > 0) {
			    System.out.print(",");
			}
			if (paramTypes[i].isArray()) {
			    System.out.println(paramTypes[i].getComponentType().getName() + "[]");
			} else {
			    System.out.print(paramTypes[i].getName());
			}
		    }
		    System.out.println(");");
		}
		// 获取成员方法
		Method[] methods = c1.getDeclaredMethods();
		for (Method method : methods) {
		modifier = Modifier.toString(method.getModifiers());
		Class returnType = method.getReturnType(); // 获取方法的返回类型
		if (returnType.isArray()) {
		    String arrType = returnType.getComponentType().getName() + "[]";
		    System.out.print("" + modifier + " " + arrType + " " + method.getName() + "(");
		} else {
		    System.out.print("" + modifier + " " + returnType.getName() + " " + method.getName() + "(");
		}
			Class[] paramTypes = method.getParameterTypes();
			for (int i = 0; i < paramTypes.length; i++) {
				if (i > 0) {
					System.out.print(",");
				}
				if (paramTypes[i].isArray()) {
					System.out.println(paramTypes[i].getComponentType()
							.getName() + "[]");
				} else {
					System.out.print(paramTypes[i].getName());
				}
			}
			System.out.println(");");
		}
	}

	public static void test02() throws InstantiationException,
			IllegalAccessException, SecurityException, NoSuchMethodException,
			IllegalArgumentException, InvocationTargetException {
		// 反射调用方法,可以通过Method类的invoke方法实现动态方法的调用
		// public Object invoke(Object obj, Object... args)
		//该方法中有多个参数:method.invoke(o, new Object[] {参数1,参数2...});
		// 第一个参数代表对象
		// 第二个参数代表执行方法上的参数
		// 若反射要调用类的某个私有方法,可以在这个私有方法对应的Mehtod对象上先调用setAccessible(true)
		Class c1 = TestReflection.class;
		TestReflection t1 = (TestReflection) c1.newInstance(); // 利用反射调用无参的构造方法来创建类的对象
		System.out.println("username == " + t1.username);
		System.out.println("password == " + t1.password);
		//获得名称setUserName的方法public void com.reflection.TestReflection.setUserName(java.lang.String),参数为String类型
		Method method = c1.getDeclaredMethod("setUserName", String.class);
		method.invoke(t1, "Java反射的学习");//传入参数为字符串("Java反射的学习"),来调用类中的setUserName方法,此时已经改变实例t1的username的属性值
		System.out.println("username == " + t1.username);
		//调用私有方法private void com.reflection.TestReflection.setPassWord(java.lang.String),参数为String类型
		method = c1.getDeclaredMethod("setPassWord", String.class);
		//设置对私有方法的可操作权限
		method.setAccessible(true);
		method.invoke(t1, "反射执行某个Private修饰的方法");
		System.out.println("password == " + t1.password);
	}

	public static void main(String[] args) throws ClassNotFoundException,
		SecurityException, IllegalArgumentException,
		InstantiationException, IllegalAccessException,
		NoSuchMethodException, InvocationTargetException {
//		test01();
		test02();
	}
}

class  Sum{
     public   static   void  main(String[] args)  {
	      int vec[] = new int[]{1, 5, 3};  // 第一种方法          
	      int vec1[]  = {37,47,23} ;   // 第二种方法  
	      int vec2[] = new int [3];//指定数组的元素个数
	      for(int i=0;i<3;i++){
	    	  vec[i]=i+1;           //第三种方法
	      }
	  }  
}

再给与个实例:

package org.cqut.java.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class CopyObject {

	public Object copyObject(Object object) throws Exception {

		// 1.获取待操作类的一个Class对象
		Class<?> classType = object.getClass();

		// 2.获取待操作类的一个实例
		Constructor<?> constructor = classType
				.getConstructor(new Class<?>[] {});
		Object copyObj = constructor.newInstance(new Object[] {});

		// 3.获取被拷贝类的成员变量
		Field[] fields = classType.getDeclaredFields();

		for (Field field : fields) {
			// 4.遍历数组获取各个成员变量名字
			String name = field.getName();// 获取成员变量名字;

			// 5.操作字符串获取成员变量的set和get方法名字;
			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 seMethod = classType.getMethod(setMethodName,
					new Class<?>[] { field.getType() });
			
			/*最开始认为以下两个invoke方法的第一和参数都应该调用copyObj,
			 * 但是最终的结果为输出为默认的空值。
			 * copyObj:程序前面通过Constructor类的newInstance方法
			 * 获取待操作类的一个实例;
			//Object value = getMethod.invoke(copyObj, new Object[] {});
			//seMethod.invoke(copyObj, new Object[] { value });

			/*现在改用如下方式了,输出就正常了
			 * 所以产生疑惑:为什么第一个方法调用的object对象而不是copyObj呢?
			 * 
			 */
			Object value = getMethod.invoke(object, new Object[] {});
			seMethod.invoke(copyObj, new Object[] { value });
		}

		return copyObj;
	}

	public static void main(String[] args) throws Exception {

		Student student = new Student("Tom", 21);
		student.setId(111030805);
		CopyObject copy = new CopyObject();
		Student student2 = (Student) copy.copyObject(student);
		System.out.println(student2.getId() + " " + student2.getName() + " "
				+ student2.getAge());
	}
}

// 一个被反射的JavaBean
class Student {

	private long id;
	private String name;
	private int age;

	public Student() {

	}

	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}

	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;
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

}

    对于利用object给copyObj赋值的invoke的解惑:

Object value = getMethod.invoke(object, new Object[] {});
seMethod.invoke(copyObj, new Object[] { value });

这两句代码的作用如下,

第一句,获取object中的值。
第二句,将该值设置到copyObj中。

这样才能完成赋值。
如果按你所说
//Object value = getMethod.invoke(copyObj, new Object[] {});
            //seMethod.invoke(copyObj, new Object[] { value });

那就是讲从copyObj获取的值,赋值给copyObj,这样做根本毫无意义。


 for (Field field : fields) {
            String name = field.getName();
 
            field.setAccessible(true);
            Object value =  field.get(object);
            field.set(copyObj, value);
}
for循环里这样写,就成功的将object中的值赋值到了copyObj中。


共有 人打赏支持
粉丝 13
博文 239
码字总数 96213
×
文文1
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: