java小技巧-2

1,Java多线程

http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html

1.1 继承Thread类

/**
 * @author 继承Thread类,直接调用run方法
 * */
class hello extends Thread {
    private String name;
 
    public hello() {
    }
 
    public hello(String name) {
        this.name = name;
    }
 
    public void run() {
        System.out.println(name + "运行");
    }
 
    public static void main(String[] args) {
        Thread h1=new hello("A");
        Thread h2=new hello("B");
        h1.start();//注意是start方法启动,而不是run
        h2.start();
    }
}

1.2 实现Runnable接口

/**
 * @author 实现Runnable接口
 * */
class hello implements Runnable {
    private String name;

    public hello() {
    }

    public hello(String name) {
        this.name = name;
    }

    public void run() {
        System.out.println(name + "运行");
    }

    public static void main(String[] args) {
        Thread h1=new Thread(new hello("A"));//注意是代理模式
        Thread h2=new Thread(new hello("B"));
        h1.start();
        h2.start();
    }
}


其实Thread也是实现Runnable接口的。

1.3 Thread和Runnable的区别

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

/**
 * @author 继承Thread类,不能资源共享
 * */
class hello extends Thread {

    private int count = 5;

    public void run() {
       System.out.println("count= " + count--);
    }

    public static void main(String[] args) {
        hello h1 = new hello();//主要是因为这里的原因,单独的建立了一个线程
        hello h2 = new hello();
        hello h3 = new hello();
        h1.start();
        h2.start();
        h3.start();
    }
}

在上述程序中,每个线程都会输出5,而不会有线程输出4

class hello implements Runnable{

    private int ticket = 100;  //100张票

    public void run() {
       while(true){
            if (this.ticket > 0) {
                System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);
                try {
               Thread.sleep(1000);//线程休眠
            } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
            }
            }
            else{
               break;
            }
        }
    }
    public static void main(String [] args) {
        hello my = new hello();
        new Thread(my, "1号窗口").start();
        new Thread(my, "2号窗口").start();
        new Thread(my, "3号窗口").start();
    }
}

由于这里new Thread(my,),故可以共享。实际上与Runnable还是extends无关,可能Runnable更适合这么写。



2,Java线程池

http://www.cnblogs.com/jersey/archive/2011/03/30/2000231.html

2.1 创建线程池的静态方法

java.util.concurrent.Executors类的API提供大量创建连接池的静态方法:

newSingleThreadExecutor:

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

newFixedThreadPool:

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool:

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

newScheduledThreadPool:

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

newSingleThreadExecutor:

创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

2.2 固定大小的线程池

对于以下两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。一旦池中有线程完毕,则排队等待的某个线程会入池执行。

package BackStage;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class JavaThreadPool {
    public static void main(String[] args) {
	// 创建一个可重用固定线程数的线程池
	ExecutorService pool = Executors.newFixedThreadPool(2);
	// 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
	Thread t1 = new MyThread();
	Thread t2 = new MyThread();
	Thread t3 = new MyThread();
	Thread t4 = new MyThread();
	Thread t5 = new MyThread();
	// 将线程放入池中进行执行
	pool.execute(t1);
	pool.execute(t2);
	pool.execute(t3);
	pool.execute(t4);
	pool.execute(t5);
	// 关闭线程池
	pool.shutdown();
    }
}
class MyThread extends Thread {
    @Override
    public void run() {
	System.out.println(Thread.currentThread().getName() + "正在执行。。。");
    }
}


2.3 单任务线程池:

//创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 
ExecutorService pool = Executors.newSingleThreadExecutor(); 


3,java对象-->Json串

http://blog.csdn.net/conant1989/article/details/7186345

Gson是Google的一个开源项目,可以将Java对象转换成JSON,也可能将JSON转换成Java对象。Gson里最重要的对象有2个Gson 和GsonBuilder。

注意使用Gson时记得添加第三方类库gson-1.6.jar:

import com.google.gson.Gson;
Gson有2个最基本的方法:

1) toJson() – 转换java 对象到JSON
2) fromJson() – 转换JSON到java对象

3.1 toJson() – 转换java 对象到JSON

class TestObjectToJson {  
  private int data1 = 100;  
  private String data2 = "hello";  
}  
   
TestObjectToJson obj = new TestObjectToJson();  
Gson gson = new Gson();  
String json = gson.toJson(obj); 
会输出 {"data1":100,"data2":"hello"}

