黑马程序员--反射(Java)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一.理解。

1.概述:
应用程序已经写好,后期出现的接口子类无法直接在该应用程序中用new创建对象。
既然子类不确定,可以通过对外提供配置文件的形式,将不确定的信息存储到配置文件中即可。
该应用程序只要之前写好如何读取配置文件信息即可。
如果存储了指定的子类名,就根据具体的名称找该类并进行加载和对象的创建,这些动作都在前期定义软件时写好的。就是在没有类之前就将创建对象的动作完成了。动态的获取指定的类,并使用类中的功能。
(配置文件:把具体实现的子类的名称定义到配置文件中。)


2.反射技术:
其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。


3.好处:反射技术大大提高了程序的扩展性。



二.Class类。

1.Class类:
描述字节码文件的对象。
Class类是Java程序中各个Java类的总称。它是反射的基石,通过Class类来使用反射。
Class类中就包含属性有field(字段)、method(方法)、construction(构造函数)。



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

1)、通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。
例子:
    Person p1 = new Person();
    Class clazz = p1.getClass();
    System.out.println(clazz.getName());//获取类的名字。

2)、任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。不用new对象,但是要使用具体的类。
例子:
    Class clazz = Person.class;

3)、使用的Class类中的方法,静态的forName方法。通过给定的类名来获取字节码文件对象。
例子:
    String className = "Person";//来自配置文件。
    Class clazz = Class.forName(className);//此对象代表Person.class
以上两行代码其实就是完成三个步骤:
                        1,通过给定的类名称,加载对应的字节码文件,并封装成字节码文件对象Class。
                        2,通过new创建给定的类的实例。
                        3,调用该类的构造函数。
第三种方式好处:指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。
这就是反射技术使用的获取字节码文件对象的方式。
通常被反射的类都会提供空参数的构造函数。没有对应的构造函数,会报InstantiationException。如果有提供,但权限不够,会报IllegalAccessException异常。



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

1)、通过newInstance()就可以创建字节码文件对象所表示的类的实例。
调用空参数的构造函数:使用了Class类中的newInstance()方法。
(接上面方式3代码):
Object obj = clazz.newInstance();
System.out.println(obj);

2)、如果被反射的类没有空参数的构造函数:(Constructor类)
(接上面方式3代码):
//获取指定的构造器。获取Person类中两个参数String,int的构造函数。
Constructor cons = clazz.getConstructor(String.class,int.class);
//有了构造器对象后,通过构造器对象来初始化该类对象。
Object obj = cons.newInstance("wangwu",23);


4.获取字段:(Field类)
(代码 GetField.java):

class Person 
{
	private String name;
	private int age;
	Person()
	{
		super();
	}
	Person(String name,int age)
	{
		super();
		this.name=name;
		this.age=age;
	}
	public String toString()
	{
		return name+":"+age;
	}
	public void show(String name,int age)
	{
		System.out.println("show run name="+name+",age="+age);
	}
	public static void staticshow()
	{
		System.out.println("static run name");
	}
}


 

//获取Person对象的成员变量
import java.lang.reflect.*;
class GetField 
{
	public static void main(String[] args) throws Exception
	{
		//通过配置文件获取类名(获取字节码文件对象):
		String className = "Person";
		Class clazz = Class.forName(className);
		
		//获取字段:
		String fieldName = "age";
		//Field field = clazz.getField(fieldName);//获取的是公共字段。
		Field field = clazz.getDeclaredField(fieldName);//获取的是已有的字段。

		//创建指定的类的对象:
		Object obj = clazz.newInstance();
		
		//设置字段:(对其进行值的设置,必须先有对象)
		field.setAccessible(true);//取消权限检查。暴力访问。
		field.set(obj,30);//IllegalAccessException异常:age字段是私有的。
		System.out.println(field.get(obj));
	}
}


5.获取方法:(Method类)
(代码 GetMethod.java):

import java.lang.reflect.*;
class GetMethod 
{
	public static void main(String[] args) throws Exception
	{
		String className = "Person";
		Class clazz = Class.forName(className);
        
		//获取带参数的方法
		/*
		Object obj = clazz.newInstance();
		String methodName = "show";
		Method method = clazz.getMethod(methodName,String.class,int.class);
		method.invoke(obj,"lisi",20);
		*/

		//获取不带参数的静态方法
		String methodName = "staticshow";
		Method method = clazz.getMethod(methodName,null);
		method.invoke(null,null);//第一个null是因为静态,不用new对象。
	}
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值