JAVA基础3
来源:互联网 发布:中国软件协会培训中心 编辑:程序博客网 时间:2024/05/16 08:01
(1)线程创建的第一种方式
public class Test
{
public static void main(String[] args){
MyThread mt = new MyThread(); //创建出一条线程
mt.start(); //让线程开启
}
}
class MyThread extends Thread
{
public void run(){
//......
}
}
(2)线程创建的第二种方式
public class Test
{
public static void main(String[] args){
MyThread mt = new MyThread();
Thread th1 = new Thread(mt); //创建线程
Thread th2 = new Thread(mt);
th1.start(); //启动线程
th2.start();
}
}
class MyThread implements Runnable
{
private int num = 10;
public void run(){
if(num > 0){
System.out.println(num--);
}
}
}
/*
这两种方式创建线程的区别:
1、通过实现Runnable接口的方式来创建线程的好处在于还可以继承其他的类
而通过继承Thread的方式来创建线程有很大局限性
2、通过实现Runnable接口的方式来创建线程,创建的多个线程可以共享一个
对象,即上面的th1 th2可以共享执行一段代码,因为只有一个对象
而继承Thread的方式创建两个线程,没办法实现这一效果,他们分别执行
*/
2、线程运行的几种状态。
创建状态:new时创建,start运行
运行状态:具备CPU执行资格和执行权限。sleep(time)或者wait()就进入冻结状态。
冻结状态:释放了CPU执行资格和执行权限。sleep(time)或者notify就进入运行状态。
阻塞状态:具备CPU的执行资格,不具备CPU的执行权。冻结状态结束后,就有可能进入阻塞状态。
运行状态时也有可能进入阻塞状态。
消亡状态:run结束。
3、同步:一件事情接着一件事情做
异步:多件事件都在进行,相互不影响。
多线程存在的异步问题
(1)同步代码块
public class ThreadDemo
{
public static void main(String[] args){
MyThread mt = new MyThread();
Thread th1 = new Thread(mt);
Thread th2 = new Thread(mt);
th1.start();
th2.start();
}
}
/*
使用synchronized(对象){} 来锁住代码块
如果两个不同线程都拿着同一个对象去开锁,那只能有一个能进去锁住的代码块
另外一个线程必须等待第一个线程退出后方能进去。
当然,如果两个不同的线程拿着不同的对象,不影响。
同步锁成立的条件:(1)共享代码部分必须有多条线程在执行
(2)必须保证使用的是同一个锁对象
*/
class MyThread implements Runnable
{
private int num = 30;
Object obj = new Object();
public void run(){
while(true){
synchronized(obj){
if(num > 0){
System.out.println(num--);
}
}
}
}
}
(2)同步函数的方式
public class ThreadDemo
{
public static void main(String[] args){
MyThread mt = new MyThread();
Thread th1 = new Thread(mt);
Thread th2 = new Thread(mt);
th1.start();
th2.start();
}
}
class MyThread implements Runnable
{
private int num = 30;
public void run(){
show();
}
public synchronized void show(){ //同步函数的方式,使用的锁是this
if(num > 0){
System.out.println(num--);
}
}
}
//同步函数使用的锁是线程类对象this
//静态的同步函数(public static synchronized void show())使用的锁是该函数所在类的对象
//即 MyThread.class
4、多线程间的通讯
(1)wait方法:使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。
线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它,
这样它才能重新获得锁的拥有权和恢复执行。
要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
wait会释放对象的锁。
Thread.sleep(100),在睡眠期间是不会释放对象的锁。
(2)notify或者notifyAll:notify唤醒任意一个具备该锁的wait中的线程。notifyAll是唤醒所有具备该锁
的wait中的线程。
但是那个被唤醒的线程没办法马上执行,还要等notify的线程释放对象锁。
所以notify或者notifyAll方法调用也必须放在synchronized方法或synchronized块中。
(3)join()方法,在主线程中执行 th.join(); 那么主线程要等th线程执行完了才能往下执行
(4)yield()方法; 该线程让出CPU,让CPU切换到其他的线程。
5、String字符串
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
System.out.println(s1 == s2); // true 栈中的s1,s2都指向了堆里的常量池中的"abc"。常量池只有一个"abc"
System.out.println(s1 == s3); // false 栈中的s3指向了堆中的String对象,String对象里的成员变量指向常量池里//的"abc"。
6、字符串常用方法 String s = "abcdabhelo";
(1)求长度
s.length(); //注意和数组中的 arr.length属性区别开来
(2)根据下标返回字符
s.charAt(2); // c
(3)根据字符或者字符子串找到其位置
s.indexOf('a'); // 0
s.indexOf('a', 2); // 4 从下标2开始往右找字符'a'
s.indexOf("ab"); // 0
s.indexOf("ab", 1); // 4 和上面的原理一样
(4)反向查找
s.lastIndexOf('a'); // 4 从右边开始找第一个'a'
(5)是否以某些字符串开头
s.startsWith("abc"); // true
(6)是否以某些字符串结尾
s.endsWith("elo"); // true
(7)是否包含某些字符串
s.contains("dabh"); // true
(8)忽略大小写判断字符串相同
s.equalsIgnoreCase("AbcdaBHelo"); // true
(9)字符数组转为字符串
char[] arr = {'a','b','c','d','e'};
String str = new String(arr); // abcde
str = new String(arr,1,3); // bcd
(10)字符串转为字符数组
s.toCharArray(); // {'a','b','c','d','a','b'.....}
(11)字节数组转为字符串
byte[] arr = {'b','a','y','j'};
String str = new String(arr); // bayj
str = new String(arr,1,3); // ayj
(12)字符串转为字节数组
s.getBytes();
(13)基本数据类型转为字符串
String str = String.valueOf(5); // "5"
String str = String.valueOf(3.5); // "3.5"
(14)替换
String str = s.replace('a','x'); // str="xbcdxbhelo"而s不变 s="abcdabhelo"
String str = s.replace("ab","xy"); // str="xycdxyhelo"
String str = s.replace('m','m'); //原串没有m字符的话,返回原串
(15)切割
String s = "hello,world,nihao";
String[] arr = s.split(","); //arr[0]="hello" arr[1]="world" arr[2]="nihao"
(16)截取子串
String s = "abcdef";
String s1 = s.substring(2); //cdef
String s2 = s.substring(2,4); //注意结果是cd 从第2个开始截取,截取到第3个
(17)转大小写
String s = "Hello Java";
s.toUpperCase(); //HELLO JAVA
s.toLowerCase(); //hello java 同样也是不会改变原来的s的值
(18)去两端空格
s.trim();
(19)比较字符串大小
String s1 = "abc";
String s2 = "abd";
s1.compareTo(s2); //返回0表示相等 返回正数表示s1>s2 返回负数表示s1<s2
7、StringBuffer
特点 (1)长度可变
(2)里面数据类型不定
(3)无论任何类型的数据,最终都变为字符串。比如sb.append(new Object());//com.test.sb.Object@3e0ebb
StringBuffer sb = new StringBuffer("abc");
sb.append("12");
sb.append(true); //追加
System.out.println(sb.toString()); // abc12true
sb.insert(1,"qq"); //插入
System.out.println(sb.toString()); // aqqbc12true
sb.delete(2,4); //包含头,不包含尾,所以删了2和3
System.out.println(sb.toString()); // aqc12true
sb.deleteCharAt(1); //删除一个字符
System.out.println(sb.toString()); // ac12true
sb.replace(0,2,"hello"); //替换,同样是包含头,不包含尾
System.out.println(sb.toString()); //hello12true
sb.setCharAt(4,'m');
System.out.println(sb.toString()); //hellm12true
sb.reverse(); //反转
System.out.println(sb.toString()); //*******注意****** eurt21mlleh
//开发中建议用StringBuilder代替StringBuffer,API是一样的。效率和安全性更好。
8、包装数据类型
boolean Boolean
char Character
byte Byte
short Short
int Integer
long Long
float Float
double Double
基本数据类型转为字符串
(1) 12 + ""
(2) String.valueof(12);
字符串转为基本数据类型
(1) int i = Integer.parseInt("1234"); ==> i = 1234
(2) Integer integer = new Integer("10");
int i = integer.intValue(); ==> i = 10
十进制转其它进制
String binary = Integer.toBinaryString(110); //十进制转二进制
String hex = Integer.toHexString(110); //十进制转十六进制
String octal = Integer.toOctalString(110); //十进制转八进制
其它进制转十进制
int num = Integer.parseInt("110", 2); //二进制转为十进制
int num = Integer.parseInt("27", 8); //八进制转为十进制
int num = Integer.parseInt("4a", 16); //十六进制转为十进制
9、包装类型自动装箱和拆箱
//JDK1.5之后的新特性
Integer i = new Integer(10);
//JDK1.5之后可简写为
Integer i = 10; //自动装箱(普通类型转为类类型) 其实在这里把 new Integer(10)省略为10
i = i + 5; //首先先把i拆箱(类类型转为普通数据类型)为int类型,和5相加后的结果再装箱为Integer类型
10、集合,用来存储对象。数组,用来存储基本数据类型。
(1)Collection常用方法
Collection c = new ArrayList();
c.add("hello");
Collection c1 = new ArrayList();
c1.add(new Integer(10));
c1.add("java");
c.addAll(c1);
System.out.println(c.size()); // 3
System.out.println(c); // hello 10 java
System.out.println(c.contains("java")); // true
c.remove("java");
System.out.println(c); // hello 10
c1.clear();
c1.add("hello");
c.retainAll(c1); //这个式子的返回值是true 将c和c1里相同的元素保存在c中
System.out.println(c); // hello
(2)迭代器iterator
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
(3)List常用方法
ArrayList al = new ArrayList();
al.add("hello");
al.add("world");
al.add("nihao");
增
al.add(1,"zhang"); // hello zhang world nihao
删
al.remove(3); // hello zhang world
改
al.set(1,"nihao"); // hello nihao world
查
al.get(2); // world
List list = al.subList(0,2); //list里面有hello nihao 同样是包含头不包含尾
List中特有的遍历方法
因为Collection中的遍历方法有很大的局限性,不能在遍历的同时对其进行添加操作等
所以就出现了ListIterator
ListIterator li = al.listIterator();
while(li.hasNext()){
Object obj = li.next();
if(obj.equals("hello")){
li.add("xixi"); //利用迭代器的增加方法,如果使用Iterator就没有该方法了
}
}
//假如下面这种做法是有问题的:
//假如a1里有4个对象,迭代器it只知道它有4个对象。那么后面ArrayList add进来了 迭代器
//也不知道有新增的对象,所有就会报错。
Iterator it = a1.iterator();
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("hello")){
a1.add("xixi");
}
}
(4)List接口下的类特点
ArrayList:底层是以数组的结构存在。查询和修改快,增加和删除慢。
LinkedList:底层是以链表的结构存在。查询和修改慢,增加和删除快。
List:存进去的对象有顺序的,可重复的。
Set:存进去的对象没有顺序的,不可重复的。
(5)LinkedList常用方法
JDK1.6之后可使用的方法
LinkedList link = new LinkedList();
link.add("hello");
link.add("world");
link.offerFirst("nihao"); // nihao hello world
link.offerLast("zhang"); // nihao hello world zhang
link.peekFirst(); //获得第一个元素 nihao
link.peekLast(); //获得最后一个元素 zhang
link.pollFirst(); //获得第一个元素 并且从链表中删除了第一个元素
link.pollLast(); //获得最后一个元素 并且从链表中删除了最后一个元素
(6)Set:集合,数据是不可重复,并且数据时无序的。
数据无序的:数据存进去和取出来的顺序不一定一致。
HashSet:最底层其实还是数组,一个对象首先经过hashCode算法,得到一个结果,然后去这个数组的这个
结果的位置找其内容,如果这个位置的原本的对象不equals新的这个对象,那么新的对象就会在这个位置的下面增加进来,原来的对象依然存在。总结为一句,首先先判断hasCode()是否一致,如果一致再判断是否equals,如果equals,那么该对象就已经存在,不会再存进去。
自定义对象实现HashSet:
public class Person {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int hashCode() {
return name.hashCode() + age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Person){
Person p = (Person) obj;
if(this.name.equals(p.name) && this.age == p.age){
return true;
}
}
return false;
}
}
TreeSet的使用:
TreeSet ts = new TreeSet();
ts.add("abd");
ts.add("bcd");
ts.add("abc");
//最后打印的结果是有序,这个有序指的是会把帮从小到大排列,结果是:abc,abd,bcd
自定义对象实现TreeSet:
因为TreeSet具备排序的功能,所以其往里增加的对象必须是实现了Comparable接口,重写compareTo方法
@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person p = (Person) o;
if(this.age > p.age)
return -1;
else if(this.age < p.age)
return 1;
else
return 0;
} else {
throw new ClassCastException("类型转换错误");
}
}
11、泛型<>
List<Person> list = new ArrayList<Person>();
上面的意思是指,该List里面只能装Person类型的对象,把检测提前到编译时期。
泛型擦除:对源码进行编译时,通过泛型对类型进行检查。如果类型没有问题,就会编译成class文件。
class文件是不带泛型信息的,所以这种情况叫做泛型擦除。
(1)泛型类:
class Util<A>{
private A a;
public A getA(){
return a;
}
public void setA(A a){
this.a = a;
}
}
main:
Util<Person> util = new Util<Person>(); //这样创建对象。
注意:A只是一个标记而已,任何字符都可以。
(2)泛型方法:当你的方法的参数类型是不确定时使用,与类的类型没有关系。
class Demo{
public <A> void show(A a){
System.out.println(a);
}
}
main:
Demo d = new Demo();
d.show("hello");
d.show(12);
注意,如果是静态的方法上使用泛型,不能定义在类上,因为如果定义在类上,它必须通过对象才能确定类型。
而静态方法优先于对象存在。所以只能像上面这样,定义在方法上。
(3)泛型接口:
interface MyInterface<A>{
public void show(A a);
}
下面子类实现上面的接口,分为两种情况:
第一种,传入类型明确。
class Demo implements MyInterface<String>{
public void show(String s){
}
}
main:
Demo<String> demo = new Demo<String>();
demo.show("hello");
第二种,传入类型也不明确。
class Demo<K> implements MyInterface<K>{
public void show(K k){
}
}
main:
Demo<String> demo = new Demo<String>();
demo.show("hello");
Demo<Person> demo2 = new Demo<Person>();
demo.show(new Person());
(4)泛型通配符:?第一种,就是普通的泛型方法。
public static <T> void myShow1(Collection<T> c){
Iterator<T> it = c.iterator();
while(it.hasNext()){
T t = it.next();
System.out.println("--->" + t);
}
}
第二种,利用泛型通配符,和上面的效果一样,但是用通配符更简便。
public static void myShow2(Collection<?> c){
Iterator<?> it = c.iterator();
while(it.hasNext()){
System.out.println("--->" + it.next());
}
}
注意,泛型通配符只是一个标识,并不是一种类型,所以没办法像第一种那样能获得 T t对象。
第一种的泛型方法,它明确了是一种类型,只是这种类型暂时还不知道罢了。
(5)泛型限定:
public static void show(Collection<? extends Person> c){
//限定泛型的类型为Person或者为Person的子类
}
public static void show(Collection<? super Person> c){
//限定泛型的类型为Person或者为Person的父类
}
12、Map:存储的是键值对
(1)
Map<Integer,String> map = new HashMap<Integer, String>();
System.out.println(map.put(2,"hello")); //结果是null
System.out.println(map.put(2,"world")); //结果是hello
System.out.println(map.get(2)); //结果是world
System.out.println(map.containsKey(1)); //false,判断是否包含这样的键
map.remove(2); //删除
Collection<String> coll = map.values(); //把map中所有的值放到Collection里
(2)keySet()的使用,当该map的键我们都不知道的时候,怎么取出里面的键和值呢?
Map<Integer,String> map = new HashMap<Integer, String>();
map.put(1,"hello");
map.put(3,"nihao");
map.put(2,"world");
Set<Integer> set = map.keySet(); //获得键的集合
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
int i = it.next(); //获得键
String value = map.get(i); //获得值
}
(3)entrySet的使用,也是为了获取键和值的。
Map<String,String> map = new HashMap<String,String>();
map.put("1","hello");
map.put("2","world");
map.put("3","zhang");
Set<Map.Entry<String,String>> s = map.entrySet(); //把map里所有键值对的关系对象放到Set里面
Iterator<Map.Entry<String,String>> it = new s.iterator();
while(it.hasNext()){
Map.Entry<String,String> me = it.next(); //获得键值对的关系对象
me.getKey(); //获得键
me.getValue(); //获得值
}
//注意,上面的泛型Map.Entry<String,String> 比较特殊,它就是键值对的关系类型。这种写法其实就是在Map
//接口里面,有一个内部的接口Entry,并且Entry是静态的,所以能直接调用。
(4)HashMap和TreeMap
HashMap:和HashSet类似的数据结构,是不同步的,而且允许键值对为null
TreeMap:和TreeSet类似的数据结构,是不同步的,会对键进行排序。
不同步是为了提高效率,同步是为了提高安全性。
13、工具类:
Arrays:asList,把数组转为List
toString,把数组转为字符串
binarySearch,二分法查找
copyOf,数组复制
fill,数组内容填充,比如数组是1,2,3,4 填充成9,9,9,9
sort,数组排序,从小到大
Collections:集合工具类
List<String> list = new ArrayList<String>();
list.add("hellooo");
list.add("world");
list.add("cba");
list.add("nbab");
(1)排序,
//对List进行从小到大的排序
//结果是cba hellooo nbab world
Collections.sort(list);
(2)自定义排序,下面例子是比较字符串的长度。
public class MyCompare implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
}
//对List进行自定义的排序,自定义的方式是实现Comparator重写compare方法
//结果是cba nbab world hellooo
//注意,Comparable和Comparator接口的区别:
//Comparable是内部的,是对List里面的对象进行操作的,比如TreeSet的排序
//Comparator是外部的,是对list整体进行操作的。现在就是对list整体进行操作
Collections.sort(list, new MyCompare());
(3)随机排序
Collections.shuffle(list);
(4)二分法查找,前提是该List必须是升序排列好的
Collections.sort(list);
Collections.binarySearch(list, "world"); //返回找到的位置。
还有另外一种,是自定义排序的。还是用上面的比较器
Collections.sort(list, new Compare());
Collections.binarySearch(list, "world", new Compare());
(5)获取最大值
Collections.max(list); //默认会按Collections.sort(list);排序获取最大值
Collections.max(list, new MyCompare()); //会用自定义的排序获取最大值
(6)反转
Collections.reverse(list);
(7)能将不同步的ArrayList,HashMap等转为同步的,解决多线程并发问题。
Collections.synchronizedList(list);
Collections.synchronizedMap
Collections.synchronizedSet
14、JDK1.5之后的新特性
(1)可变参数,arr实际上是一个数组。
public static int add(int x, int... arr){
int temp = 0;
for(int i=0; i<arr.length; i++){
temp += arr[i];
}
return temp;
}
main:
add(1,2,3); //结果是5,因为x=1
add(5,2,3,9); //结果是14,因为x=5
//注意一点,可变参数只能是参数列表的最后一项,如果int... arr 和 int x调转就报错了。
(2)增强型for循环,把list的每一个元素取出来,赋值给s
for(String s : list){
System.out.println(s);
}
//增强for循环的弊端,只能遍历Collection或数组。
(3)静态导入包
main:
Collections.sort(list); //sort和max都是静态的方法,此时就可以省略写法。
Collections.max(list);
import static java.util.Collections.*; //静态导入包
main:
sort(list); //简写成这样,但是开发中不建议使用,阅读性很差。
max(list);
15、开发常用的工具API
System类
(1)
获取系统当前时间,long time = System.currentTimeMillis();
这个time是当前时间与1970年1月1日0时0分0秒相隔的毫秒数
(2)
获取系统属性,比如获取系统的名称String osName = System.getProperty("os.name");
不同的系统都能实现分行
System.out.println("hello" + System.getProperty("line.separator"); + "world");
(3)
退出程序,System.exit(0); //正常退出,非0是异常退出
(4)
请求系统进行垃圾回收,System.gc();
Math类
double value1 = Math.abs(-5.2); //获取绝对值
System.out.println(value1); //结果是 5.2
double value2 = Math.ceil(7.2); //获取大于该值的最小整数
System.out.println(value2); //结果是 8.0
double value3 = Math.floor(7.2); //获取小于该值的最大整数
System.out.println(value3); //结果是 7.0
double value4 = Math.round(3.45); //四舍五入
System.out.println(value4); //结果是 3.0
double value5 = Math.pow(2,4); //二的四次方
System.out.println(value5); //结果是 16.0
double value6 = Math.sin(30*Math.PI/180); //参数是弧度,不能是角度
System.out.println(value6); //结果是 0.49999999999999994
double value7 = Math.random(); //伪随机数,范围0.0-1.0之间
System.out.println(value7); //结果不确定
Random r = new Random();
r.nextInt(10); //包含0,不包含10
Date类
//毫秒值转为日期对象。空的构造函数默认是系统当前的时间
Date date = new Date(1396837370954l);
System.out.println(date);
//日期对象转为毫秒值
System.out.println(date.getTime());
DateFormat类
//日期时间格式化,把日期时间对象转为字符串
/**
* (1)系统自带的风格
*/
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String result1 = df.format(new Date());
System.out.println(result1); // 2014年4月7日 上午11时49分02秒
df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
String result2 = df.format(new Date());
System.out.println(result2); // 2014年4月7日 星期一 上午11时50分16秒 CST
df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
String result3 = df.format(new Date());
System.out.println(result3); // 2014-4-7 11:51:09
df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
String result4 = df.format(new Date());
System.out.println(result4); // 14-4-7 上午11:51
/**
* (2)自定义风格
*/
Date date = new Date(1396848370954l);
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
String result = format.format(date);
System.out.println(result); //2014/04/07 13:26:10
//日期时间解析,把字符串转成日期对象
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = null;
try {
d = format.parse("2014-04-07 10:20:30");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(d); // Mon Apr 07 10:20:30 CST 2014
//解析这里有一点值得注意的是,解析的格式必须和format的格式一致。
Calendar类
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1;
System.out.println(year + "..." + month); //2014...4
c.set(2013, 3, 8); //设置时间
c.add(Calendar.MONTH, 2); //修改时间
System.out.println(c.get(Calendar.MONTH)); //5
- java基础3
- java基础(3)
- Java基础3
- java基础笔记3
- java基础3
- java基础复习--3
- java基础--连载3
- java基础3
- java基础面试3
- Java基础面试-3
- java基础3
- java 基础命令3
- java基础--笔记3
- java 基础3 类
- JAVA基础3
- java基础3
- Java基础(3)
- Java基础回顾(3)
- 股票详解
- ios开发中的基本设计模式
- 进程 内存查看
- Google support4 SlidingPaneLayout DrawerLayout
- JSTL标签库formatDate标签格式化日期
- JAVA基础3
- c++ 数据结构之 set
- CSDN主题首页
- hdu2222 AC自动机
- c++时间与java时间相互转化代码实例
- Solr4.6,搜索不区分大小写的配置
- 关于举办2014年全国高校IT骨干教师暑期培训班的通知
- apache +tomcat实现负载均衡
- 自定义BuufferedReader中的readLine方法。