java总结系列之反射机制

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


JAVA反射(放射)机制:"程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言"。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

JAVA反射机制定义:

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


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


一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。


尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。




JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类

的所有属性和方法;

 * 对于任意一个对象,都能够调用它的任意一个方法和属性;

 * 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

 



 * 动态获取类中信息,就是java反射 。

 * 可以理解为对类的解剖。

 *  

 * 要想要对字节码文件进行解剖,必须要有字节码文件对象.

 * 如何获取字节码文件对象呢?

 * 最有扩展性的获取方式就是:

 * 方式三:Class类:java.lang包中的类。

 * 只要通过给定的类的 字符串名称就可以获取该类,更为扩展。

 * 可是用Class类中的方法完成。

 * 该方法就是Class类中的方法:forName().

 * 返回与带有给定字符串名的类或接口相关联的 Class 对象

 * 这种方式只要有名称即可,更为方便,扩展性更强。

 * ClassNotFoundException:这是所指定的类不存在的异常。

 * String className = "cn.itcast.bean.Person";

 *//指定类的路径名必须要是全名,就算导包也对这种方法无用

 *Classclazz = Class.forName(className);

 *   //forName().返回与带有给定字符串名的类或接口相关联的 Class对象


/*
* 方式三:
* 只要通过给定的类的 字符串名称就可以获取该类,更为扩展。
* 可是用Class类中的方法完成。
* 该方法就是Class类中的方法:forName().
* 返回与带有给定字符串名的类或接口相关联的 Class 对象
* 这种方式只要有名称即可,更为方便,扩展性更强。 
* ClassNotFoundException:这是所指定的类不存在的异常。
*/

public static void getClassObject_3() throws ClassNotFoundException {

String className = "cn.itcast.bean.Person";
//指定类的路径名必须要是全名,就算导包也对这种方法无用
Class clazz = Class.forName(className);
//forName(). 返回与带有给定字符串名的类或接口相关联的 Class 对象
System.out.println(clazz);
}








/*
* 方式二:
* 2,任何数据类型都具备一个静态的属性.class来获取其对应的Class对象。
* 相对简单,但是还是要明确用到类中的静态成员。
* 这两种方式还是需要还是不够扩展。 

*/
public static void getClassObject_2() {

Class clazz = Person.class;

Class clazz1 = Person.class;
System.out.println(clazz==clazz1);
}

/*
* 获取字节码对象的方式:
* 1,Object类中的getClass()方法的。
* 想要用这种方式,必须要明确具体的类,并创建对象。
* 麻烦 .

*/
public static void getClassObject_1(){

Person p = new Person();
Class clazz = p.getClass();

Person p1 = new Person();
Class clazz1 = p1.getClass();

System.out.println(clazz==clazz1);
}


获取字节码文件中的构造函数。

 *

 * Class既然是可以获取指定的类的字节码文件对象,进而其就可以获取指定类中各个部分的对象

 * 比如:*构造函数**字段**方法*等而且一旦获取了对部位的对象,就可以对这个对象进行一些方法操作。

 * 其中获取方法最常用。

 * 但要知道这三个类都是java.lang.reflect包中的类。是java.lang.reflect.AccessibleObject的子类。

 *

 *

 * //获取到了指定的*构造函数*对 象。  

 *Constructor constructor = clazz.getConstructor(String.class,int.class);

 *//通过该构造器对象的newInstance方法进行对象的初始化。

 *Objectobj = constructor.newInstance("小明",38);

 *

 *而获取到指定的*构造函数*对 象之后,就可以使用其中的方法对这个对象进行操作。

 *例:newInstance(Object...initargs)

     *使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,

     *     并用指定的初始化参数初始化该实例

