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

黑马程序员—反射知识总结

2015-10-12 19:54 369 查看
-------
android培训、java培训、期待与您交流! ----------

反射概述:Java反射机制是在运行中,对任意一个类,都能够知道这个类的所有属性和方法。

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

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

想要解剖一个类,必须想要获取到该类的字节码文件,而对象解剖使用的就是Class类中的方法,所以要

获取到每一个字节码文件对应的Class类型对象。

三种获取方式:

1.object类的getClass方法,通常用来判断两个对象是否是同一个字节码文件。

2.静态属性class。例:静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class

3.Class类中的静态方法forName()。读取配置文件。

1,2,3分别用于获取源文件阶段,字节码阶段以及创建对象阶段的字节码文件。

三种获取方法的演示:

例:

public static void main(String[] args) throws ClassNotFoundException

{
Class clazz1 = Class.forName("com.heima.bean.Person");
//方式1Class中静态方法forName。
Class clazz2 = Person.class;
//方式2静态属性class.

Person p = new Person();
Class clazz3 = p.getClass();
//方式三object中的getClass方法

System.out.println(clazz1 == clazz2);
System.out.println(clazz2 == clazz3);

}

用forName读取配置文件:

榨汁机例:

interface Fruit 
//建立水果接口

{

public void squeeze();

}

class Apple implements Fruit
//两个子类实现水果接口

{

public void squeeze()

{

S.O.P("榨出一杯品果汁");

}

}

class Orange implements Fruit

{

public void squeeze()

{

S.O.P("榨出一杯橘子汁");

}

}

class Juicer
//建立果汁类

{

public void run(Fruit f)

{

f.squeeze();

}

}

class Demo

{

public static void main(String [] args)

{

Juicer j = new Juicer();
//创建果汁对象

     BufferedReader bufr = new BufferedReader(new FileReader("config.properties"));
//因为要读取文件所以这里用了文件读取流并加入缓冲区。文件中是我们要获取的类的全称

Class clazz = Class.forName(bufr);
//用forName获取类的字节码文件

Fruit f = (Fruit)clazz.newInstance();
//newInstance建立一个对象用该类的空参数构造方法。

j.run(f);
//调用Juicer中的方法。

}

}

通过反射获取带参数的构造方法并使用。

如果一个类中没有无参的构造函数则不能使用newInstance方法来创建。

要使用class类中的getConstructor方法获取指定的构造函数。

然后再调用Constructor类中的newInstance方法来创建对象。

例:

class Demo2

{

//假如有一个Person类其中类中的构造函数需要传递两个参数String name 与int age;

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

{
Class clazz = Class.forName("com.heima.bean.Person");
//Person p = (Person) clazz.newInstance();           通过无参构造创建对象
//System.out.println(p);

Constructor c = clazz.getConstructor(String.class,int.class); //获取有参构造
Person p = (Person) c.newInstance("张三",23); //通过有参构造创建对象
System
4000
.out.println(p);
}

}

通过反射获取成员变量并使用

Class.getField(String)方法可以获取类中的指定字段(可见的)。 如果是私有的可以用getDeclaedField(String)方法获取,

  通过set(obj, String)方法可以设置指定对象上该字段的值,  如果是私有的需要先调用setAccessible(true)设置访问权限,

 用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值

class Demo3

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

{

Class clazz = Class.forName("com.heima.bean.Person");           

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

Person p = (Person) c.newInstance("張三",23);

 

//Field  f = clazz.getField("name");                      
//获取姓名字段

//f.set(p,"李四");
//修改姓名的值

Field f = clazz.getDeclaredField("name");
//暴利反射获取私有字段

f.setAccessible(true);
//去除私有权限

f.set(p,"李四");

System.out.println(p);

}

}

通过反射获取类中指定的方法并使用

Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法

可以获取类中的指定方法,调用invoke(Object, Object...)可以调用该指定方法。

例:

假如有Person类其中有eat方法。通过反射获取并使用该方法

class Demo4

{

public static void main()

{

Class clazz = Class.forName("Person"); 
//获取字节码文件

Constructor c = clazz.getConstranctor(String.class,int.class);
//获取指定有参构造函数

Person p = clazz.newInstrance("张三",14);
//建立有参对象

Method m = clazz.getMethod("eat");
//获取方法

m.invoke(p);
//调用方法

}

}

通过反射越过泛型检查

我们都知道一旦定义了一个带有指定类型的泛型的集合后,就无法向该集合中添加其他类型的元素。

但是通过反射我们可以在该集合添加不同类型的元素。因为泛型只在编译器有效,在运行期会被擦除。

例:

class Demo5

{

public static void main(String[] args)

{

ArrayList<Integer> al = new ArrayList<Integer>()

al.add(123);

al.add(321);

Class clazz 
= Class.forName("java.util.Arraylist");

Method m = clazz.getMothod("add",objcet.class);

m.invoke(al,"abc");

}

}

反射动态代理

概述:代理就是本来应该自己做的事交给别人去做,被请的人就是代理对象。

动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

通过实现InvocationHandler接口复写invoke方法来实现。

例:

interface Student 

{
public void login();
public void submit();

}

class Student implements

{

public void login()

{

S.o.p("...");

}

public void submit();

{

S.o.p("...");

}

}

public class MyInvocationHandler implements InvocationHandler  
//实现InvocationHandler接口

 {
private Object target;
//设置成员变量 (就是传进来的类)

public MyInvocationHandler(Object target)

{
this.target = target;
}

//proxy要代理的对象
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("权限校验");
//添加一些我们需要的功能,代理对象实现的功能
method.invoke(target, args);
//执行被代理target对象的方法
System.out.println("日志记录");
return null;
}

}

class Demo6

{
StudentImp si = new StudentImp();
si.login();
si.submit();

System.out.println("--------------");
MyInvocationHandler m = new MyInvocationHandler(si);  //建立InvocationHandler的子类对象(他实现了InvocationHandler)
//把si传入InvocationHandler中
Student s = (Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m);
//注意这里返回的是接口所以要写Student。强制转换。

//调用Proxy方法getClass().getClassLoader()是通过对象获取字节码文件,然后获取该类的加载器与左边原理相同获取对象的所有实现接口

//m是InvocationHandler的子类,里面有我们的写的方法
s.login();
s.submit();

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