黑马程序员java之反射



 ------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------


反射技术:动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。

反射的好处:大大的增强了程序的扩展性。


反射的基本步骤:

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

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

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


获取这个Class对象,有三种方式:

1:通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。

2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。

3:使用的Class类中的方法,静态的forName方法


  指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。


package cn.itcast_01;

/*
 * 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
 * 
 * Person p = new Person();
 * p.使用
 * 
 * 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
 * Class类:
 * 		成员变量	Field
 * 		构造方法	Constructor
 * 		成员方法	Method
 
 * 一般我们到底使用谁呢?
 * 		A:自己玩	任选一种,第二种比较方便
 * 		B:开发	第三种
 * 			为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。
 */
public class ReflectDemo {
	public static void main(String[] args) throws ClassNotFoundException {
		// 方式1
		Person p = new Person();
		Class c = p.getClass();

		Person p2 = new Person();
		Class c2 = p2.getClass();

		System.out.println(p == p2);// false
		System.out.println(c == c2);// true
		//可以证明,p和p2不是同一个文件对象,却有相同的字节码文件也就是。class文件

		// 方式2
		Class c3 = Person.class;;
		System.out.println(c == c3);//true

		// 方式3
		Class c4 = Class.forName("cn.itcast_01.Person");
		System.out.println(c == c4);//true
		//通过实验可以证明,有三种方式可以获得文件的字节码文件。
	}
}

反射都需要获取字节码文件,获取了字节码文件对象后,最终都需要创建指定类的对象:

获取所有构造器。

    Constructor[] constructors =clazz.getConstructors();//只包含公共的

    constructors =clazz.getDeclaredConstructors();//本类公有,包含私有的

    for(Constructorcon : constructors) {

       System.out.println(con);

    }

我们一般只需要获取一个带参数的构造器。

      Constructorconstructor = clazz.getConstructor(String.class,int.class);

想要对对象进行初始化,使用构造器的方法newInstance();

      Objectobj = constructor.newInstance("zhagnsan",30);

package cn.itcast_02;

import java.lang.reflect.Constructor;

/*
 * 需求:通过反射去获取该构造方法并使用:
 * public Person(String name, int age, String address)
 * 
 * Person p = new Person("林青霞",27,"北京");
 * System.out.println(p);
 */
public class ReflectDemo2 {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件对象
		Class c = Class.forName("cn.itcast_01.Person");

		// 获取带参构造方法对象可以叫构造器
		Constructor con = c.getConstructor(String.class, int.class,
				String.class);

		// 通过带参构造方法对象创建对象
		Object obj = con.newInstance("林青霞", 27, "北京");
		
		System.out.println(obj);
	}
}

package cn.itcast_02;

import java.lang.reflect.Constructor;

/*
 * 需求:通过反射获取私有构造方法并使用
 * private Person(String name){}
 * 
 * Person p = new Person("风清扬");
 * System.out.println(p);
 */
public class ReflectDemo3 {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件对象
		Class c = Class.forName("cn.itcast_01.Person");

		// 获取私有构造方法对象
		// NoSuchMethodException:出现了这个方法异常
		// 原因是一开始我们使用的方法只能获取公共的构造函数,private修饰的需要特殊构造器
		//getDeclaredConstructor可以访问所有构造函数包括私有构造函数
		Constructor con = c.getDeclaredConstructor(String.class);

		// 用该私有构造方法创建对象
		// IllegalAccessException:会出现非法的访问异常。
		// 因为对象私有,我们需要强制访问,这种方式称为暴力访问
		con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
		Object obj = con.newInstance("风清扬");

		System.out.println(obj);
	}
package cn.itcast_03;

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

/*
 * 通过发生获取成员变量并使用
 */
public class ReflectDemo {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件对象
		Class c = Class.forName("cn.itcast_01.Person");

		// 获取所有的成员变量
		// Field[] fields = c.getFields();
		// Field[] fields = c.getDeclaredFields();
		// for (Field field : fields) {
		// System.out.println(field);
		// }

		/*
		 * Person p = new Person(); p.address = "北京"; System.out.println(p);
		 */

		// 通过无参构造方法创建对象
		Constructor con = c.getConstructor();
		Object obj = con.newInstance();

		// 获取单个的成员变量
		// 获取address并对其赋值
		Field addressField = c.getField("address");
		// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
		addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"

		// 获取name并对其赋值访问私有成员变量
		// NoSuchFieldException
		Field nameField = c.getDeclaredField("name");
		// IllegalAccessException
		nameField.setAccessible(true);//暴力访问
		nameField.set(obj, "林青霞");
		System.out.println(obj);

	}
}


获取类中所有的方法

      //获取字节码文件对象

    Class c = Class.forName("cn.itcast_01.Person")

    //获取所有的方法

    // Method[] methods =c.getMethods(); //获取自己的包括父亲的公共方法

    // Method[] methods =c.getDeclaredMethods(); //获取自己的所有的方法

    // for (Method method :methods) {

    //System.out.println(method);

    // }


package cn.itcast_04;

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

public class ReflectDemo {
	public static void main(String[] args) throws Exception {
		// 获取字节码文件对象
		Class c = Class.forName("cn.itcast_01.Person");

		Constructor con = c.getConstructor();
		Object obj = con.newInstance();

		// 获取单个方法并使用
		Method m1 = c.getMethod("show");

		m1.invoke(obj); // 调用obj对象的m1方法
		// 第一个参数表示的方法名,如果有传入参数,表示的是方法的参数的class类型
		Method m2 = c.getMethod("method", String.class);
		m2.invoke(obj, "hello");;

		//获取private成员函数,想要获取私有方法。必须用getDeclearMethod();
		Method m4 = c.getDeclaredMethod("function");
		m4.setAccessible(true);//暴力访问
		m4.invoke(obj);
	}
}

ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?

package cn.itcast.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;


public class ArrayListDemo {
	/*
	 * ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
	 */
	public static void main(String[] args) throws NoSuchMethodException,
			SecurityException, IllegalAccessException,
			IllegalArgumentException, InvocationTargetException {
		// 创建集合对象
		ArrayList<Integer> array = new ArrayList<Integer>();

		// array.add("hello");
		// array.add(10);

		Class c = array.getClass(); // 集合ArrayList的class文件对象
		Method m = c.getMethod("add", Object.class);

		m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello
		m.invoke(array, "world");
		m.invoke(array, "java");

		System.out.println(array);
	}
}

数组的反射。

具有相同维数和元素类型的数组属于同一类型。即具有相同的Class实例对象。

例如:int[] a=new int[]{1,2,3};

         int[] a1=new int[5];

         int[][] a2=new int[4][3];

         String[] s=new String[2];

aa1是相同的维数和元素类型所以他们具有相同的字节码。

而其他的都不相同或因维数不同或因类型不同。

 

代表数据的Class实例对象的getSuperclass()方法返回的是父类的Object类对应的 Class.

所以基本数据类型的一维数组可以被当做Object类型使用,不能当做Object[]数组类型使用。

 非基本类型的一维数组,既可以当做Object类型使用又可以当做Object[]数组类型使用。

从上面例子中,引用到这里可以写成:
Object o1=a;     

Object o2=a1;   

Object o3[]=a2;

Object o4[]=s;

Object o5[]=a 是编译不通过的。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值