您的位置:首页 > 职场人生

黑马程序员 反射

2015-08-29 17:01 597 查看
------- android培训java培训、期待与您交流! ----------

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

1.Class类

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。

想要获取到一个类的字段,方法,构造函数等,首先要获取其字节码文件。

获取字节码的三种方式:

1、当获取一个对象时,想要获取其类的字节码,使用getClass()方法。
Class cl = p.getClass() //获取对象p的字节码文件
2、当获取一个指定类的字节码时,使用该类的class方法
Class cl = Student.class //获取Student类的字节码文件
3、获取一个类的的字节码,也可以通过Class类的forName()方法加上类的全限定名获取
Class cl = Class.forName("java.util.Arrays"); //获取Arrays类的字节码文件

九个预定义Class对象:8个基本数据类型,和void。

在Class类中有一些常用方法:

public static Class<?> forName(String className):通过类的名字获得该类的Class对象,这个方法是静态方法。在Class类中没有构造方法,要想获得Class对象只能通过静态方法返回。
Class getClass() :返回Class对象即字节码对象
public Field getField(String name):返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。name 参数是一个 String,用于指定所需字段的简称。
public Method getMethod(String name,Class<?>... parameterTypes):返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
public String getName():以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。 public boolean isArray():判定此 Class 对象是否表示一个数组类。
public boolean isPrimitive():判定指定的 Class 对象是否表示一个基本类型。
public boolean isInterface():判定指定的 Class 对象是否表示一个接口类型。
public T newInstance():创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。

可以看到,反射就是将Java类中的各种成分映射成相应的java类。例如,类中的组成成分:成员变量、构造方法、方法、包信息等分别对应Field、Constructor、Method、Package等。

2.构造函数的反射

当一个类不存在空参数的构造函数时,就不能通过newInstance方法获得其对象,所以必须先要通过反射获得其构造函数。

构造函数可能有多种重载方式,我们通过不同的参数列表来确定反射的是哪个构造函数。或者通过getConstructors方法得到其全部的构造函数。

Constructor cons =  String.class.getConstructor(StringBuffer.class);
String str2 = (String)cons.newInstance(new StringBuffer("abc"));


3.成员变量的反射

使用getField方法获得成员变量的字段。

Field fieldY = XXX.getClass().getField("Y");

获得了Field对象后可以再使用Field对象给指定对象上的成员变量设定指定的值,或者得到一个对象上这个字段的值

public void set(Object obj,Object value):将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
public Object get(Object obj):返回指定对象上此 Field 表示的字段的值。如果该值是一个基本类型值,则自动将其包装在一个对象中。
如果要访问私有的字段,要先设置其权限
public void setAccessible(boolean flag):将此对象的 accessible 标志设置为指示的布尔值。值为true时表示可以访问。

public class ReflactTest2 {

public static void main(String[] args)throws Exception {
Class c =Class.forName("Person");

//调用默认的构造函数
Person p = (Person)c.newInstance();

//获得Field对象,是属于字节码的。对于private的属性要使用getDeclaredFile才可以看见。
Field age = c.getDeclaredField("age");
//对于private的变量,要通过下面的方法设置权限
age.setAccessible(true);
//调用Field对象的set方法设置具体person对象的age
age.set(p, 10);

Field name = c.getDeclaredField("name");
name.setAccessible(true);
name.set(p, "zhangsan");

//不是private的属性使用getField就可以拿到。
Field address = c.getField("address");
address.set(p, "beijing");

System.out.println(p.toString());
}
}
class Person{
private int age ;
private String name ;
public String address;

public Person(){
System.out.println("Person run.."+this.name+":"+this.age);
}

public void show(){
System.out.println("Pserson show ...");
}

public void show(String p){
System.out.println("Pserson show ..."+"String:"+p);
}

private void show(int i){
System.out.println("private method show ..."+"String:"+i);
}
}


4.方法的反射

通过Class类中的getMethod方法来获得指定的Method对象

public Method getMethod(String name,Class<?>... parameterTypes):获得一个指定的Method对象,该方法的名字以传入的值确认,parameterTypes代表该方法的参数列表 ,无参数可以写null。
public Method[] getMethods():返回一个包含某些 Method 对象的数组
public Method getDeclaredMethod(String name,Class<?>... parameterTypes):获得本类私有方法

Method类中常用的方法有:

public Object invoke(Object obj,Object... args):对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。obj表示指定的对象,args表示参数列表当这个方法为静态方法时作用对象可以填null,无参方法时参数可以填null。

public static void getPersonMethod() throws Exception{
//如果想要获取方法,必须先要有对象。
Class clazz=Class.forName("cn.itheima.Person");
Person p=(Person)clazz.newInstance();

Method[] mes=clazz.getMethods();//只获取所有方法

for(Method me:mes){
System.out.println(me);
}

//获取单个方法
Method me=clazz.getMethod("toString", null);
Object returnVaule=me.invoke(p, null);
System.out.println(returnVaule);
}


5.反射在框架中的作用

java框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现。

框架在开发时,无法知道后来开发要调用的类名,所以无法直接通过new某个对象,而是通过反射来创建对象。

public class ReflactTest {
public static void main(String[] args)throws Exception {
//加载配置文件
Properties proper = new Properties();
InputStream is = new FileInputStream("G:\\eclipse\\Reflect\\src\\init.property");
proper.load(is);
//拿到配置文件中,对应的类名
String soundcard = proper.getProperty("soundCard");
String netcard = proper.getProperty("netCard") ;
//根据上面的类名,通过反射获得类的对象
pci p1 = (pci)Class.forName(soundcard).newInstance();
pci p2 = (pci)Class.forName(netcard).newInstance() ;
//调用对象的方法
p1.run();
p2.run();
}
}

class SoundCart implements pci{
public void start(){
System.out.println("Sound is start");
}
public void close(){
System.out.println("Sound is close");
}
public void run(){
start();
close();
}
}

class netCard implements pci{

public void start() {
System.out.println("netCard is start");
}
@Override
public void close() {
System.out.println("netCard is start");
}
public void run(){
start();
close();
}
}


6.一个反射应用实例

可以看到,泛型的出现让程序变得更安全,但是反射可以绕过泛型,让程序又出现了安全隐患。。

/**
*
* 3、 ArrayList<Integer> list = new ArrayList<Integer>();
*    在这个泛型为Integer的ArrayList中存放一个String类型的对象。
*/

import java.lang.reflect.*;
import java.util.*;
public class pritice03 {
public static void main(String[] args)
{
ArrayList<Integer> list = new ArrayList<Integer>();
//@SuppressWarnings("rawtypes")
Class<?> listcls = list.getClass();

try {
Method me = listcls.getMethod("add", Object.class);//获得ArrayList中的add方法
me.invoke(list,"哥就是要存字符串");
//调用该方法存入字符串到泛型为Integer的ArrayList中
System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
}

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