3.2 fromJson() – 转换JSON到java对象

import com.google.gson.Gson;  
   
class TestJsonFromObject {  
  private int data1;  
  private String data2;  
}  
   
String json = "{'data1':100,'data2':'hello'}";  
Gson gson = new Gson();  
TestJsonFromObject obj = gson.fromJson(json, TestJsonFromObject.class); 

3.3 将Java对象的属性转换成指定的JSON名字

import com.google.gson.FieldNamingPolicy;  
import com.google.gson.Gson;  
import com.google.gson.GsonBuilder;  
import com.google.gson.annotations.SerializedName;  
  
public class TestGson {  
      
    @SerializedName("FirstField")  
    private String field1;  
      
    private String secondField;  
  
    public TestGson(String param1, String param2) {  
        field1 = param1;  
        secondField = param2;  
    }  
}  
  
TestGson obj = new TestGson("aaaa", "bbbbb");  
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();  
gson.toJson(obj);  
输出结果 {"FirstField":"aaaa","SecondField":"bbbbb"}


//以下只有@Expose的才会选择
import com.google.gson.FieldNamingPolicy;  
import com.google.gson.Gson;  
import com.google.gson.GsonBuilder;  
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;  

public class TestGson {  

    @Expose
    private String field1;  

    private String secondField;  

    public TestGson(String param1, String param2) {  
        field1 = param1;  
        secondField = param2;  
    }  
}

TestGson obj = new TestGson("aaaa", "bbbbb");  
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().setPrettyPrinting().create();
gson.toJson(obj);  
输出结果:

{
  "field1": "aaaa"
}

4,Java对象序列化

4.1 Java串行化技术

Java 串行化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来,重新构造一个相同的对象。这种机制允许你将对象通过网络进行传播,并可以随时把对象持久化数据库、文件等系统里。Java的串行化机制是RMI、EJB等技术的技术基础。用途:利用对象的串行化实现保存应用程序的当前工作状态,下次再启动的时候将自动地恢复到上次执行的状态。
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题

4.2 序列化的实现 

序列化的实现:将需要被序列化的类实现Serializable接口,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。

4.3 序列化的特点

(1)如果某个类能够被串行化,其子类也可以被串行化。如果该类有父类,则分两种情况来考虑,如果该父类已经实现了可串行化接口。则其父类的相应字段及属性的处理和该类相同;如果该类的父类没有实现可串行化接口,则该类的父类所有的字段属性将不会串行化。
(2)声明为static和transient类型的成员数据不能被串行化。因为static代表类的状态, transient代表对象的临时数据;
(3)相关的类和接口:在java.io包中提供的涉及对象的串行化的类与接口有ObjectOutput接口、ObjectOutputStream类、ObjectInput接口、ObjectInputStream类。

4.4 代码示例

import java.io.*;

public class Cat implements Serializable {

  private String name;

  public Cat() {
    this.name = "Cat A";
  }

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public static void main(String[] args) {
    Cat cat = new Cat();
    try {
      FileOutputStream fos = new FileOutputStream("catDemo.out");
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      System.out.println(" 1> " + cat.getName());
      cat.setName("Cat B");
      oos.writeObject(cat);
      oos.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    try {
      FileInputStream fis = new FileInputStream("catDemo.out");
      ObjectInputStream ois = new ObjectInputStream(fis);
      cat = (Cat) ois.readObject();
      System.out.println(" 2> " + cat.getName());
      ois.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}// writeObject和readObject本身就是线程安全的,传输过程中是不允许被并发访问的。所以对象能一个一个接连不断的传过来

5,Java的反射机制

5.1 什么是Java的反射机制

简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。    

一般机制是java知道类的定义(比如import了这个类,或者就在同一个包里),然后根据类定义去new一个实例出来。
反射机制是不知道类是什么样的,根据字符串之类的类名字等去获取一个实例,然后根据方法名字去执行方法。
好比说,一般情况下画一只老虎,我得先知道老虎长什么样子才能画出来;有了反射机制,我只要知道“老虎”这个名字就能画出来。

5.2 反射机制能获得什么?

类中有什么信息,它就可以获得什么信息。

5.2.1 获得对应的类对象

首先得根据传入的类的全名来创建Class对象(第一步是获得你想操作的类的 java.lang.Class 对象):

方法一:Class c = Class.forName("java.lang.String"); //这条语句得到一个 String 类的类对象。
方法二:Class c = int.class;     //可获得基本类型的类信息。
方法三:Class c = Integer.TYPE;  //可获得基本类型的类信息。

Class是运行中的class类,forName(className)是将这个名为className的类装入JVM,这样就可以动态的加载类,通过Class的反射机制可以获得此类的一些信息。Class.forName 的作用动态加载和创建Class 对象。
类加载器是用来加载.class文件,读取.class文件的字节码并加载到内存中。

5.2.2 其次创建对象实例:

forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如:Object obj = Class.forName(s).newInstance();
虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如:if(e.getClass() == Employee.class)...  
Class c=Class.forName("className");//注明:className必须为全名,比如,cn.netjava.pojo.UserInfo;
Object obj=c.newInstance();//创建对象的实例 

5.2.3 再次获得各类信息:

获得构造函数的方法:

Constructor getConstructor(Class[] params)//根据指定参数获得public构造器
Constructor[] getConstructors()//获得public的所有构造器
Constructor getDeclaredConstructor(Class[] params)//根据指定参数获得public和非public的构造器
Constructor[] getDeclaredConstructors()//获得public的所有构造器
获得类方法的方法:

Method getMethod(String name, Class[] params),根据方法名,参数类型获得方法
Method[] getMethods()//获得所有的public方法
Method getDeclaredMethod(String name, Class[] params)//根据方法名和参数类型,获得public和非public的方法
Method[] getDeclaredMethods()//获得所以的public和非public方法

获得类中属性的方法:

Field getField(String name)//根据变量名得到相应的public变量
Field[] getFields()//获得类中所以public的方法
Field getDeclaredField(String name)//根据方法名获得public和非public变量
Field[] getDeclaredFields()//获得类中所有的public和非public方法


6,Java的异常机制

http://www.jz123.cn/text/1821910.html

6.1 基本概念

程序中的异常,一般称为例外情况,可以理解为是非正常情况。这里需要分清楚的是异常和错误不是一个概念。异常并非是真正的错误,因为他们是一些例外情况,这些情况有可能不会导致系统直接崩溃掉,但是它的存在只能说是程序的某种缺陷,或者说是非必然缺陷,而Java里面提供的异常体系结构就是为了解决这些缺陷而存在的。

在异常处理机制诞生之前,传统的异常处理方式多数是为了采用返回值来标识程序出现异常的情况,这种方式都很熟悉,如同在调试过程即是有良好的调试工具,但是常用的手段就是System.out.println的方式,但是这样的方式隐含一定的缺点:

[1]一个API可以返回任意的值,但是这些返回值本身不能解释返回值是否代表一个异常发生了,也不能描述异常的详细情况,若要知道该API出现异常的一些内容,还需要调用它的某些方法;
[2]没有一种结构可以确保异常情况能够得到处理,如果使用第一种方法,就会使得代码的可读性很差,而且很多时候并不能因为某些情况的存在就终止程序,就程序本身而言是应该提供一定的反馈情况。假设这样一个场景,如果你去输入用户名和密码登陆,如果你的用户名和密码输入错误了,但是界面上没有任何反应,这种情况是不是很糟糕,当然这只是个比方,这里不一定是出现了异常。

在开发过程中,当一个程序本身抛出了异常过后,程序会从程序导致异常的地方跳出来,在java语言里面,使用try和catch块来实现,当JVM碰到这个语句块的时候,它会监听整个Java程序,一旦出现了任何异常情况,它会将整个程序的执行权交给catch块来执行。

6.2 Java异常体系结构

java小技巧-2_第1张图片

Throwable是所有异常的基类,程序中一般不会直接抛出Throwable对象,Throwable本身存在两个子类实例,一个是Error、一个是Exception;
[1]Error:在Java里面Error表示程序在运行期间出现了十分严重的问题以及不可以恢复的错误,这种情况唯一的办法是中止程序运行,JVM一般不会检查Error是否被处理,而本身在程序中也不能捕获Error类型的异常,因为Error一旦产生,该程序基本会处于需要中止的状态。
[2]Exception:在Java里面Exception指的就是在编程过程可能会遇到的异常的概念,也属于Java程序里面允许出现的例外的状况,而Exception本身分为以下两种:
  RuntimeException:该异常继承于Exception类,这种类型的异常可以这样理解,为不可估计的异常,一般称为运行时异常,从字面意思上讲就是在程序正式运行的时候会碰到的偶发性异常,这种异常因为是在运行时抛出一般情况下不需要进行捕获操作。
  CheckedException:该类异常不存在继承于Exception类的说法,因为Java里面没有CheckedException异常类,而之所以这样区分,因为CheckedException类的异常是在编程过程中经常会遇到的异常,可以翻译为“可检测异常”或者“捕获型异常”,该类异常往往属于编译期异常,一般开发过程会针对系统进行CheckedException的设计。

http://book.51cto.com/art/201009/227779.htm 这篇很有意思

7,JNI技术

没有测试!

7.1 JNI定义

JNI是Java Native Interface的缩写,中文为JAVA本地调用。从Java1.1开始,Java Native Interface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。

使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少保证本地代码能工作在任何Java 虚拟机实现下

7.2 设计目的

1,标准的java类库可能不支持你的程序所需的特性。

2,或许你已经有了一个用其他语言写成的库或程序,而你希望在java程序中使用它。

3,你可能需要用底层语言实现一个小型的时间敏感代码,比如汇编,然后在你的java程序中调用这些功能。

7.3 书写步骤

1,编写带有native声明的方法的java类

HelloWorld.java:

class HelloWorld {
   public native void displayHelloWorld();// 所有native关键词修饰的都是对本地的声明

   static {
      System.loadLibrary("hello");// 载入本地库
  }

  public static void main(String args[]) {
      new HelloWorld().displayHelloWorld();
  }
}
声明native方法:如果你想将一个方法做为一个本地方法的话,那么你就必须声明该方法为native的,并且不能实现。其中方法的参数和返回值在后面讲述。 Load动态库:System.loadLibrary("hello");加载动态库(我们可以这样理解:我们的方法 displayHelloWorld()没有实现,但是我们在下面就直接使用了,所以必须在使用之前对它进行初始化)这里一般是以static块进行加载的。同时需要注意的是System.loadLibrary();的参数“hello”是动态库的名字。

2,使用javac命令编译所编写的java类

javac HelloWorld.java

3,使用“javah -jni java类名”生成扩展名为.h的头文件

javah -jni HelloWorld

生成了HelloWorld.h文件如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    displayHelloWorld
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
这 里我们可以这样理解:这个h文件相当于我们在java里面的接口,这里声明了一个Java_HelloWorld_displayHelloWorld (JNIEnv *, jobject);方法,然后在我们的本地方法里面实现这个方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致。

4,使用C/C++实现本地方法

实现和由javah命令生成的头文件里面声明的方法名相同的方法。

HelloWorldImpl.c

#include "jni.h"
#include "HelloWorld.h"
//#include other headers
JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv *env, jobject obj)
{
    printf("Hello world!\n");
    return;
}
注意第1行,需要将jni.h(该文件可以在%JAVA_HOME%/include文件夹下面找到)文件引入,因为在程序中的JNIEnv、 jobject等类型都是在该头文件中定义的;另外在第2行需要将HelloWorld.h头文件引入(我是这么理解的:相当于我们在编写java程序的时候,实现一个接口的话需要声明才可以,这里就是将HelloWorld.h头文件里面声明的方法加以实现。当然不一定是这样)。然后保存为 HelloWorldImpl.c就ok了。

5,将C/C++编写的文件生成动态连接库

注意我们这里include了 jni.h和刚才得到的HelloWorld.h文件。因此你要在VC++里面设置好,jni.h在JAVA_HOME/include里面。编译通过后再生成hello.dll文件。

6,运行程序 java HelloWorld

HelloWorld


8,以csv格式存储

8.1 csv格式简介

“CSV”,是Comma Separated Value(逗号分隔值)。因此要存储为csv格式,可用逗号分隔即可。

8.2 代码示例

public class test {

   public static void main(String[] args) throws IOException {
      // TODO Auto-generated method stub
      String string = "aaa,bbb,ccc\nddd,eee,fff";

      FileWriter fw = new FileWriter("1.csv");
      fw.write(string);
      fw.close();
   }
}
文本结果为:

aaa,bbb,ccc
ddd,eee,fff
用excel打开为:

java小技巧-2_第2张图片

9,java遍历map

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.ietf.jgss.Oid;
import org.omg.CORBA.PUBLIC_MEMBER;

/**
 * map遍历的三种办法
 *
 * @author us
 *
 */
public class test2 {
  /**
   * 1.把值放到一个集合里,然后遍历集合
   */
  public static void f1(Map<String, String> map) {

    Collection c = map.values();
    Iterator it = c.iterator();
    for (; it.hasNext();) {
      System.out.println(it.next());
    }
  }

  /**
   * 2.把key放到一个集合里,遍历key值同时根据key得到值 (推荐)
   */

  public static void f2(Map<String, String> map) {
    Set set = map.keySet();
    Iterator it = set.iterator();
    while (it.hasNext()) {
      String s = (String) it.next();
      System.out.println(map.get(s));
    }

  }

  /**
   * 3.把一个map对象放到放到entry里,然后根据entry同时得到key和值
   */
  public static void f3(Map<String, String> map) {
    Set set = map.entrySet();
    Iterator it = set.iterator();
    while (it.hasNext()) {
      Map.Entry<String, String> entry = (Entry<String, String>) it.next();
      System.out.println(entry.getKey() + ":" + entry.getValue());

    }
  }

  public static void main(String[] args) {
    /**
     * new一个map,然后添加内容
     */
    Map map = new HashMap();
    for (int i = 0; i < 10; i++) {
      map.put(i + "", i + "");
      System.out.println("添加" + i + "成功");
    }
    System.out.println("map大小" + map.size());
    f3(map);

  }

}

更简单的写f3():

public static void f3(Map<String, String> map) {
    for(Map.Entry<String, String> entry:map.entrySet())
      System.out.println(entry.getKey() + ":" + entry.getValue());
    }

10,Java UUID

GUID是一个128位长的数字,一般用16进制表示。算法的核心思想是结合机器的网卡、当地时间、一个随即数来生成GUID。从理论上讲,如果一台机器每秒产生10000000个GUID,则可以保证(概率意义上)3240年不重复。

UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。

UUID是由一个十六位的数字组成,表现出来的形式例如:550E8400-E29B-11D4-A716-446655440000 

import java.util.UUID;
 
UUID uuid  =  UUID.randomUUID(); 
String s = uuid.toString();//用来生成数据库的主键id非常不错  

防止多线程,虽然几乎不可能,在纳秒级时间:

import java.io.Serializable;
import java.util.UUID;

public class Sequence implements Serializable {
   public static String GeneralID()
   {
      synchronized(Sequence.lock){//防止多线程
         return UUID.randomUUID().toString().replaceAll("-", "_");   
      }
   }
   public static String lock=new String();

   public static void main(String args[]){
      System.out.println(GeneralID());
   }
}

11,MD5加密算法

MD5的全称是Message-Digest Algorithm 5,Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数。MD5将任意长度的"字节串"变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。 

算法摘自网络:

package com.hemes.md5;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5 {
public String md5Set(String plainText)
{
   String str="";
   try 
   {   
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(plainText.getBytes()); 
    byte b[] = md.digest(); 
   
    int i; 
   
    StringBuffer buf = new StringBuffer(""); 
   
    for (int offset = 0; offset < b.length; offset++)
    {
     i = b[offset]; 
     if (i < 0) 
     i += 256; 
     if (i < 16) 
     buf.append("0"); 
     buf.append(Integer.toHexString(i)); 
    }
    str = buf.toString(); 
//    System.out.println("result: " + buf.toString());// 32位的加密 
//    System.out.println("result: " + buf.toString().substring(8, 24));// 16位的加密 
   } catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
   }
   return str; 
}

public static void main(String[] args) {
   MD5 md5=new MD5();
   String str=md5.md5Set("123");
   System.out.println(str);
}

}


12,内建一个Cache(MD5算法应用)

import java.util.HashMap;
import java.util.Map;

public class Parser {
   //将表达式exp解析为ASTNode
   private ASTNode parserWhere(String exp){
       if(exp==null || exp.isEmpty())
          return null;
      //先判断Cache中是否存在
       String md5=MD5.md5(exp);
       ASTNode node=getCacheNode(md5);
       if(node!=null)
          return node;
       //Cache中不存在,再将exp解析为ASTNode
       ParseDriver pd = new ParseDriver();
       node = pd.parseWhere(exp);
       //将ASTNode加入Cache中
       putCache(md5,node);
       return node;
    }

   //以下为本类内建的一个Cache,一个Map(key=MD5值,value=ASTNode)
    private static Map<String,ASTNode> parserCache;
    public static void putCache(String key,ASTNode node){
       if(parserCache==null)
          parserCache=new HashMap<String,ASTNode>();
       parserCache.put(key, node);
    }
    public static ASTNode getCacheNode(String key){
       if(parserCache==null)
          return null;
       if(parserCache.containsKey(key))
          return parserCache.get(key);
       return null;

    }
}

13,利用Java反射机制加载文件中的数据

HiveParser.java

public class HiveParser{
    public static final int TOK_FUNCTIONDI=22;
    public static final int LSQUARE=452;
    public static final int TOK_PRIV_SHOW_DATABASE=222;
    public static final int KW_REPAIR=357;
    public static final int KW_FORMAT=363;
}

TokCache.java

static语句块在运行时加载该类后被执行。

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class TokCache {
   //使用Java反射机制,根据HiveParser.class载入TOK类型与值的映射
   public static Map<String,Integer> tokTypeCache;
   static{
      tokTypeCache=new HashMap<String,Integer>();
      for(Field f:HiveParser.class.getDeclaredFields()){
         if(f.getType().equals(int.class))
         {
            try {
               tokTypeCache.put("HiveParser."+f.getName(), f.getInt(null));
            } catch (IllegalArgumentException e) {
               e.printStackTrace();
            } catch (IllegalAccessException e) {
               e.printStackTrace();
            }
         }
      }
   }
   public static int getTokTypeValue(String tokName){
      if(tokTypeCache.containsKey(tokName)){
         return tokTypeCache.get(tokName);
      }
      else{
         return -1;
      }
   }
   public static void main(String args[]){
      System.out.println(TokCache.getTokTypeValue("HiveParser.KW_IN"));
      System.out.println(TokCache.getTokTypeValue("HiveParser.KW_FORMAT"));
   }
}

14,java日志输出

14.1 需要的Jar包和配置文件

1,commons-logging.jar:只是提供了对外的统一接口,真正的记录日志的工具是log4j或者sun logger。apache的common-logging包是通用日志接口,通过这个中间层,你可以随便指定到底用哪个日志系统。

2,log4j.rar:真正的实现部分,Log4j是Apache的一个开放源代码项目,需要一个配置文件:在CLASSPATH下建立log4j.properties

3,log4j.properties:其内容可以设置日志输出级别,从高到低是:Debug Info Warn Error Fatal,该文件可如下设置

log4j.rootLogger=INFO,console
#log4j.rootLogger=warn,error,fatal

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.Encoding=UTF-8
log4j.appender.console.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH:mm:ss}]  [ Class = %C | Method = %M | Line = %L ] | %m |%n

log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.layout=org.apache.log4j.PatternLayout
log4j.appender.info.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH:mm:ss}]  [ Class = %C | Method = %M | Line = %L ] | %m |%n
log4j.appender.info.datePattern='.'yyyy-MM-dd
log4j.appender.info.Threshold=INFO
log4j.appender.info.append=true
log4j.appender.info.Encoding=UTF-8
log4j.appender.info.File=${loghome}/info.log

log4j.logger.debug=debug
log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH:mm:ss}]  [ Class = %C | Method = %M | Line = %L ] | %m |%n
log4j.appender.debug.datePattern='.'yyyy-MM-dd
log4j.appender.debug.Threshold=DEBUG
log4j.appender.debug.append=true
log4j.appender.debug.Encoding=UTF-8
log4j.appender.debug.File=${loghome}/debug.log

log4j.logger.warn=warn
log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender
log4j.appender.warn.layout=org.apache.log4j.PatternLayout
log4j.appender.warn.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH:mm:ss}]  [ Class = %C | Method = %M | Line = %L ] | %m |%n
log4j.appender.warn.datePattern='.'yyyy-MM-dd
log4j.appender.warn.Threshold=WARN
log4j.appender.warn.append=true
log4j.appender.warn.Encoding=UTF-8
log4j.appender.warn.File=${loghome}/warn.log

