黑马程序员—反射知识总结
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();
}
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对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统