java 基础 日积月累

 

 

Eclipse version:

Eclipse Java EE IDE for Web Developers.

 

Version: Kepler Service Release 1

Build id: 20130919-0819

 

反射获取目标class的目标属性泛型实际类型

(参考资料:Java反射与动态代理):

 

 

package com.tch.test.testextend;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class GetGenericActualTypeTest {

    public static void main(String[] args) {
        getGenericActualType(User.class, "username");
        getGenericActualType(User.class, "friends");
        getGenericActualType(User.class, "friendUsername");
        getGenericActualType(User.class, "friendNameMap");
    }
    
    public static void getGenericActualType(Class<?> clazz, String fieldName){
        System.out.println("begin to getGenericActualType for field: " + fieldName);
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        if(field != null){
            /**
             * 如果field是一个普通的属性,不带有泛型,则getGenericType() 和 getType()的结果一样,都是该field的类型
             * 如果field是一个带有泛型的属性,则getGenericType()得到的是泛型类型,需要类型转换为ParameterizedType, 和getType()的结果就不一样了
             */
            
            // 拿到属性的泛型类型(比如List<String> list, 得到的就是String)
            Type genericType = field.getGenericType();
            // getType() 得到的是属性的类型
            Type type = field.getType();
            System.out.println("fieldName: " + fieldName + ", genericType equals type? " + genericType.toString().equals(type.toString()));
            if(genericType instanceof ParameterizedType){
                // 获取泛型的实际类型
                Type[] actualTypes = ((ParameterizedType) genericType).getActualTypeArguments();
                if(actualTypes.length > 0){
                    for(Type actualType : actualTypes){
                        // 类型转为Class
                        Class<?> actualClass = (Class<?>) actualType;
                        System.out.println(actualClass);
                    }
                }
            }
        }
        
        System.out.println();
        System.out.println();
    }
    
    class User{
        private int age;
        private String username;
        private List<User> friends;
        private List<String> friendUsername;
        private Map<String, User> friendNameMap;
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public List<User> getFriends() {
            return friends;
        }
        public void setFriends(List<User> friends) {
            this.friends = friends;
        }
        public List<String> getFriendUsername() {
            return friendUsername;
        }
        public void setFriendUsername(List<String> friendUsername) {
            this.friendUsername = friendUsername;
        }
        public Map<String, User> getFriendNameMap() {
            return friendNameMap;
        }
        public void setFriendNameMap(Map<String, User> friendNameMap) {
            this.friendNameMap = friendNameMap;
        }
        
    }
    
}

  

 

import java.util.List;

public class Class1 {

	private List<String> list;
	private String name1;
	private void add(){
		System.out.println("add---");
	}
	
}

 

 

 

package com.tch.test.concurrent;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class ReturnTest {
	private int i;
	public static void main(String[] args) throws Exception{
		m1("name1", Class1.class);
	}
	/**
	 *  Created on: 			2013-11-27 
	 * <p>Discription:			反射获取目标class的目标属性泛型实际类型</p>
	 * @param fieldName 	属性名
	 * @param clazz 			目标Class对象
	 * @return 				void
	 */
	public static <T> void m1(String fieldName,Class<T> clazz){
		try {
			Field field = clazz.getDeclaredField(fieldName);
			Type type = field.getGenericType(); 
			if (type instanceof ParameterizedType) {     
			    ParameterizedType paramType = (ParameterizedType) type;     
			    Type[] actualTypes = paramType.getActualTypeArguments();     
			    for (Type aType : actualTypes) {         
			        if (aType instanceof Class<?>) {         
			            Class<?> clz = (Class<?>) aType;             
			            System.out.println(clz.getName()); 
			        }     
			    } 
			} 
		}catch (Exception e) {
			e.printStackTrace();
		} 
	}
		
}

 

 

 

访问私有方法:

 

	public static void callHiddenMethod(Object a, String methodName) throws Exception {
	    Method g = a.getClass().getDeclaredMethod(methodName);
	    g.setAccessible(true);
	    g.invoke(a);
	}

 

 获取目标Class对象的实际父类泛型类型:

public class Father<T> {

}

 

public class Child extends Father<String>{

}

 

import java.lang.reflect.ParameterizedType;


public class GenericUtils {

	/**
	 *  Created on: 			2013-11-27 
	 * <p>Discription:			获取目标Class对象的实际父类泛型类型</p>
	 * @param clazz			目标Class对象
	 * @return 				Class<T>
	 */
	@SuppressWarnings("unchecked")
	public static <T> Class<T> getGenericType(Class<T> clazz){
		return (Class<T>)((ParameterizedType)clazz.getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
}

 测试方法:

	public static void main(String[] args) throws Exception {
		System.out.println(GenericUtils.getGenericType(Child.class));
	}

 

 

快速排序 / 冒泡排序:

 

package com.tch.test;

public class QuickSort {
	public void quickSort(int[] arr, int from, int to) {
		if(from >= to){
			return;
		}
		int left = from;
		int right = to;
		int tmp = arr[from];
		while(left < right){
			while(right > left){
				if(arr[right] < tmp){
					arr[left] = arr[right];
					break;
				}
				right --;
			}
			while(left < right){
				if(arr[left] > tmp){
					arr[right] = arr[left];
					break;
				}
				left++;
			}
		}
		arr[left] = tmp;
		quickSort(arr, from, left-1);
		quickSort(arr, right+1, to);
	}

	public void maopao(int[] arr){
		int length = arr.length;
		int tmp = 0;
		for(int i=0;i<length;i++){
			for(int j=(i+1);j<length;j++){
				if(arr[i] > arr[j]){
					tmp = arr[i];
					arr[i] = arr[j];
					arr[j] = tmp;
				}
			}
		}
	}
	
	public static void main(String[] args) {
		int[] arr = new int[] { 1,4,8,2,5,9,7,6,3,10 ,3,5,8,0,1,6 };
		QuickSort sort = new QuickSort();
		//sort.quickSort(strVoid, 0, arr.length - 1);
		sort.maopao(arr);
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + "  ");
		}
	}
}

 

 

 

