java中的反射机制

反射的概念

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

功能

          Java反射机制主要提供了以下功能:
1. 在运行时判断任意一个对象所属的类;
2. 在运行时构造任意一个类的对象;
3. 在运行时判断任意一个类所具有的成员变量和方法;
4. 在运行时调用任意一个对象的方法;
5. 生成动态代理。

理解反射的概念

反射就是把Java类中的各种成分映射成相应的Java类。

例如:众多的人用一个Person类来表示,那么众多的Java类就用一个Class类来表示。

                       Person 类代表人,它的实例对象就是张三,李四这样一个个具体的人;

           Class类代表Java类,它的各个实例对象对应的就是各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的字节码等等。

Class类用于表示.class文件,是所有加载进内存的字节码对象的父类。所以可以通过Class得到运行时的类。

如何得到某个class文件对应的class对象呢?

                     方法有3种:

1)类名.class 例如,Person.class

2)对象.getClass() 例如,new Data().getClass()。

3)Class.forName("包名.类名"); 例如,Class.forName("java.lang.String");

package com.laobi.day28;

public class ReflectDemo {
	/**
	 * java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法
	 * 对于任意一个对象,都能够调用它的任意一个方法和属性
	 * 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
	 * 
	 * 动态获取类中信息,就是java反射
	 * 可以理解为对类对解剖
	 * 
	 * 要想要对字节码文件进行解剖,必须要有字节码文件对象。
	 * 如何获取字节码文件对象呢?
	 * @throws ClassNotFoundException 
	 * 
	 */
	public static void main(String[] args) throws ClassNotFoundException {
		getClassObject_3();
	}
	
	/*
	 * 方式三:
	 * 只要通过给定的类的字符串名称就可以获取该类,更为扩展
	 * 可是用class类中的方法完成 
	 * 该方法就是forName
	 * 这种方式只要有名称即可,更为方便,扩展性更强。 
	 */
	private static void getClassObject_3() throws ClassNotFoundException {
		String className = "com.laobi.day28.Person";
		Class c = Class.forName(className);
		System.out.println(c);
	}

	/*
	 * 方式二:
	 * 任何数据类型都具备一个静态的属性.class来获取其对应的Class对象
	 * 相对简单,但是还要明确用到类中的静态成员
	 * 还是不够扩展
	 */
	private static void getClassObject_2() {
		Class class1 = Person.class;
		Class class2 = Person.class;
		System.out.println(class1==class2);
		
	}

	/*
	 * 方式一:
	 * 获取字节码对象对方式:
	 * 1、Object类中对getClass方法
	 * 想要用这种方式,必须要明确具体的类,并创建对象。 
	 */  
	public static void getClassObject_1(){
		Person p = new Person();
		Class class1 = p.getClass();
		Person p1 = new Person();
		Class class2 = p1.getClass();
		System.out.println(class1==class2);
	}

}

注意:字节码文件是唯一的,所以无论怎么获取,都是同一份字节码文件。

            九个预定义Class实例对象(八大原始类型+void)

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。

每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该Class 对象。

基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void也表示为 Class 对象。


   反射的基本步骤:

1、获得Class对象,就是获取到指定的名称的字节码文件对象。

2、实例化对象,获得类的属性、方法或构造函数。

3、访问属性、调用方法、调用构造函数创建对象。

package com.laobi.day28;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class ReflectDemo2 {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		createNewObject_2();
	}
	
	private static void createNewObject_2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//		com.laobi.day28.Person p = new com.laobi.day28.Person("旺财",29);
		
		/*
		 * 当获取指定名称对应类中的所体现的对象时, 
		 * 而该对象初始化不使用空参数构造该怎么办呢?
		 * 既然是通过指定的构造函数进行对象的初始化,
		 * 所以应该先获取到该构造函数。通过字节码文件对象即可完成。
		 * 该方法是:getConstructor(paramterTypes);
		 */
		String name = "com.laobi.day28.Person";
		//找寻该名称类文件,并加载进内存,并产生Class对象
		Class class1 = Class.forName(name);
		//获取到了指定到构造函数对象
		Constructor constructor = class1.getConstructor(String.class,int.class);
	    
		//通过该构造器对象的newInstance方法进行对象的初始化
		Object obj = constructor.newInstance("小强",16);
	}

	public static void createNewObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
		
		//早期:new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,并创建该字节码文件对象,并接着创建该字节文件的对应的Person对象。
//		com.laobi.day28.Person p = new com.laobi.day28.Person();
		
		//现在:
		String name = "com.laobi.day28.Person";
		//找寻该名称类文件,并加载进内存,并产生Class对象
		Class class1 = Class.forName(name);
		//如何产生该类的对象呢?
		Object obj = class1.newInstance();
	}

}

构造方法的反射应用(Coustructor类)


Constructor类的实例对象代表类的一个构造方法。

反射公共,私有和保护的构造方法:

反射公共的需要的方法是:getConstructor();

反射私有的需要的方法是:getDeclaredConstructor();

Constructor对象代表一个构造方法,Constructor对象有的方法:得到构造方法名字,得到所属于的类,产生实例对象。


暴力反射

反射里的Constructor,Field,Method三个类都有一个getDeclaredXxx方法,可以不受权限控制的获取类的构造函数,

字段,方法,如果想要私有构造函数创建对象,字段赋值,方法调用的话,会自动的访问类的isAccessable,默认的是false,

所以,要想访问类中的私有成员的时候,就要调用setAccessable方法,将其改为true,

这样,就可以对类中的私有成员进行操作了.

package com.laobi.day28;

import java.lang.reflect.Field;

public class ReflectDemo3 {
	public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		getFieldDemo();
	}

	private static void getFieldDemo() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		Class class1 = Class.forName("com.laobi.day28.Person");
		
		Field field =null;// class1.getField("age");//获取公有的
		
		field = class1.getDeclaredField("age");//只获取本类的,包含私有的
		
		//对私有字段的访问取消权限检查.也称暴力访问
		field.setAccessible(true);
		
		Object obj = class1.newInstance();
		
		field.set(obj,89);
		
		Object o = field.get(obj);
		
		System.out.println(o);
		
	}

}

成员方法的反射(Method类)

Method类代表某个类中的一个成员方法

得到类中的某一个方法:

例子:Method charAt =Class.forName("java.lang.String").getMethod("charAt",int.class);

调用方法:

通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str, 1)); 

如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?

说明该Method象对应的是一个静态方法!

package com.laobi.day28;

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

public class ReflectDemo4 {

	public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		getMethodDemo_3();
	}
	
	public static void getMethodDemo_3() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Class class1 = Class.forName("com.laobi.day28.Person");

		Method method = class1.getMethod("paramMethod",String.class,int.class);// 获取空参数一般方法

		Object obj = class1.newInstance();
		
		method.invoke(obj, "小强",14);
	}

	public static void getMethodDemo_2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Class class1 = Class.forName("com.laobi.day28.Person");
		
		Method method = class1.getMethod("show", null);//获取空参数一般方法
		
//		Object obj = class1.newInstance();
		Constructor constructor = class1.getConstructor(String.class,int.class);
		Object obj = constructor.newInstance("旺财",24);
		
		method.invoke(obj, null);
		
	}

	/*
	 * 获取指定Class中的所以公有方法
	 */

	public static void getMethodDemo() throws ClassNotFoundException {

		Class class1 = Class.forName("com.laobi.day28.Person");
		
		Method[] methods = class1.getMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
	}

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值