您的位置:首页 > 编程语言 > Java开发

Java学习总结-反射

2016-07-26 17:23 519 查看

1、反射的概念。

是Java语言提供的一种机制,并不是所有语言都具备;反射可以实现在.java文件编译时,可以不明确类的具体类型,而在.class文件运行再去检查和明确这个类。

2、反射的原理。

首先要了解一下java程序的运行步骤,源(.java)文件经过javac.exe编译后生成二进制(.class)文件,编译主要工作就是语法检查,然后通过java.exe去执行二进制文件,这时jvm会通过类加载器把二进制文件装入方法区,同时在堆中会创建一个描述这个类的对象,类型为java.lang.Class(注意是大写)。

这个类描述的内容无非是装载类的基本属性:

class Class{

名称(类名)

字段(成员变量)

构造函数

一般函数(成员函数)

}

 


通过这个类可以获取到字节码文件的所有信息,而反射的就是依赖的这个字节码文件对象。

也许你有疑问,获取这些信息能干什么呢?

1.  有了构造函数,你可以创建这个类的新的实例(对象)。

2.  可以返回字段值。

3.   执行一般函数等。

所有的工作都可以做,跟你拿到这个类的源代码是同样的效果。下面的工作就是怎么获取一个类的二进制文件的对象。

3、获取Class对象的三种方式

1、  通过Object类提供的getClass
()
方法。

2、  通过所有类都具备的静态属性.class。

3、  通过java.lang.Class的forName
(
String
 className)
方法(重点)。

 

packageitcast.reflect.demo;

publicclass ReflectDemo {
public static void main(String[] args)throws Exception{
//getClassObject_1()
//getClassObject_2()
getClassObject_3();
}
/*
*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);
}
/*
*2、任何数据类型都具备一个静态属性.class来获取起对应的class对象
*/
public static void getClassObject_2(){
Class clazz = Person.class;

Class clazz1 = Person.class;

System.out.println(clazz ==clazz1);
}
/*
*3、通过java.lang.Class类的forName,根据类名的字符串形式,获取该类的二进制文件对象,这种方式只需名称即可,扩展性更强。
*/
public static void getClassObject_3()throws Exception{
String name ="itcast.reflect.demo.Person";
Class clazz =Class.forName(name);
System.out.println(clazz);
}

}
packageitcast.reflect.demo;

publicclass Person {
private int age;
private String name;

public Person(String name,int age){
super();
this.age = age;
this.name = name;

System.out.println("Personparam run..."+this.name+":"+this.age);
}

public Person(){
super();

System.out.println("personrun");
}

public void show(){
System.out.println(name+"...showrun..."+age);
}

private void privateMethod(){
System.out.println("privateMethodrun");
}

public void paraMethod(String str,intnum){
System.out.println("paraMethodrun...."+str+":"+num);

}
public static void staticMethod(){
System.out.println("staticmethod run....");
}
}


4、获取构造函数(创建实例)

1、  如果是构建一个无参的实例,通过Class调用newInstance
()
方法。

2、  如果是构建一个有参数的实例,通过Class的getConstructor
(
Class
<?>... parameterTypes)
方法,根据传入的参数列表的类型去返回对象的构造函数对象,然后再调用newInstance(Object... initargs)方法创建实例。

 

packageitcast.reflect.demo;

importjava.lang.reflect.*;

publicclass ReflectDemo2 {
public static void main(String[] args)throws Exception {
createNewObject_2();
}

public static void createNewObject()throws Exception{
//早期:new时候,先根据被new的名称找寻该类的字节码文件,并加载进内存,
//并创建该自己吗文件对象,并接着创建该字节文件的对应的Person对象
//itcast.bean.Person p = newcn.itcast.bean.Person();

//现在:
String name ="itcast.reflect.demo.Person";
//找寻该名称类文件,并加载进内存,并产生Class对象
Class clazz =Class.forName(name);
//如何产生该类的对象呢
Object obj =clazz.newInstance();

}

public static void createNewObject_2()throws Exception{

/*
* 当获取指定名称对应类中的所体现的对象是
* 而该对象初始化不适用空参数构造该怎么办呢
* 既然是通过指定的构造函数进行初始化,所以应该先获取该构造函数。
* 通过字节码文件对象就可以获得,指定的:getConstructor(Class<?>...parameterTypes) 全部:getConstructors() 全部(包含私有):getDeclareConstrunctors()
*
*/

String name ="itcast.reflect.demo.Person";
Class<?> clazz =Class.forName(name);
//获取到了指定的构造函数对象
Constructor constructor =clazz.getConstructor(String.class,int.class);
//通过该构造器对象的newInstance方法进行对象的初始化
Object obj =constructor.newInstance("小强",23);

}
}


