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

------- 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.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();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值