java高新技术:反射


java反射技术:

 * JAVA反射机制是在运行状态中,对于任意一个类(class),都能够知道这个类的所有属性和方法
 * 对于任意一个对象,都能调用他的任意一个方法和属性
 * 这种动态获取的信息以及动态调用对象的方法功能成为java语言的反射机制
 * 
 * 
 * 动态获取类中信息,就是反射机制
 * 可以理解为对类的解剖
 * 
 * 要相对字节码进行解剖,必须要哟字节码文件对象


获取字节码的三种方法:
<strong>	</strong>/*
	 * 第一种获取字节码的方法
	 * */
	public static void getClassObject_1()
	{
		Person p = new Person();
		Class clazz = p.getClass();
		
		Person p1 = new Person();
		Class clazz1 = p1.getClass();
		
		System.out.println(clazz1==clazz);
	}
	
	/*
	 * 第二种
	 *任何数据类型都具备一个静态属性,class获取对应的class对象 
	 *相对简单,但是还是要明确用到类中的静态成员,不够扩展
	 * */
	public static void getClassObject_2()
	{
		Class clazz = Person.class;
		
		Class clazz1 = Person.class;
		
		System.out.println(clazz==clazz1);
		
		
	}
	/*
	 * 第三种
	 * 只要通过给定的类的字符串名称就可以获取该类,更为扩展
	 * 可以通过Class类中的方法来完成
	 *	forName();
	 * 这种方式只要有名称即可,扩展性更强
	 * */
	public static void getClassObject_3() throws Exception
	{
		String className = "FanShe.Person";		//类名必须要加包名,就算导包了也要加
		Class clazz = Class.forName(className);
	}

反射的用法:

1、需要获得java类的各个组成部分,首先需要获得类的Class对象,获得Class对象的三种方式:

       Class.forName(classname)   用于做类加载

       obj.getClass()                       用于获得对象的类型

       类名.class                        用于获得指定的类型,传参用

 

2、反射类的成员方法:

       Class clazz =Person.class;

       Method method =clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});

       method.invoke();

      

3、反射类的构造函数:

       Constructor con =clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})

       con.newInstance(params...)

 

4、反射类的属性:

       Field field =clazz.getField(fieldName);

       field.setAccessible(true);

       field.setObject(value);

获取了字节码文件对象后,最终都需要创建指定类的对象,创建对象的两种方式(其实就是对象在进行实例化时的初始化方式):

1、调用空参数的构造函数:使用了Class类中的newInstance()方法。

2、调用带参数的构造函数:先要获取指定参数列表的构造函数对象,然后通过该构造函数的对象的newInstance(实际参数) 进行对象的初始化。

	public static void getClassObject_3() throws Exception
	{
		String className = "FanShe.Person";		//类名必须要加包名,就算导包了也要加
		Class clazz = Class.forName(className);
	
		//第一种方法:
		Object obj = clazz.newInstance();	//创建一个新实例,此方法只创建空参数	
		
		

		//第二种方法:
		/*
		 * 当获取指定名称对应类中的所体现的对象时,而该对象初始化不使用空参数构造时该怎么办呢?
		 * 既然是通过指定的构造函数进行对象的初始化,所以应该先获取到该构造函数
		 * 
		 * */
		Constructor constructor = clazz.getConstructor(String.class,int.class);
		
		Object object = constructor.newInstance("小明",25);
		
	}
	

综上所述,第二种方式,必须要先明确具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数。


利用反射获取字段:

<strong>	</strong>public static void getField()throws Exception
	{
		String className = "cn.itheima.Person";
		Class clazz = Class.forName(className);
		
		Constructor constructor = clazz.getConstructor(String.class,int.class);
		
		Person p = (Person)constructor.newInstance("张三",22);

		
		//获取字段,只获取公共
		Field field = clazz.getField("name");
		
		//获取本类字段,包括私有
		Field field1 = clazz.getDeclaredField("age");
		
		//对字段取消权限检查
		field1.setAccessible(true);
		
		//设置获取字段
		field1.set(p,25);
		System.out.println(field1.get(p));
		
		field.set(p, "李四");	
		String name = (String)field.get(p);
		System.out.println(name);
	}

利用反射获取方法:

<strong>	</strong>public static void getMethod()throws Exception
	{
		String className = "cn.itheima.Person";
		Class clazz = Class.forName(className);
		Person p = (Person)clazz.getConstructor(String.class,int.class).newInstance("李四",88);
		
		//获取所有公共方法
		Method[] methods = clazz.getMethods();
		
		//获取本类方法,包含私有
		//Method[] methods = clazz.getDeclaredMethods();
		
		System.out.println(methods.length);
		for(Method m : methods)
		{
			System.out.println(m.toString());
		}
		
		//获取某个方法
		Method method = clazz.getMethod("getName",null);
		
		Method method1 = clazz.getMethod("show",String.class,int.class);
		
		//调用方法
		System.out.println(method.invoke(p));
		System.out.println(method.invoke(p,"xiaoming",22));
		
	}

使用反射注意两点:

1、如果用反射调用的是静态方法,则调用invoke方法时,不用写对象,如果此方法有参数,则对象写null;

2、如果要调用的函数是一个数组,java会把它拆包成若干个对象,这时,要将这个对象封装成一个对象如:(Object)new String[];


反射扩展练习:

/*

一台电脑有一块主板,主板有一个接口,电脑运行主板
有一个声卡实现了这个主板接口,在电脑运行
后期又添加了一个网卡,让网卡业运行起来,利用反射技术,不修改任何代码的情况下,
修改配置文件就可以直接让网卡跑起来


*/

package cn.itheima;
import java.util.*;
import java.lang.reflect.*;
import java.net.*;
import java.io.*;
public class ReflectDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args)throws Exception
	{
		Properties pro = new Properties();
		FileInputStream fis = new FileInputStream("PCI.properties");
		
		//将流中的键值对加载进集合
		pro.load(fis);
		for(int x=0;x<pro.size();x++)
		{
			String className = pro.getProperty("PCI"+(x+1));
			
			//在获取字节码文件的时候要确定字节码文件要导包
			System.out.println(className);
			Class clazz = Class.forName(className);
			
			//父类的引用指向了子类对象,子类实现了父类的方法,所以使用的还是子类的实现方法
			//后期添加了网卡,那么这个网卡实现了主板接口,拿到这个实现的类名,创建此对象
			Mainboard p =(Mainboard)clazz.newInstance();

			//调用主板接口中的方法,也就是子类实现父类的方法
			p.opend();
			p.close();

		}
		//getField();
		//getMethod();
		
	}
	


public class SoundCord implements Mainboard
{
	public void opend()
	{
		System.out.println("SoundCord--声卡运行");
	}
	public void close()
	{
		System.out.println("SoundCord--声卡关闭");
	}

}


package cn.ittest;

public class NetCord implements Mainboard
{
	public void opend()
	{
		System.out.println("NetCord--网卡运行");
	}
	public void close()
	{
		System.out.println("NetCord--网卡关闭");
	}
}


public interface Mainboard 
{
	void opend();
	void close();
}







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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值