读取一行:

	/**
	 *  Created on 2013-5-22 
	 * <p>Discription:读取一行内容</p>
	 * @param in 输入流
	 * @return String 读取到的一行内容
	 */
	public static String readLine(InputStream in){
		String result = null;
		try {
			byte[] b = new byte[1];
			int n = -1;
			while((n = in.read()) != -1){
				if(n == '\r' || n == '\n'){
					break;
				}else{
					b[b.length-1] = (byte)n;
					b = Arrays.copyOf(b, b.length+1);
				}
			}
			if(b.length <= 1){
				return null;
			}
			b = Arrays.copyOf(b, b.length-1);
			return new String(b,"utf-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

 

 

servlet下载pdf:

package com.tch.excel;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class ExportExcel extends HttpServlet {

	/**
	 * The doGet method of the servlet. <br>
	 *
	 * This method is called when a form has its tag value method equals to get.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	/**
	 * The doPost method of the servlet. <br>
	 *
	 * This method is called when a form has its tag value method equals to post.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("application/pdf");
		File file = new File("E:\\中文.pdf");
		response.addHeader("Content-Disposition", "attachment;"+new String(("filename=我的Excel.pdf").getBytes("GBK"), "ISO-8859-1")); 
		response.setContentLength((int) file.length());
		PrintWriter out = response.getWriter();
		FileReader in = new FileReader(file);
		char[] b = new char[10240];
		int n = -1;
		while((n=in.read(b)) != -1){
			out.write(b, 0, n);
		}
		out.flush();
		out.close();
	}

}

 

 

 

 下载excel::(只需要改contentType和文件后缀即可)

package com.tch.excel;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@SuppressWarnings("serial")
public class ExportExcel extends HttpServlet {

	/**
	 * The doGet method of the servlet. <br>
	 *
	 * This method is called when a form has its tag value method equals to get.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	/**
	 * The doPost method of the servlet. <br>
	 *
	 * This method is called when a form has its tag value method equals to post.
	 * 
	 * @param request the request send by the client to the server
	 * @param response the response send by the server to the client
	 * @throws ServletException if an error occurred
	 * @throws IOException if an error occurred
	 */
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("application/x-xls;charset=utf-8");
		response.addHeader("Content-Disposition", "attachment;"+new String(("filename=我的Excel.xls").getBytes("GBK"), "ISO-8859-1")); 
		PrintWriter out = response.getWriter();
		out.print(" 中文内容");
		out.flush();
		out.close();
	}

}

 

 

 下载word:(只需要改contentType和文件后缀即可)

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("application/msword;charset=utf-8");
		response.addHeader("Content-Disposition", "attachment;"+new String(("filename=我的Excel.doc").getBytes("GBK"), "ISO-8859-1")); 
		PrintWriter out = response.getWriter();
		out.print(" 中文内容");
		out.flush();
		out.close();
	}

 

 

 导出excel:

	static void export() throws Exception{
		HSSFWorkbook wb = new HSSFWorkbook();
	    Sheet sheet = wb.createSheet("007");
		HSSFCellStyle style = wb.createCellStyle();
		//背景颜色(注意不是setFillBackgroundColor)
		style.setFillForegroundColor(HSSFColor.WHITE.index);
		//背景颜色填充样式
		style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		//上下左右边框样式
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		//上下左右边框颜色
		style.setRightBorderColor(HSSFColor.GREY_25_PERCENT.index);
		style.setBottomBorderColor(HSSFColor.GREY_25_PERCENT.index);
		style.setLeftBorderColor(HSSFColor.GREY_25_PERCENT.index);
		style.setTopBorderColor(HSSFColor.GREY_25_PERCENT.index);
		//水平、垂直对齐方式
		style.setAlignment(HSSFCellStyle.ALIGN_LEFT);
		style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		
	    Row row = sheet.createRow((short) 1);

	    Cell cell = row.createCell((short) 1);
	    cell.setCellValue("X");
	    cell.setCellStyle(style);

	    cell = row.createCell((short) 2);
	    cell.setCellValue("X");
	    cell.setCellStyle(style);

	    FileOutputStream fileOut = new FileOutputStream("f:workbook.xls");
	    wb.write(fileOut);
	    fileOut.close();
	}

 

 

产生验证码(以servlet为例):

 

package com.tch.excel;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class AuthImage extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static char[] codeArr = new char[] {'a','b','c','d','e','f','g','h','i',
												   'j','k','l','m','n','o','p','q','r',
												   's','t','u','v','w','x','y','z','A',
												   'B','C','D','E','F','G','H','I','J',
												   'K','L','M','N','O','P','Q','R','S',
												   'T','U','V','W','X','Y','Z','0','1',
												   '2','3','4','5','6','7','8','9'};
	private Random random = new Random();
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		int length = codeArr.length;
		int width = 200;
		int height = 100;
		//存放生成的字符
		String code = "";
		//存放最终的字符组成的字符串验证码
		String validateCode = "";
		//构建BufferedImage对象,用来存储生成的验证码图片(临时存放在内存中)
		BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		//获取BufferedImage的Graphics对象,Graphics起着画笔的作用,用来写验证码及其它内容
		Graphics graphics = bufferedImage.getGraphics();
		//开始在BufferedImage对象上面涂背景色
		graphics.setColor(Color.white);
		graphics.fillRect(0, 0, width-1, height-1);
		//在BufferedImage对象上面画边框
		graphics.setColor(Color.black);
		graphics.drawRect(0, 0, width-1, height-1);
		//设置要画的字符串的字体
		graphics.setFont(new Font("Comic Sans MS",Font.PLAIN,70));
		for(int i=0;i<4;i++){
			//随机产生字符
			code=""+codeArr[random.nextInt(length)];
			//随机产生颜色
			graphics.setColor(getRandColor());
			//将字符写到BufferedImage对象上(Graphics最终是写到对应的BufferedImage对象上面)
			graphics.drawString(code, 5+i*50, 70);
			//添加到验证码字符串里面
			validateCode += code;
		}
		System.out.println("validateCode : "+validateCode);
		//释放画笔占用的资源
		graphics.dispose();
		//将生成的图片通过response的输出流返回给页面
		ImageIO.write(bufferedImage, "JPEG", response.getOutputStream());
	}
	//产生随机颜色
	private Color getRandColor() {
		Random random = new Random();
		Color color[] = new Color[10];
		color[0] = new Color(32, 158, 25);
		color[1] = new Color(218, 42, 19);
		color[2] = new Color(31, 75, 208);
		return new Color(random.nextInt(220), random.nextInt(220), random.nextInt(220));
	}

}

 然后在web.xml中配置该servlet,页面如下(xxx为项目名,servlet/authImage为servlet的映射路径):

<html>
<head>
<title>导出表格到PDF实例</title>
		<meta http-equiv="pragma" content="no-cache">
		<meta http-equiv="cache-control" content="no-cache">
		<meta http-equiv="expires" content="0">
		<script type="text/javascript" charset="utf-8">
			function refreshCode(obj){
				obj.src = 'http://localhost:8080/xxx/servlet/authImage?d='+(new Date().getTime());
			}
		</script>
	</head>
	<body id="dt_example">
		<a href="###"><img src="http://localhost:8080/xxx/servlet/authImage" width="60" height="25" onclick="refreshCode(this);"></a>
	</body>
</html>

 

 

 任务调度ScheduledExecutorService:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class ScheduledTask {
	private static SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss");
        UncaughtExceptionHandler exceptionHandler = null;
	private void task1() {
                exceptionHandler = new UncaughtExceptionHandler(){
			@Override
			public void uncaughtException(Thread t, Throwable e) {
				System.out.println("thread: "+t+" , throwable : "+e);
			}
		};
		ScheduledExecutorService executor = Executors.newScheduledThreadPool(2, new ThreadFactory() {
			@Override
			public Thread newThread(Runnable r) {
				Thread thread = new Thread(r);
                                thread.setUncaughtExceptionHandler(exceptionHandler);//异常处理
				return thread;
			}
		});
		//上次任务和下次任务的开始时间间隔为固定值(这里是6 s),不论任务本身执行多长时间,但是任务时间如果超过时间间隔,就会推迟下次任务的启动时间
		executor.scheduleAtFixedRate(new Task("AtFixedRate"), 0, 6, TimeUnit.SECONDS);
		//从上次任务结束到下次任务的开始时间间隔为固定值(这里是6 s),和任务本身的执行时间有关系
		executor.scheduleWithFixedDelay(new Task("WithFixedDelay"), 0, 6, TimeUnit.SECONDS);
	}
	public class Task implements Runnable {
		private String name;
		public Task(String name){
			this.name = name;
		}
		public void run(){
			System.out.println("线程 : "+name+" 启动"+format.format(new Date()));
			try {
				TimeUnit.SECONDS.sleep(3);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("线程 : "+name+"结束"+format.format(new Date()));
		}
	}
	public static void main(String[] args) {
		new ScheduledTask().task1();
	}

}

 

 

 2种方式实现生产着消费者:

一:使用比较低级的方式:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Test2 {
    public static void main(String[] args) throws InterruptedException {
    	Test2 t = new Test2();
    	Queue<Integer> container = new LinkedList<Integer>();
		ExecutorService e = Executors.newFixedThreadPool(3);
		e.execute(t.new Producer(container));
		e.execute(t.new Consumer(container));
		e.shutdown();
    }
    
    class Producer implements Runnable{
    	Queue<Integer> container;
		public Producer(Queue<Integer> container){
			this.container = container;
		}
		int i=0;
		Integer get(){
			i++;
			return i;
		}
		@Override
		public void run() {
			try {
				while(true){
					synchronized(container){
						while(container.size()>3){
							container.wait();
						}
						Integer j = get();
						container.add(j);
						System.out.println("生产了:"+j);
						container.notifyAll();
						Thread.sleep(500);
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	} 
	class Consumer implements Runnable{
		Queue<Integer> container;
		public Consumer(Queue<Integer> container){
			this.container = container;
		}
		@Override
		public void run() {
			try {
				while(true){
					synchronized(container){
						while(container.isEmpty()){
							container.wait();
						}
						Integer butter =container.poll();
						System.err.println("消费了: "+butter);
						container.notifyAll();
						Thread.sleep(500);
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

二:使用高级点,省事的方式:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;


public class Test {
	
	public static void main(String[] args) {
		Test t = new Test();
		LinkedBlockingQueue<Integer> container = new LinkedBlockingQueue<Integer>();
		ExecutorService e = Executors.newFixedThreadPool(3);
		e.execute(t.new Producer(container));
		e.execute(t.new Consumer(container));
		e.shutdown();
	}
	class Producer implements Runnable{
		LinkedBlockingQueue<Integer> container;
		public Producer(LinkedBlockingQueue<Integer> container){
			this.container = container;
		}
		int i=0;
		Integer get(){
			i++;
			return i;
		}
		@Override
		public void run() {
			try {
				while(true){
					Integer j = get();
					System.out.println("生产了:"+j);
					container.put(j);//LinkedBlockingQueue会自动处理容器为空或者过大的情况(会等待)
					Thread.sleep(500);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	} 
	class Consumer implements Runnable{
		LinkedBlockingQueue<Integer> container;
		public Consumer(LinkedBlockingQueue<Integer> container){
			this.container = container;
		}
		@Override
		public void run() {
			try {
				while(true){
					Integer butter =container.take();//LinkedBlockingQueue会自动处理容器为空或者过大的情况(会等待)
					System.err.println("消费了: "+butter);
					Thread.sleep(500);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

  

 

 标准jdbc连接步骤(使用了批处理,以及异常回滚):

void jdbc() throws Exception{
		Connection conn = null;
		PreparedStatement statement = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");//加载数据库驱动类
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");//获取连接
			statement = conn.prepareStatement("insert into coures(id,name,age) values(?,?,?)");//创建PreparedStatement
			conn.setSavepoint();//设置保存点
			conn.setAutoCommit(false);//关闭事务自动提交
			for(int i=0;i<100;i++){
				statement.setInt(1, i);//索引从 1 开始
				statement.setString(2, "tch");
				statement.setInt(3, 23);
				statement.addBatch();//添加到批处理
			}
			statement.executeBatch();//执行批处理
			conn.commit();//没有异常,提交事务
		} catch (Exception e) {
			if(conn != null){
				conn.rollback();//出现异常时,回滚到保存点
			}
			e.printStackTrace();
		}finally{//关闭资源
			if(statement != null){
				statement.close();
			}
			if(conn != null){
				conn.close();
			}
		}
	}

 

 

最简单的死锁:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
	Object o1 = new Object(),o2 = new Object(),o = new Object();
	public static void main(String[] args) throws Exception {
		final Test t = new Test();
		ExecutorService e = Executors.newFixedThreadPool(2);
		e.execute(new Runnable() {
			@Override
			public void run() {
				try {
					t.syn1();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		e.execute(new Runnable() {
			@Override
			public void run() {
				try {
					t.syn2();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
		e.shutdown();
	}
	void syn1() throws Exception{
		synchronized(o1){
			System.out.println("syn1 获得  o1  的锁");
			Thread.sleep(50);//让出CPU,让syn2有机会获得o2的锁
			synchronized(o2){
				System.out.println("syn1 获得  o2  的锁");
			}
		}
	}
	void syn2() throws Exception{
		synchronized(o2){
			System.out.println("syn2 获得  o2  的锁");
			Thread.sleep(50);//让出CPU,让syn1有机会获得o1的锁
			synchronized(o1){
				System.out.println("syn2 获得  o1  的锁");
			}
		}
	}
}

 

 

log4j配置:

log4j.properties

log4j.rootLogger=debug,stdout,DAILY_ROLLING_FILE

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

########################
# DailyRolling File
########################
log4j.appender.DAILY_ROLLING_FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DAILY_ROLLING_FILE.Append=true
log4j.appender.DAILY_ROLLING_FILE.Threshold=debug
log4j.appender.DAILY_ROLLING_FILE.Encoding=UTF-8

#通过读取系统变量来制定日志目标位置
log4j.appender.DAILY_ROLLING_FILE.File=${logDir}/log.txt
log4j.appender.DAILY_ROLLING_FILE.DatePattern='.'yyyy-MM-dd
log4j.appender.DAILY_ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.DAILY_ROLLING_FILE.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} [%c] %m%n

###################
# Console Appender
###################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=debug
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p (%c:%L) - %m%n

###################
#指定特定类的输出级别
###################
#指定struts2日志级别
log4j.logger.com.opensymphony.xwork2=info
log4j.logger.org.apache.struts2=info
#指定某个类的日志级别
log4j.logger.com.test.LogTest=info

 

 

 

getResourceAsStream、getResource用法:

 

public class ResourceTest {

	public static void main(String[] args) {
		//Class.getResource("path")
		//path不以/开头,表示和当前文件同目录
		System.out.println(ResourceTest.class.getResource("").getPath());
		//path以/开头,表示classpath路径
		System.out.println(ResourceTest.class.getResource("/").getPath());
		//ClassLoader.getResource("path")
		//path不需要以/开头,表示classpath路径
		System.out.println(ResourceTest.class.getClassLoader().getResource("").getPath());
		//这种方式也可以获取classpath路径
		System.out.println(ResourceTest.class.getProtectionDomain().getCodeSource().getLocation().getPath());
	}

}

 

 

 

注解的用法和处理(自定义注解、使用注解、处理注解)

 

web.xml加载顺序:

 

context-param -> listener -> filter -> servlet

 

web.xml中的listener的加载顺序由该listener在web.xml中的配置顺序决定,filter的顺序由web.xml中的filter-mapping顺序决定,servlet的顺序由web.xml中的servlet-mapping顺序决定

 

	<listener>
		<listener-class>com.tch.Listener2</listener-class>
	</listener>
	<listener>
		<listener-class>com.tch.Listener1</listener-class>
	</listener>
  

 

可以看出先执行2,2等待3 s之后执行1,1在等待3 s,完全是线性执行的。

 

 

Listerner1:

 

package com.tch;

import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class Listener1 implements ServletContextListener {

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		System.out.println("1 destroy");
	}

	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		System.out.println("1 init");
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("1 sleep complete");
	}

}
Listener2: 
package com.tch;

import java.util.concurrent.TimeUnit;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class Listener2 implements ServletContextListener {

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		System.out.println("2 destroy");
	}

	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		System.out.println("2 init");
		try {
			TimeUnit.SECONDS.sleep(3);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("2 sleep complete");
	}

}

 

 

spring aop (自定义切面aspect,注意需要aspectjweaver.jar,aspectjrt.jar,cglib-nodep-2.1_3.jar,前两个用于实现了接口的类的代理,后者用于没有实现接口的类的代理):

    定义接口:

package com.tch.aspect;  
  
public interface PersonService {  
    public int save(String name) throws Exception;  
    public void update(String name, Integer id);  
    public String getPersonName(Integer id);  
}

   实现类:

package com.tch.aspect;

import org.springframework.stereotype.Component;

@Component("personService")
public class PersonServiceBean implements PersonService{  
  
    public String getPersonName(Integer id) {  
        System.out.println("我是getPersonName()方法");  
        return "xxx";  
    }  
  
    public int save(String name) {  
    //throw new RuntimeException("我爱例外");  
        //int i = 10/0;  
        System.out.println("我是save()方法");  
             return 0;  
    }  
  
    public void update(String name, Integer id) {  
        System.out.println("我是update()方法");  
    }  
}

   自定义切面:

 


package com.tch.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 切面 * */ @Aspect //声明一个切面 @Component("myInterceptor") public class MyInterceptor { @Pointcut("execution (* com.tch.aspect.PersonServiceBean.*(..))") private void anyMethod() {}//声明一个切入点 @Before("anyMethod() && args(name)")//定义前置通知,拦截的方法不但要满足声明的切入点的条件,而且要有一个String类型的输入参数,否则不会拦截 public void doAccessCheck(String name) { System.out.println("前置通知:"+ name); } @AfterReturning(pointcut="anyMethod()",returning="result") //定义后置通知,拦截的方法的返回值必须是int类型的才能拦截 public void doAfterReturning(int result) { System.out.println("后置通知:"+ result); } @AfterThrowing(pointcut="anyMethod()",throwing="e") //定义例外通知 public void doAfterThrowing(Exception e) { System.out.println("例外通知:"+ e); } @After("anyMethod()") //定义最终通知 public void doAfter() { System.out.println("最终通知"); } @Around("anyMethod()") //定义环绕通知 public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { //if(){//判断用户是否在权限 System.out.println("进入方法"); Object result = pjp.proceed();//当使用环绕通知时,这个方法必须调用,否则拦截到的方法就不会再执行了 System.out.println("退出方法"); //} return result; } }

 beans.xml:

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:context="http://www.springframework.org/schema/context"   
       xmlns:aop="http://www.springframework.org/schema/aop"        
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
       <context:component-scan base-package="com.tch.aspect"></context:component-scan>
       <aop:aspectj-autoproxy/>   
</beans> 

 测试类:

 

 

package com.tch.aspect;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAOPTest {  
  
    public static void main(String[] args) throws Exception {  
        ApplicationContext cxt = new ClassPathXmlApplicationContext("com/tch/aspect/beans.xml");  
        PersonService personService = (PersonService)cxt.getBean("personService");  
        //PersonServiceBean personService = (PersonServiceBean)cxt.getBean("personService");  
        //PersonService personService = new PersonServiceBean();  
        personService.save("xx");  
        //personService.getPersonName(90);  
    }
}

 

 

 CountDownLatch用法:

 

package com.tch.test.concurrent.test;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchTest {
	/** 线程数 */
	private int num = 3;
	private Random random = new Random();
	/** 开始运行的计数器 */
	private CountDownLatch begin = new CountDownLatch(1);
	/** 所有线程签到的计数器 */
	private CountDownLatch end = new CountDownLatch(num);
	private ExecutorService executor = Executors.newFixedThreadPool(5);
	
	public static void main(String[] args) {
		new CountDownLatchTest().test();
	}

	private void test() {
		try {
			doTask();
			System.out.println( "开始 ");
			//发出开始运行的信号
			begin.countDown();
			//主线程等待end计数器减到0,也就是所有线程都完成签到(end.countDown())
			end.await();
			System.out.println("结束 "+System.currentTimeMillis());
			executor.shutdown();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	private void doTask(){
		for(int i=0;i<num;i++){
			executor.execute(new Task(i));
		}
	}
	
	class Task implements Runnable{
		private int id;
		public Task(int id){
			this.id = id;
		}
		@Override
		public void run() {
			try {
				//等待begin的计数器减到0,导致当前线程进入阻塞状态
				begin.await();
				Thread.sleep(random.nextInt(1500));
				System.out.println("线程"+id+"结束"+System.currentTimeMillis());
				//向end计数器报到,end计时器减一
				end.countDown();
				//等待end计数器减到0,也就是等待所有线程都完成
				end.await();
				System.out.println("全部线程结束 "+System.currentTimeMillis());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

 

 

 CyclicBarrier用法:

 

package com.tch.test.concurrent.test;

import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierTest {
	private CyclicBarrier barrier;
	/** 线程数 */
	private int num = 3;
	private Random random = new Random();
	private ExecutorService executor = Executors.newFixedThreadPool(5);

	public static void main(String[] args) {
		new CyclicBarrierTest().test();
	}

	private void test() {
		barrier = new CyclicBarrier(num, new Runnable() {
			@Override
			public void run() {
				System.out.println("全部签到完成"+System.currentTimeMillis());
				System.out.println(barrier.getNumberWaiting()+"  "+barrier.getParties());
				//barrier.reset();
				System.out.println("--------------重新开始------------");
				doTask();
			}
		});
		doTask();
		barrier.reset();
		//executor.shutdown();
	}
	//barrier.reset();
	private void doTask(){
		for(int i=0;i<num;i++){
			executor.execute(new Task(i));
		}
	}
	
	class Task implements Runnable{
		private int id;
		public Task(int id){
			this.id = id;
		}
		@Override
		public void run() {
			try {
				Thread.sleep(random.nextInt(1500));
				System.out.println("线程"+id+"结束"+System.currentTimeMillis());
				barrier.await();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

 

 根据 HttpServletRequest获取DomainPath : 

 

	/**
	 * 根据 HttpServletRequest获取DomainPath
	 */
	public static String getDomainPath(HttpServletRequest request) {
		String path = request.getContextPath();
		String basePath = request.getScheme() + "://" + request.getServerName()
				+ ":" + request.getServerPort() + path + "/";
		return basePath;
	}

 

 

容易忽略的知识点:

 

1.多态通常指的是方法的多态,一般不包含属性的多态,因为属性的访问在编译期间就已经确定了:

 

package test.extend;

public class Father {

	public int field = 1;
	
}
 
package test.extend;

public class Child extends Father{

	public int field = 9;
	
}
 
package test;

import test.extend.Child;
import test.extend.Father;


public class Test {

	public static void main(String[] args) throws Exception {
		Father f = new Child();
		System.out.println(f.field);
		Child f2 = new Child();
		System.out.println(f2.field);
	}
	
}
 

 

 第一个的输出结果是父类的值:1,第二个的输出结果是子类的值:9   

 

 2.私有方法不能被覆盖,也就不存在私有方法的多态:

 

 

package test.extend;

public class Father {

	private void m(){
		System.out.println("father  method  m");
	}
	
	public void p(){
		System.out.println("father method p");
	}

	/**
	 * Create Date:		2014-1-6下午9:13:51
	 * @author:			阿O、不拽
	 * @param args
	 */
	public static void main(String[] args) {
		Father f = new Child();
		//这里访问的是父类的m方法,因为方法m是私有的,不能被覆盖
		f.m();
		//这里访问的是子类的p方法,因为方法p不是私有的,可以被覆盖
		f.p();
	}
}

 

package test.extend;

public class Child extends Father{

	public void m(){
		System.out.println("child method m");
	}

	public void p(){
		System.out.println("child method p");
	}
	
}

 输出的结果:

father  method  m

child method p

 

这里在子类的方法m其实是一个新的方法,跟父类的m方法没有任何关系了。

 

 3.子类继承的时候,构造方法的问题:在构造方法还未完成的时候,执行操作,这时候对象还没有初始化完成,会出现未知的问题,例如:

package test.extend;

public class Father {

	public Father(){
		System.out.println("Father  before draw");
		draw();
	}
	
	public void draw(){
		System.out.println("father  method  draw");
	}
	
}
package test.extend;

public class Child extends Father{

	public int field = 9;
	
	public Child(int r){
		field = r;
		System.out.println("child : field="+field);
	}
	
	public void draw(){
		System.out.println(" child draw : field="+field);
	}
	
}
package test;

import test.extend.Child;


public class Test {

	public static void main(String[] args) throws Exception {
		new Child(10);
	}
	
}

 

该示例的流程如下:在执行子类构造方法之前,需要先执行父类的构造方法,父类构造方法执行的时候,调用了draw方法,因为多态的因素,调用的是子类的draw方法,此时子类的属性还未初始化,所以是0,然后执行子类构造方法,此时子类的属性已经初始化,值就是10了

 

下面顺便记录下初始化的基本流程:

 

1.初始化父类静态代码

2.初始化子类静态代码

3.初始化父类非静态代码

4.初始化父类构造方法

5.初始化子类非静态代码

6.初始化子类构造方法

 

根据上面的流程,就可以清晰的执行判断流程了。

 

 

 

ZIP 简单压缩解压(简单实现,不严谨,仅作学习使用):

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.Enumeration;
import java.util.zip.Adler32;
import java.util.zip.CheckedInputStream;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;


public class ZipCompress {

	/**
	 * 将给定路径的文件列表sourceFileDirs压缩为zip文件,保存到指定路径destFileDir
	 * Create Date:		2014-1-6下午11:15:36
	 * @author:			阿O、不拽
	 * @param sourceFileDirs 要压缩的文件路径列表
	 * @param destFileDir    压缩后的文件保存的路径
	 * @throws Exception
	 */
	public static void zipCompress(String[] sourceFileDirs,String destFileDir) throws Exception{
		FileOutputStream f = new FileOutputStream(destFileDir);
		CheckedOutputStream csum = new CheckedOutputStream(f, new Adler32());
		ZipOutputStream zos = new ZipOutputStream(csum);
		BufferedOutputStream out = new BufferedOutputStream(zos);
		zos.setComment("A test of Java Zipping");
		for (String fileDir : sourceFileDirs) {
			BufferedReader in = new BufferedReader(new FileReader(fileDir));
			zos.putNextEntry(new ZipEntry(fileDir));
			int c;
			while ((c = in.read()) != -1)
				out.write(c);
			in.close();
			out.flush();
		}
		out.close();
	}
	
	/**
	 * 解压文件到指定目录
	 * Create Date:		2014-1-6下午11:48:31
	 * @author:			阿O、不拽
	 * @param srcFileDir	要解压的压缩文件
	 * @param destFolder 解压的目标文件夹
	 * @throws Exception
	 */
	public static void zipDeCompress(String srcFileDir,String destFolder) throws Exception{
		FileInputStream fi = new FileInputStream(srcFileDir);
		CheckedInputStream csumi = new CheckedInputStream(fi, new Adler32());
		ZipInputStream in2 = new ZipInputStream(csumi);
		BufferedInputStream bis = new BufferedInputStream(in2);
		ZipEntry ze;
		byte[] b = new byte[20480];
		int n = -1;
		File destFile = null;
		BufferedOutputStream out = null;
		while ((ze = in2.getNextEntry()) != null) {
			destFile = new File(generateFullFileName(destFolder,getSimpleName(ze.getName())));
			if(! destFile.getParentFile().exists()){
				destFile.getParentFile().mkdirs();
			}
			if(! destFile.exists()){
				destFile.createNewFile();
			}
			out = new BufferedOutputStream(new FileOutputStream(destFile), 20480);
			while ((n = bis.read(b)) != -1){
				out.write(b, 0, n);
				out.flush();
			}
			out.flush();
			out.close();
		}
		bis.close();
	}
	
	/**
	 * 解压文件到指定目录
	 * Create Date:		2014-1-6下午11:48:31
	 * @author:			阿O、不拽
	 * @param srcFileDir	要解压的压缩文件
	 * @param destFolder 解压的目标文件夹
	 * @throws Exception
	 */
	public static void zipDeCompress2(String srcFileDir,String destFolder) throws Exception{
		FileInputStream fi = new FileInputStream(srcFileDir);
		CheckedInputStream csumi = new CheckedInputStream(fi, new Adler32());
		ZipInputStream in2 = new ZipInputStream(csumi);
		BufferedInputStream bis = new BufferedInputStream(in2);
		ZipFile zf = new ZipFile(srcFileDir);
		Enumeration<?> e = zf.entries();
		byte[] b = new byte[20480];
		int n = -1;
		File destFile = null;
		BufferedOutputStream out = null;
		while (e.hasMoreElements()) {
			ZipEntry ze = (ZipEntry) e.nextElement();
			destFile = new File(generateFullFileName(destFolder,getSimpleName(ze.getName())));
			if(! destFile.getParentFile().exists()){
				destFile.getParentFile().mkdirs();
			}
			if(! destFile.exists()){
				destFile.createNewFile();
			}
			out = new BufferedOutputStream(new FileOutputStream(destFile), 20480);
			while ((n = bis.read(b)) != -1){
				out.write(b, 0, n);
				out.flush();
			}
			out.flush();
			out.close();
		}
		zf.close();
		bis.close();
	}
	
	public static String getSimpleName(String name){
		int index = Math.max(name.lastIndexOf("/"), name.lastIndexOf("\\"));
		return name.substring(index+1);
	}
	
	public static String generateFullFileName(String folder,String fileName){
		if(! folder.endsWith("/") && ! folder.endsWith("\\")){
			folder += File.separator;
		}
		System.out.println(folder+fileName);
		return folder+fileName;
	} 
	
	public static void main(String[] args) throws Exception {
		//zipDeCompress("E:\\test.zip", "e:/decompress");
		zipDeCompress2("E:\\test.zip", "e:/decompress");
	}
	
}

 

 

JAVA-JSON 处理:

 

public static String pack(Object result,JsonResultType type){
		Map<Object,Object> rt=new HashMap<Object,Object>();
		rt.put("result", result);
		JSONArray jsonArray = JSONArray.fromObject(rt);
		String jsonResult = jsonArray.toString();
		return jsonResult;
	}

 

 java生成GUID:

 

/**
	 * 获取UUID
	 * <p>Created on 2014-2-17 </p>
	 * @return
	 */
	public static String getUUID(){ 
        return UUID.randomUUID().toString(); 
    } 
	/**
	 * 去掉UUID中间的 “-” 
	 * <p>Created on 2014-2-17 </p>
	 * @return
	 */
	public static String getUUID2(){ 
        String s = UUID.randomUUID().toString(); 
        //去掉“-”符号 
        return s.substring(0,8)+s.substring(9,13)+s.substring(14,18)+s.substring(19,23)+s.substring(24); 
    } 

 

 

 总结equals和hashcode方法在HashMap中的作用:

 

先说put的过程,首先根据hashcode计算出在hash表中的bucket(固定大小的数组,个人推测),然后查看该bucket的容量是否已满,如果不满,就将该数据添加进去,如果满了,就根据一些参数扩大bucket的容量

 

然后是get的过程,首先是根据key计算出的hash码找到对应的bucket,然后看看这个bucket里面有多少数据,如果只有一个就直接取出,多于一个就根据equals遍历取出结果

 

最适合作为key的是String和Integer,当然其他的自定义对象也可以,不过自定义对象最好重写equals和hashcode方法,这样可以让元素在hash表中分布比较分散,提高读写效率。

 

 

接下来说说volatile 

在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。

 

 

然后说说ConcurrentHashMap

 

以及 深入剖析ConcurrentHashMap(2)

分析了在get的同时,如果另外的线程正在执行 put/remove 的操作的话,是什么样的情况。

 

ConcurrentHashMap效率比HashTable高,是因为ConcurrentHashMap是通过将数据分段,然后用不同的锁来锁定不同分段数据,每个锁只负责对应那一段数据的读写操作,对其中一段数据读写的时候,其它数据仍可以读写,不影响。而HashTable则是所有方法加synchronized关键字加锁。

 

get操作的高效之处在于整个get过程不需要加锁,除非读到的值是空的才会加锁重读,我们知道HashTable容器的get方法是需要加锁的,那么ConcurrentHashMap的get操作是如何做到不加锁的呢?原因是它的get方法里将要使用的共享变量都定义成volatile,如用于统计当前Segement大小的count字段和用于存储值的HashEntry的value。定义成volatile的变量,能够在线程之间保持可见性,能够被多线程同时读,并且保证不会读到过期的值,但是只能被单线程写(有一种情况可以被多线程写,就是写入的值不依赖于原值),在get操作里只需要读不需要写共享变量count和value,所以可以不用加锁。之所以不会读到过期的值,是根据java内存模型的happen before原则,对volatile字段的写入操作先于读操作,即使两个线程同时修改和获取volatile变量,get操作也能拿到最新的值,这是用volatile替换锁的经典应用场景。

 

 

 

自定义一个LinkedList,并自己实现其reverse方法:

 

 

package com.tch.test.test;

public class T {

	public static void main(String[] args) {
		MyLinkedList list = new MyLinkedList();
		list.add(new Node("1"));
		list.add(new Node("2"));
		list.add(new Node("3"));
		list.add(new Node("4"));
		list.add(new Node("5"));
		list.add(new Node("6"));
		System.out.println("反转前--------");
		Node n = list.getTop();
		System.out.println(n.getObj());
		while(n.getNextNode() != null){
			System.out.println(n.getNextNode().getObj());
			n = n.getNextNode();
		}
		reverse(list);
		System.out.println("反转后--------");
		n = list.getTop();
		System.out.println(n.getObj());
		while(n.getNextNode() != null){
			System.out.println(n.getNextNode().getObj());
			n = n.getNextNode();
		}
	}
	
	/**
	 * 将指定的list反转 
	 * <p>Created on 2014-3-19 </p>
	 * @param list 需要进行反转的list
	 */ 
	public static void reverse(MyLinkedList list){
		//从头开始调用递归进行反转
		resursiveReverse(list.getTop(),list.getTop().getNextNode(),list);
	}
	/**
	 * 递归进行反转
	 * <p>Created on 2014-3-19 </p>
	 * @param pre 前一个节点
	 * @param next 后一个节点
	 * @param list 需要进行反转的list
	 */
	public static void resursiveReverse(Node pre,Node next,MyLinkedList list){
		//如果nextNode为null,说明到达最后的节点了
		if(next.getNextNode() == null){
			next.setNextNode(pre);
			list.getTop().setNextNode(null);
			list.setTop(next);
		}else{
			//未到达最后节点,递归
			resursiveReverse(next,next.getNextNode(),list);
			//递归完成之后将当前的两个节点反转(通过将后一个节点的nextNode执行前一个节点实现)
			next.setNextNode(pre);
		}
	}
	
}
/**
 * Created on 2014-3-19
 * <p>Description: 自定义节点</p>
 */
class MyLinkedList{
	/**
	 * 指向list的最上面的元素
	 */
	private Node top;
	public void add(Node n){
		n.setNextNode(top);
		top = n;
	}
	public Node getTop() {
		return top;
	}
	public void setTop(Node top) {
		this.top = top;
	}
	
}
class Node{
	/**
	 * 存放元素的内容
	 */
	private Object obj;
	/**
	 * 存放下一个元素的引用
	 */
	private Node nextNode;
	
	public Node(Object obj) {
		super();
		this.obj = obj;
	}
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
		this.obj = obj;
	}
	public Node getNextNode() {
		return nextNode;
	}
	public void setNextNode(Node nextNode) {
		this.nextNode = nextNode;
	}
	
}

 

 DbVisualizer

 

查看数据库关系的工具.

 

检查是否两个时间段有重叠:

 

 

public static boolean overlapWithEachOther(Date startTime, Date stopTime, Date theOtherStartTime, Date theOtherStopTime) {
        if(startTime == null && stopTime == null){
            throw new IllegalArgumentException("startTime&stopTime can not be null at the same time");
        }
        if(theOtherStartTime == null && theOtherStopTime == null){
            throw new IllegalArgumentException("startTime&stopTime can not be null at the same time");
        }
        if(startTime == null || stopTime == null){
            if(startTime == null){ // means startTime(null) and stopTime(not-null)
                if(! (theOtherStartTime != null && ! theOtherStartTime.before(stopTime))){
                    // has overlap
                    return true;
                }
            }else{ // means startTime(not-null) and stopTime(null)
                if(! (theOtherStopTime != null && ! theOtherStopTime.after(startTime))){
                    // has overlap
                    return true;
                }
            }
        }
        if(theOtherStartTime == null || theOtherStopTime == null){
            if(theOtherStartTime == null){ // means theOtherStartTime(null) and theOtherStopTime(not-null)
                if(! (startTime != null && ! startTime.before(theOtherStopTime))){
                    // has overlap
                    return true;
                }
            }else{ // means theOtherStartTime(not-null) and theOtherStopTime(null)
                if(! (stopTime != null && ! stopTime.after(theOtherStartTime))){
                    // has overlap
                    return true;
                }
            }
        }
        if(startTime != null && stopTime != null && theOtherStartTime != null && theOtherStopTime != null){
            if(theOtherStartTime.before(startTime) && theOtherStopTime.after(startTime)){
                return true;
            }
            if(! theOtherStartTime.before(startTime) && theOtherStartTime.before(stopTime)){
                return true;
            }
        }
        return false;
    }

 

JAVA中float  double 加减乘除操作中,出现的精度问题:

 

 

        double d = (2.8 - 2.0);
        System.out.println(d);
        
        float f = (2.8f - 2.0f);
        System.out.println(f);

 

输出的结果是:

 

 

0.7999999999999998
0.79999995

 

 

要解决这个问题,只需要用(注意要使用BigDecimal String的构造方法,这个方法可以保证精度):

 

BigDecimal(String.valueOf(value));

 

的格式即可。

例如:

 

 

        BigDecimal b2 = new BigDecimal(String.valueOf(a)).subtract(new BigDecimal(String.valueOf(b)));
        System.out.println(b2);

 

结果就是:

 

 

2.8

 

 

instanceof/isInstance/isAssignableFrom 用法

 

        String s = "abc";
        // instanceof: object is an instance of the class
        System.out.println(s instanceof String);
        System.out.println(s instanceof Object);
        // Class.isInstance
        System.out.println(String.class.isInstance(s));
        System.out.println(Object.class.isInstance(s));
        // Class.isAssignableFrom
        System.out.println(Object.class.isAssignableFrom(s.getClass()));
        System.out.println(String.class.isAssignableFrom(s.getClass()));

 

Java中堆和栈:

public static void main(String[] args) throws Exception {
        m(1);
    }
    
    
    
    private static void m(int i){
        m(i);
    }

 

这样无限循环的,会出现StackOverflowError.(基本类型数据值是在栈中存储,栈空间不足的时候,就出现StackOverflowError)

 

但是下面这样:

public static void main(String[] args) throws Exception {
        m(new byte[1024000]);
    }
    
    private static void m(byte[] i){
        m(new byte[1024000]);
    }

 

这样会出现OutOfMemoryError。(因为new byte[xxx]是在堆中存放,占用空间不足的时候,就会出现OutOfMemoryError)

 

 

java正则表达式匹配超链接,例如String testStr = "<a href=\"www.baidu1.com\">  </a>  <a href=\"www.baidu2.com\">  </a>  <a href=\"www.baidu3.com\">  </a>";

要匹配出超链接,得到下面的结果:

<a href="www.baidu1.com">  </a>

<a href="www.baidu2.com">  </a>

<a href="www.baidu3.com">  </a>

 

刚开始最简单的使用了<a .*</a>来匹配,结果发现得到的结果是:

<a href="www.baidu1.com">  </a>  <a href="www.baidu2.com">  </a>  <a href="www.baidu3.com">  </a>

 

就是说其实后面的</a>匹配到了字符串的最后一个</a>,有点类似恶汉的感觉,而我想要的是懒汉的结果,拿到第一个匹配的,就返回,而不是最后一个匹配的。

 

搞了好久,最后发现只需要稍加改动,就可以达到所谓的懒汉匹配:

<a .*?</a>

没错,就是在.*后面加个?就可以了。参考资料:Java 正则中的(.*?)vs.*)的区别

 

代码:

 

package com.tch.test;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TestRegExp {

	public static void main(String[] args) throws IOException {
		String testStr = "<a href=\"www.baidu1.com\">  </a>  <a href=\"www.baidu2.com\">  </a>  <a href=\"www.baidu3.com\">  </a>";
		String regex = "<a .*?</a>";
//		String regex = "<a .*?href.*?>.*?</a>";
		Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
		Matcher matcher = p.matcher(testStr);
		while (matcher.find()) {
			System.out.println(matcher.group(0));
//			int gc = matcher.groupCount();
//			for (int i = 0; i <= gc; i++) {
//				System.out.println("group " + i + " :" + matcher.group(i));
//			}
		}
	}

}

 

 

 

 

 

 

你可能感兴趣的:(java,总结,知识点,收集,日积月累)