log4j.logger.fatal=fatal
log4j.appender.fatal=org.apache.log4j.DailyRollingFileAppender
log4j.appender.fatal.layout=org.apache.log4j.PatternLayout
log4j.appender.fatal.layout.ConversionPattern=[%p]  [%d{yyyy-MM-dd HH\:mm\:ss}]  [ Class \= %C | Method \= %M | Line \= %L ] | %m |%n
log4j.appender.fatal.datePattern='.'yyyy-MM-dd
log4j.appender.fatal.Threshold=FATAL
log4j.appender.fatal.append=true
log4j.appender.fatal.Encoding=UTF-8
log4j.appender.fatal.File=${loghome}/fatal.log
#The log output to the directory
loghome=/tmp/log

14.2 使用方法:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Test {
   private static Log logger=LogFactory.getLog(Test.class);

   public static void main(String[] args) {
      logger.debug("debug");
      logger.info("info");
      logger.warn("warn");
      logger.error("error");
      logger.fatal("fatal");
   }
}

15,java对象设置属性用boolean还是Boolean

有时候对于一个对象,需要设置一个布尔型的属性,来表示某些特性,但是用如下方法,默认值为false:

public class Apple{

   private boolean isRed;

   public static void main(String[] args) {
      Apple test = new Apple();
   }
}
这肯定不是希望得到的结果,因为无法区分是赋值后的false,还是根本没有赋值呢,所以应该将

