反射-Reflection
反射
1.获取类对象(三种途径)
-
Hero.class
-
Class.forName()
-
new Hero().getClass()
注:当前获取类对象会加载类的静态属性(除了
Class c = Hero.class
这种方式)
2.创建一个对象
ReflectionTestClass p = new ReflectionTestClass("男");
Class<? extends ReflectionTestClass> c = p.getClass();//类对象
Constructor<?> constructor = c.getConstructor();//构造器
ReflectionTestClass o = (ReflectionTestClass)constructor.newInstance()//通过构造器进行实例化
o.setAge(12);
System.out.println(o);
3.获取属性(字段)
Class
类提供了以下几个方法来获取字段:
- Field getField(name):根据字段名获取某个public的field(包括父类)
- Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
- Field[] getFields():获取所有public的field(包括父类)
- Field[] getDeclaredFields():获取当前类的所有field(不包括父类)
getField和getDeclaredField的区别
这两个方法都是用于获取字段
getField 只能获取public的,包括从父类继承来的字段。
getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。 (注: 这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))
ReflectionTestClass p = new ReflectionTestClass("男");
Class<? extends ReflectionTestClass> c = p.getClass();
Field age = c.getDeclaredField("sex");
age.setAccessible(true);//因其属性是private 所以拿到需要加该语句
age.set(p, "女");//修改该字段的
System.out.println(age.get(p));
4.调用方法
Class
类提供了以下几个方法来获取Method
:
Method getMethod(name, Class...)
:获取某个public
的Method
(包括父类)Method getDeclaredMethod(name, Class...)
:获取当前类的某个Method
(不包括父类)Method[] getMethods()
:获取所有public
的Method
(包括父类)Method[] getDeclaredMethods()
:获取当前类的所有Method
(不包括父类
ReflectionTestClass p = new ReflectionTestClass("男");
Method m = p.getClass().getMethod("setId", int.class);
m.invoke(p,12);
System.out.println(p.getId()+" ");
5.cron表达式格式:{秒数} {分钟} {小时} {日期} {月份} {星期}
“* ”
“30 * * * * ?” 每半分钟触发任务
“30 10 * * * ?” 每小时的10分30秒触发任务
“30 10 1 * * ?” 每天1点10分30秒触发任务
“30 10 1 20 * ?” 每月20号1点10分30秒触发任务
“30 10 1 20 10 ? *” 每年10月20号1点10分30秒触发任务
“30 10 1 20 10 ? 2011” 2011年10月20号1点10分30秒触发任务
“30 10 1 ? 10 * 2011” 2011年10月每天1点10分30秒触发任务
“30 10 1 ? 10 SUN 2011” 2011年10月每周日1点10分30秒触发任务
“15,30,45 * * * * ?” 每15秒,30秒,45秒时触发任务
“15-45 * * * * ?” 15到45秒内,每秒都触发任务
“15/5 * * * * ?” 每分钟的每15秒开始触发,每隔5秒触发一次
“15-30/5 * * * * ?” 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
“0 0/3 * * * ?” 每小时的第0分0秒开始,每三分钟触发一次
“0 15 10 ? * MON-FRI” 星期一到星期五的10点15分0秒触发任务
“0 15 10 L * ?” 每个月最后一天的10点15分0秒触发任务
“0 15 10 LW * ?” 每个月最后一个工作日的10点15分0秒触发任务
“0 15 10 ? * 5L” 每个月最后一个星期四的10点15分0秒触发任务
“0 15 10 ? * 5#3” 每个月第三周的星期四的10点15分0秒触发任务
6.调用构造方法
通过Class实例获取Constructor的方法如下:
getConstructor(Class...)
:获取某个public
的Constructor
;getDeclaredConstructor(Class...)
:获取某个Constructor
;getConstructors()
:获取所有public
的Constructor
;getDeclaredConstructors()
:获取所有Constructor
。
注意Constructor
总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。
调用非public
的Constructor
时,必须首先通过setAccessible(true)
设置允许访问。setAccessible(true)
可能会失败。
7.动态代理
在运行期动态创建一个interface
实例的方法如下:
-
定义一个
InvocationHandler
实例,它负责实现接口的方法调用; -
通过
Proxy.newProxyInstance()
创建
interface
实例,它需要3个参数:
- 使用的
ClassLoader
,通常就是接口类的ClassLoader
; - 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler
实例。
- 使用的
-
将返回的
Object
强制转型为接口。public class Main { public static void main(String[] args) { InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method); if (method.getName().equals("morning")){ System.out.println("Good morning, " + args[1]); } else if(method.getName().equals("lunch")) { System.out.println("Good afternoon, " + args[0]); } return null; } }; Hello o = (Hello)Proxy.newProxyInstance( Hello.class.getClassLoader(), //传入Classloader new Class[]{Hello.class}, //传入要实现的接口 invocationHandler); //传入处理调用方法的InvocationHandler o.morning("Bob", 12); o.lunch(13); } } interface Hello { void morning(String name, int age); void lunch(int age); }