5、返回Class中字段

公有的字段,通过Class的getField
(
String
 name)
,根据字段名去获取。

私有的,通过Class的
getDeclaredField
(
String
 name)
获取,又叫暴力获取。

以上返回Field对象,其中该对象的set
(
Object
 obj,
Object
 value)
方法可以修改对象中值。


packageitcast.reflect.demo;

importjava.lang.reflect.*;

publicclass ReflectDemo3 {
public static void main(String[] args)throws Exception {
getFieldDemo();
}

public static void getFieldDemo()throws Exception {
Class<?> clazz =Class.forName("itcast.reflect.demo.Person");
//私有成员变量无法获取
//Field field=clazz.getField("age");
//暴力获取私有成员变量
Field field =clazz.getDeclaredField("age");

//获取指定参数的构造函数
Constructor constructor =clazz.getConstructor(String.class,int.class);

//调用构造的函数传入参数,创建实例
Object obj  = constructor.newInstance("小强",23);

//get(Object obj)返回指定对象上Field表示字段的值
//私有成员不能获取,通过SetAccessible()设置
field.setAccessible(true);

field.set(obj,89);
Object value =field.get(obj);

System.out.println(value);
}

}


6、 获取Class中方法

通过Class的getMethods
()
获取所有的公共方法,包括父类的。
通过Class的getDeclaredMethods
()
获取本类的方法,包括私有。

通过Class的getDeclaredMethod
(
String
 name,
Class
<?>... parameterTypes)
获取单个方法,name表示函数名,parameterTypes表示参数。
以后返回Method对象,通过invoke
(
Object
 obj,
Object
... args)
,传入对象和参数值,执行该方法。


package itcast.reflect.demo;

import java.lang.reflect.*;

public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
getMethodDemo_2();
}
/*
* 获取指定Class中的公共函数
*/

public static void getMethodDemo() throws Exception {

Class clazz =Class.forName("itcast.reflect.demo.Person");

Method[] methods = clazz.getMethods();//获取的都是公有的方法

methods = clazz.getDeclaredMethods();//获取本类的所有方法

for(Method method : methods){
System.out.println(method);
}

}

public static void getMethodDemo_2() throws Exception {
Class<?> clazz = Class.forName("itcast.reflect.demo.Person");

Method method =clazz.getMethod("staticMethod",null);

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

//Object obj  =constructor.newInstance("小强",23);

method.invoke(null,null);
}

}


7、  反射的应用

通过读取配置文件,获取加载的类文件对象,然后动态执行程序,编码程序的修改。

 

packageitcast.reflect.test;

importjava.lang.reflect.*;
importjava.io.*;
importjava.util.*;

publicclass ReflectTest {
public static void main(String[] args)throws Exception {
Mainboard mb = newMainboard();
mb.run();

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

File configFile = newFile("pci.properties");

Properties prop = newProperties();

FileInputStream fis = newFileInputStream(configFile);

prop.load(fis);

for(intx=0;x<prop.size();x++){
String pciName =prop.getProperty("pci"+(x+1));
Class clazz =Class.forName(pciName);
Object obj =clazz.newInstance();

PCI p =(PCI)clazz.newInstance();

mb.usePCI(p);
}

fis.close();
}

}


packageitcast.reflect.test;

//importitcast.reflect.test.PCI;

publicclass Mainboard {

public void run() {
System.out.println("mainborad run...");
}

/*public void useSound(SoundCard c){
c.open();
c.close();
}*/

public void usePCI(PCI p){
if(p!=null){
p.open();
p.close();
}

}
}


packageitcast.reflect.test;

publicinterface PCI {

public void open();

public void close();
}

packageitcast.reflect.test;

publicclass SoundCard implements PCI {

public void open() {
System.out.println("soundopen");
}

public void close() {
System.out.println("soundclose");
}
}


packageitcast.reflect.test;

publicclass NetCard implements PCI {

public void open() {
System.out.println("netopen");
}

public void close() {
System.out.println("netclose");
}
}


文件名:pci.properties:

pci1=itcast.reflect.test.SoundCard
pci2=itcast.reflect.test.NetCard
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: