首页 > 技术文章 > java-高新技术总结

beyondbycyx 2015-07-16 10:22 原文

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

  

 

推荐阅读