――Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ――
1.反射和内省
反射:能动态修改Java代码,用于运行时检测和修改某个对象的结构及其行为
内省:内省是反射的一个子集,用于运行时检测某个对象的类型及其包含的属性
JavaBean:是一种特殊的Java类,主要用于传递数据信息。
使用案例:
package cn.itcast.day1; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtils; public class IntroSpectorTest { /** * @param args */ public static void main(String[] args) throws Exception { // TODO Auto-generated method stub ReflectPoint pt1 = new ReflectPoint(3,5); String propertyName = "x"; //"x"-->"X"-->"getX"-->MethodGetX--> //读取对象的字段 Object retVal = getProperty(pt1, propertyName); System.out.println(retVal); Object value = 7; //修改对象的字段 setProperties(pt1, propertyName, value); System.out.println("beantils:"+BeanUtils.getProperty(pt1, "x").getClass().getName()); BeanUtils.setProperty(pt1, "x", "9"); System.out.println(pt1.getX()); /*//java7的新特性 ?????? Map map = {name:"zxx",age:18}; BeanUtils.setProperty(map, "na me", "lhm"); */ BeanUtils.setProperty(pt1, "birthday.time", "111"); System.out.println(BeanUtils.getProperty(pt1, "birthday.time")); PropertyUtils.setProperty(pt1, "x", 9); System.out.println("x="+pt1.getX()); System.out.println(PropertyUtils.getProperty(pt1, "x").getClass().getName()); } //直接利用属性描述器获取该字段的setter方法 private static void setProperties(Object pt1, String propertyName, Object value) throws IntrospectionException, IllegalAccessException, InvocationTargetException { PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass()); Method methodSetX = pd2.getWriteMethod(); methodSetX.invoke(pt1,value); } //通过内省机制获取该类的Javabean,在通过Javabean获取该类的所有成员信息:属性描述器 private static Object getProperty(Object pt1, String propertyName) throws IntrospectionException, IllegalAccessException, InvocationTargetException { /*PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass()); Method methodGetX = pd.getReadMethod(); Object retVal = methodGetX.invoke(pt1);*/ //获取pt1对象的beaninfo,它是用来传递数据的信息的 BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass()); //获取beaninfo中的所有属性描述器 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); Object retVal = null; //遍历出想要的属性:propertyName for(PropertyDescriptor pd : pds){ if(pd.getName().equals(propertyName)) { //获取该属性的读取方法(getter) Method methodGetX = pd.getReadMethod(); retVal = methodGetX.invoke(pt1); break; } } return retVal; } }
2.类加载器
类加载器:将类的字节码文件加载到内存中运行。
三大类加载器:
BootStrap: jre/lib/rt.jar
ExtClassLoader: jre/lib/ext/.*.jar ,文件
AppClassLoader(系统默认的类加载器):classPath下的类文件或目录
类加载器的委托机制:
每个类加载器加载类时,又先委托给其上级类加载器。--load方法
(如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B)
双亲委派机制:如果load方法找不到时,则用find方法找。好处:没有重名的类加载上
3.代理
静态代理:Thread采用了静态代理,Runnable是target,Thread是代理类,new Thread(Runnable target),将target交给代理类Thread执行。
动态代理:好处是可以在运行期动态生成出类的字节码,不需要为每个类配置静态代理的功能。
使用案例:
package cn.itcast.day3; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; public class ProxyTest { /** * @param args */ public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub //生成代理类 Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class); final ArrayList target = new ArrayList(); //根据target:ArrayList,和接口:Advice,创建一个代理类对象出来,该代理只关心target接口的方法,所以选择它的接口 Collection proxy3 = (Collection)getProxy(target,new MyAdvice()); proxy3.add("zxx"); proxy3.add("lhm"); proxy3.add("bxd"); System.out.println(proxy3.size()); System.out.println(proxy3.getClass().getName()); } //根据target:ArrayList,和接口:Advice,创建一个代理类对象出来 private static Object getProxy(final Object target,final Advice advice) { Object proxy3 = Proxy.newProxyInstance( target.getClass().getClassLoader(), /*new Class[]{Collection.class},*/ target.getClass().getInterfaces(), //获取target的接口,原因是代理类要调用target的方法,但是不关心具体内容,所以使用它的接口 new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /*long beginTime = System.currentTimeMillis(); Object retVal = method.invoke(target, args); long endTime = System.currentTimeMillis(); System.out.println(method.getName() + " running time of " + (endTime - beginTime)); return retVal;*/ advice.beforeMethod(method);//方法之前的操作 Object retVal = method.invoke(target, args);//调用目标类的方法 advice.afterMethod(method);//方法之后的操作 return retVal; } } ); return proxy3; } }
4.线程篇
4.1 ThreadLocal
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。
在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,
使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。
因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
4.2 线程池
ExecutorService:Executors.newCachedThreadPool(),Executors.
newFixedThreadPool(int nThreads),Executors.
newSingleThreadExecutor()
作用:在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,
它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,这就是封装。记住,任务是提交给整个线程池,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。
4.3 Callable&Future
作用:好比我同时种了几块地的麦子,然后就等待收割。收割时,则是那块先成熟了,则先去收割哪块麦子。
4.4 Lock&Condition
Lock:将“锁”的功能从“对象锁”中抽离出来,形成一个与对象无关,独立功能的锁。
condition:将对象中的等待,唤醒方法抽离出来,弄成一个condition条件的形式控制对象线程的等待,唤醒操作。
4.5 Semaphore
作用:Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。
形式:Semaphore(int permits),permits为固定的许可证数量,只有的到了“许可证”才可以执行任务,执行完任务后释放“许可证”
4.6 其他同步工具类
CyclicBarrier :表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面,这就好比整个公司的人员利用周末时间集体郊游一样,
先各自从家出发到公司集合后,再同时出发到公园游玩,在指定地点集合后再同时开始就餐,…。
CountDownLatch: 犹如倒计时计数器,调用CountDownLatch对象的countDown方法就将计数器减1,当计数到达0时,则所有等待者或单个等待者开始执行。
这直接通过代码来说明CountDownLatch的作用,这样学员的理解效果更直接。 可以实现一个人(也可以是多个人)等待其他所有人都来通知他,
这犹如一个计划需要多个领导都签字后才能继续向下实施。还可以实现一个人通知多个人的效果,类似裁判一声口令,运动员同时开始奔跑。用这个功能做百米赛跑的游戏程序不错哦! Exchanger: 用于实现两个人之间的数据交换,每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据
4.7 可阻塞的队列
ArrayBlockingQueue 只有put方法和take方法才具有阻塞功能
BlockingQueue: 实现主要用于生产者-使用者队列
BlockingQueuez: 实现是线程安全的
作用:部分线程负责生产线,生产的产品数量固定,生产足够后,等待部分线程负责消费,然后生产线在补充生产,如此下去
class Producer implements Runnable { private final BlockingQueue queue; Producer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { queue.put(produce()); } } catch (InterruptedException ex) { ... handle ...} } Object produce() { ... } } class Consumer implements Runnable { private final BlockingQueue queue; Consumer(BlockingQueue q) { queue = q; } public void run() { try { while(true) { consume(queue.take()); } } catch (InterruptedException ex) { ... handle ...} } void consume(Object x) { ... } } class Setup { void main() { BlockingQueue q = new SomeQueueImplementation(); Producer p = new Producer(q); Consumer c1 = new Consumer(q); Consumer c2 = new Consumer(q); new Thread(p).start(); new Thread(c1).start(); new Thread(c2).start(); } }