private boolean isRed;
改用:

private Boolean isRed;
这样默认值时null,当为null时,就表示未赋值。

16,一个java文件有多个类

//一个Java文件可以有多个类,但public权限的类最多只能有一个,若有则文件名必须是public类名同名
public class Car {

   private Engine engine ;
}

//不能是public了,同包中仍可访问
class Engine{

}

//Car类中有内部类Engine,外部不能访问
public class Car {

   private Engine engine ;

   //内部类
   class Engine{

   }
}

17,用java的反射机制获取资源文件

对于获取资源文件,一般,如要取得c:/test.txt文件,就会这样用File file = new File("c:/test.txt");但缺点是资源硬编码(即直接使用绝对路径)。更好的方法是:Class.getResource()Class.getResourceAsStream()方法,以下详细解释之。比如我们有以下目录:

|--project
    |--src
        |--javaapplication
            |--Test.java
            |--file1.txt
        |--file2.txt
    |--build 
        |--javaapplication
            |--Test.class
            |--file3.txt
        |--file4.txt
 
在上面的目录中,有一个src目录,这是JAVA源文件的目录,有一个build目录,这是JAVA编译后文件(.class文件等)的存放目录。那么,我们在Test类中应该 如何分别获得file1.txt  file2.txt  file3.txt  file4.txt这四个文件呢?
 
首先讲file3.txt与file4.txt:
file3.txt:
方法一:File file3 = new File(Test.class.getResource("file3.txt").getFile());
方法二:File file3 = new File(Test.class.getResource("/javaapplication/file3.txt").getFile());
方法三:File file3 = new File(Test.class.getClassLoader().getResource("javaapplication/file3.txt").getFile());
 
file4.txt:
方法一:File file4 = new File(Test.class.getResource("/file4.txt").getFile());
方法二:File file4 = new File(Test.class.getClassLoader().getResource("file4.txt").getFile());

注释:Test.class.getResource会 先定位到最终生成的Test.class文件,而不是以.java文件的路径为出发点,因为真正使用的就是.class,不会拿个.java文件就使用(java是编译型语言)。而getResouce()方法的参数,即 以.class为出发点,再结合相对路径的概念,就可以准确地定位资源文件了。其根目录指顶层package作为根目录,比如在Web应用中,有一个WEB-INF的目录,WEB-INF目录里面除了web.xml文件外,还有一个classes目录,它就是你这个WEB应用的package的顶层目录,也是所有.class的根目录“/”,假如classes目录下面有一个file.txt文件,它的相对路径就是"/file.txt",如果相对路径不是以"/"开头,那么它就是相对于.class的路径。


很好,我们可以有多种方法选择,但是file1与file2文件呢?如何获得?答案是,你只能写上它们的绝对路径,不能像file3与file4一样用class.getResource()这种方法获得,它们的获取方法如下
假如整个project目录放在c:/下,那么file1与file2的获取方法分别为:
file1.txt
方法一:File file1 = new File("c:/project/src/javaapplication/file1.txt");


file2.txt
方法一:File file2 = new File("c:/project/src/file2.txt");

还有一个getResourceAsStream()方法,参数是与getResouce()方法是一样的,它相当于你用getResource()取得File文件后,再new InputStream(file)一样的结果。

18,简单字符串的加密与解密

http://blog.csdn.net/mcpang/article/details/7024685

package com;