public class ReflectDemo2 {


/**
* @param args
* @throws Exception 
* @throws InstantiationException 
* @throws ClassNotFoundException 
* 获取字节码文件中的构造函数。

* Class既然是可以获取指定的类的字节码文件对象,进而其就可以获取指定类中各个部分的对象
* 比如:*构造函数**字段**方法*等而且一旦获取了对部位的对象,就可以对这个对象进行一些方法操作。
* 其中获取方法最常用。 
* 但要知道这三个类都是java.lang.reflect包中的类。是java.lang.reflect.AccessibleObject的子类。


* //获取到了指定的*构造函数*对 象。  
* Constructor constructor = clazz.getConstructor(String.class,int.class);
* //通过该构造器对象的newInstance方法进行对象的初始化。
* Object obj = constructor.newInstance("小明",38);
*
*而获取到指定的*构造函数*对 象之后,就可以使用其中的方法对这个对象进行操作。
*例:newInstance(Object... initargs) 
     *使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,
     *     并用指定的初始化参数初始化该实例
*/
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, Exception {


createNewObject_2();

}

public static void createNewObject_2() throws Exception {

// cn.itcast.bean.Person p = new cn.itcast.bean.Person("小强",39);

/*
* 当获取指定名称对应类例如(Person类)中的所体现的对象时,
* 而该对象初始化不使用空参数构造该怎么办呢? 例没有:Person(){}

* 既然是通过指定的构造 函数进行对象的初始化,
* 所以应该先获取到该构造函数。 通过字节码文件对象即可完成。
* 该方法是:getConstructor(paramterTypes)等一系列的方法;

* cn.itcast.bean.Person p = new cn.itcast.bean.Person("小强",39);
* 以下程序实现的功能与上面的这句话实现的功能一致。

* Class既然是可以获取指定的类的字节码文件对象,进而其就可以获取指定类中各个部分的对象
* 比如:*构造函数**字段**方法*等而且一旦获取了对部位的对象,就可以对这个对象进行一些方法操作。
*/
String name = "cn.itcast.bean.Person";
//找寻该名称类文件,并加载进内存,并产生Class对象。
Class clazz = Class.forName(name);
//获取到了指定的*构造函数*对 象。  
Constructor constructor = clazz.getConstructor(String.class,int.class);

//通过该构造器对象的newInstance方法进行对象的初始化。
Object obj = constructor.newInstance("小明",38);



}


public static void createNewObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//InstantiationException:空参异常,例如下面调用创建对象时,Person类中没有空参数的过早函数时就会报此异常。
//IllegalAccessException:无效指针异常;当Person类的构造函数贝斯有化时,会报此异常
//早期:new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,
// 并创建该字节码文件对象,并接着创建该字节文件的对应的Person对象.
// cn.itcast.bean.Person p = new cn.itcast.bean.Person();

//现在:优点在于此方法由记得的扩展性。
String name = "cn.itcast.bean.Person";//只需要将此处暴露到卑职文件中,就可只用一个字符串名字就创建一个对应的对象
//找寻该名称类文件,并加载进内存,并产生Class对象。
Class clazz = Class.forName(name);
//如何产生该类的对象呢?
Object obj  = clazz.newInstance();
//newInstance() :实际上与上面的创建失一个意思, 创建此 Class 对象所表示的类的一个新实例
//如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类


}

--------------------------------------------------------------------------------

获取字节码文件中的字段。

 * clazz.getField("age");//只能获取公有的

 * clazz.getDeclaredField("age");//只获取本类,但包含私有。

 * 这两种方法返回的都是字段数组。

 


拿方法与那构造函数不同,构造函数的名字都是一样的但是方法名大都不同,

 * 因此想要拿指定的方法,就必须指定方法名以及方法中的参数才行。

 * 例如:

 *Method method = clazz.getMethod("show", null);//获取空参数一般方法

 *Method method = clazz.getMethod("paramMethod", String.class,int.class);非空参数

 *method.invoke(obj, "小强",89);使用Method类中的方法对这个method对象进行操作。

 *

 *method类的父类是java.lang.reflect.AccessibleObject

/*
 * 电脑运行。 
 */
public class ReflectTest {


/**
* @param args
* @throws Exception 
* 这个包中的文件模拟了如何使一个电脑在接口处插上一个外界设备例如:声卡、网卡等,
* 而只需要在配置文件中奖其键值对星系信息加上就可以使外接设备运行的功能。

* 此类是:电脑整体对象:
* 可以在其上新建主板对象,插上接口连上声卡进而使其工作
* 但是关键在于我们不知道可能会插上什么样的对象是声卡还是别的
* 而且我们不想每一次插入一个对象就在这里修改代码来调用它,因此
* 这就需要程序的扩展性。

* 以如今的这个包中的程序实现来看,我们要运行一个外接接口的对象,
*就只需要将配置文件中的键值对信息修改了就可以了


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


Mainboard mb = new Mainboard();
mb.run();
//每次添加一个设备都需要修改代码传递一个新创建的对象
// mb.usePCI(new SoundCard());
//能不能不修改代码就可以完成这个动作。 
// 不用new来完成,而是只获取其class文件。在内部实现创建对象的动作。 

File configFile = new File("pci.properties");//关联一个文件,获取其虚拟对象

Properties prop = new Properties();//属性集:键值对。
//Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。
//属性列表中每个键及其对应值都是一个字符串
FileInputStream fis = new FileInputStream(configFile);

prop.load(fis);
//load(InputStream inStream) 从输入流中读取属性列表(键和元素对)
       
for(int x=0; x<prop.size(); x++){

String pciName = prop.getProperty("pci"+(x+1));

Class clazz = Class.forName(pciName);//用Class去加载这个pci子类。 

PCI p = (PCI)clazz.newInstance();//将新建的实例强转成PCI类。

mb.usePCI(p);//调用mainboard类的usePCI方法。
}
fis.close();
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值