public class MD5Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		System.out.println(decrypt("137%128%143%145%124%144%135%143%76%"));
		
		System.out.println(encrypt("frontdev"));
	}
	
	/**
	   *用户名解密
	   *@param ssoToken 字符串
	   *@return String 返回加密字符串
	  */
	  public static String decrypt(String ssoToken)
	  {
	    try
	    {
	      String name = new String();
	      java.util.StringTokenizer st=new java.util.StringTokenizer(ssoToken,"%");
	      while (st.hasMoreElements()) {
	        int asc =  Integer.parseInt((String)st.nextElement()) - 27;
	        name = name + (char)asc;
	      }

	      return name;
	    }catch(Exception e)
	    {
	      e.printStackTrace() ;
	      return null;
	    }
	  }

	  /**
	   *用户名加密
	   *@param ssoToken 字符串
	   *@return String 返回加密字符串
	  */
	  public static String encrypt(String ssoToken)
	  {
	    try
	    {
	      byte[] _ssoToken = ssoToken.getBytes("ISO-8859-1");
	      String name = new String();
	     // char[] _ssoToken = ssoToken.toCharArray();
	      for (int i = 0; i < _ssoToken.length; i++) {
	          int asc = _ssoToken[i];
	          _ssoToken[i] = (byte) (asc + 27);
	          name = name + (asc + 27) + "%";
	      }
	      return name;
	    }catch(Exception e)
	    {
	      e.printStackTrace() ;
	      return null;
	    }
	  }
}

19,java对象简单的持久化

ObjectPersistence.java

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectPersistence {
  //将对象obj持久化到文件fileName中
  public static void output(Object obj, String fileName)
       {
    try {
      ObjectOutputStream out = new ObjectOutputStream(
          new FileOutputStream(fileName));
      out.writeObject(obj);
      out.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
    //从资源文件fileName中获取对象
  public static Object inputFromResource(String fileName)
  {
    try {
    InputStream is=ObjectPersistence.class.getResourceAsStream(fileName);
    ObjectInputStream in = new ObjectInputStream(is);
    Object obj = in.readObject();
    in.close();
    return obj;
    }
    catch (Exception ex) {
      ex.printStackTrace();
      return null;
    }
  }
  //从文件fileName中获取对象
  public static Object input(String fileName)  {
    try {
      ObjectInputStream in = new ObjectInputStream(new FileInputStream(
          fileName));
      Object obj = in.readObject();
      in.close();
      return obj;
    } catch (Exception ex) {
      ex.printStackTrace();
      return null;
    }
  }
}

20,读取配置文件,设置时持久化到原文件

Configuration.java

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 1,配置文件存放在本classpath的根下/
 * 2,使用单例模式:Configuration.getInstance()
 * 3,每次set操作,都会在该配置文件中save操纵(持久化)
 */
public class Configuration {
  static Log logger = LogFactory.getLog(Configuration.class);
  private Properties pro;
  private static Configuration instance;
  private static String configFile;
  public Configuration()
  {
  }
  public static Configuration getInstance(){
    try{
      if(instance!=null)
        return instance;

      if(configFile==null)
        configFile = "/app_config.property";
      instance=new Configuration(configFile);
    }
    catch(Exception ex){
      logger.error(ex);
      instance=new Configuration();
    }
    return instance;
  }
    //单例模式,构造函数为私有的
  private Configuration(String filePath) {
    pro = new Properties();
    try {
      // 读取属性文件
      InputStream inputFile = Configuration.class.getResourceAsStream(filePath);
      pro.load(inputFile);
      inputFile.close();
    } catch (Exception e) {
      logger.error("读取属性文件--->失败!- 原因:文件路径错误或者文件不存在", e);
    }
  }

  public String getValue(String key) {
    if (pro == null)
      return null;
    if (pro.containsKey(key)) {
      String value = pro.getProperty(key);
      return value;
    } else {
      return "";
    }
  }

  public void clear() {
    if (pro == null)
      return;
    pro.clear();
    save();
  }

  public void setValue(String key, String value) {
    if (pro == null)
      return;
    pro.setProperty(key, value);
    save();
  }

  //设置为私有
  private void save() {
    if (pro == null)
      return;
    try {
      //获取当前所在的根位置
      String currentPath = Configuration.class.getClass().getResource("/").getPath();
      FileOutputStream outputFile = new FileOutputStream(currentPath+configFile);
      System.out.println("持久化为:"+pro.toString());
      pro.store(outputFile,"");
      outputFile.close();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException ioe) {
      ioe.printStackTrace();
    }
  }

  public static void main(String[] args){
    //使用方法,单例使用getInstance
    Configuration configuration = Configuration.getInstance();
    System.out.println(configuration.getValue("sex"));
    configuration.setValue("name","dudu");
    System.out.println(configuration.getValue("name"));
    configuration.clear();
  }
}




你可能感兴趣的:(java小技巧-2)