JAVA 笔记
一、Java基础以及面向对象编程
1、float类型的数自动转换成double类型时,可能会出现前后不相等的情况,因为有些数不能够用有限的二进制位精确表示。
2、右移
>>右移,左边空出位以符号位填充
>>>右移,左边空出位以0填充
3、计算阶乘
public class Factorial { public Factorial(){ } public long getFactorial(int n){ if((n<0)||(n>17)){ return -1; }else if(n==0 || n==1){ return 1; }else{ long result=n; do{ result *=(--n); }while(n>1); return result; } } }
4、System.exit(0) 该方法关闭Java虚拟机,退出应用程序,当exit方法的参数为0时表示程序正常退出,为其他值时异常退出。
5、重写equals、clone、hashCode方法
这几个方法在Object类中都是基于对象的地址来实现的,如果要实现符合实际意义的方法,则需要在Object的子类中进行重写。这里以复数类为例:
(1)重写equals方法
先判断传入对象与现有对象是否同一类,再对同一类的传入对象比较属性。
@Override public boolean equals(Object obj) { if(obj==null){ return false; } if(obj instanceof ComplexNumber){ ComplexNumber b=(ComplexNumber)obj; if((this.realPart == b.realPart) && (this.imaginaryPart==b.imaginaryPart)){ return true; }else{ return false; } }else{ return false; } }
(2)重写hashCode方法
找到一个能够代表对象的Key,如果这个key是int类型,可以直接返回该key,如果其他类型,则返回该key的hashCode。
@Override public String toString() { return "ComplexNumber{" + "realPart=" + realPart + ", imaginaryPart=" + imaginaryPart + '}'; } @Override public int hashCode() { return this.toString().hashCode(); }
(3)重写clone方法
首先,类要实现Cloneable方法,然后再重写clone方法。实现时,先调用父类的clone方法,然后将现有对象的属性值赋给新对象。
@Override protected Object clone() { try{ ComplexNumber newObject=(ComplexNumber) super.clone(); newObject.setRealPart(this.realPart); newObject.setImaginaryPart(this.imaginaryPart); return newObject; }catch(CloneNotSupportedException e){ e.printStackTrace(); return null; } }
6、Java在传递参数时,如果参数是对象类型,则将“参数的引用”复制之后传给方法。
7、System的gc方法通知Java虚拟机进行垃圾回收,但何时回收由虚拟机决定,进行垃圾回收时,虚拟机会调用对象的finalize方法。
8、对于每个类,Java虚拟机只加载一次,加载时,对类的静态方法、静态变量、静态初始化块进行初始化。只有在新建一个对象时,才会按先父类后子类的顺序初始化类的初始化块、构造函数。
9、方法和变量在继承时的覆盖和隐藏
(1)同名的实例方法被覆盖,同名的类方法(静态方法)被隐藏。
(2)隐藏和覆盖的区别:子类对象转换成父类后,能够访问父类被隐藏的变量和方法,但不能访问被覆盖的变量和方法。
10、排序
(1)接口
public interface ISortNumber { /** * 升序排序 * @param intArray * @return */ public int[] sortASC(int[] intArray); }
(2)选择排序
public class SelectionSort implements ISortNumber{ public SelectionSort() { } @Override public int[] sortASC(int[] intArray) { if(intArray==null){ return null; } int[] srcDatas=(int[])intArray.clone(); int size=srcDatas.length; for(int i=0;i<size;i++){ for(int j=i;j<size;j++){ if(srcDatas[i]>srcDatas[j]){ swap(srcDatas,i,j); } } } return srcDatas; } private void swap(int[] data,int src,int dest){ int temp=data[src]; data[src]=data[dest]; data[dest]=temp; } }
(3)冒泡排序
public class BubbleSort implements ISortNumber{ public BubbleSort() { } @Override public int[] sortASC(int[] intArray) { if(intArray==null){ return null; } int[] srcDatas=(int[]) intArray.clone(); boolean changedPosition=true; int comparedTimes=0; int maxComparedTimes=srcDatas.length-1; while((comparedTimes<maxComparedTimes) && (changedPosition)){ for(int i=0;i<(maxComparedTimes-comparedTimes);i++){ changedPosition=false; if(srcDatas[i]>srcDatas[i+1]){ swap(srcDatas,i,i+1); changedPosition=true; } } comparedTimes++; } return srcDatas; } private void swap(int[] data,int src,int dest){ int temp=data[src]; data[src]=data[dest]; data[dest]=temp; } }
(4)线性插值排序
public class LinearInsertSort implements ISortNumber{ public LinearInsertSort() { } @Override public int[] sortASC(int[] intArray) { if(intArray==null){ return null; } int[] srcDatas=(int[])intArray.clone(); int size=srcDatas.length; int temp=0; int index=0; for(int i=1;i<size;i++){ temp=srcDatas[i]; index=i; while((index>0) && (temp<srcDatas[index-1])){ srcDatas[index]=srcDatas[index-1]; index--; } } return srcDatas; } }
(5)快速排序
public class QuickSort implements ISortNumber{ public QuickSort() { } @Override public int[] sortASC(int[] intArray) { if(intArray==null){ return null; } int[] srcDatas=(int[])intArray.clone(); return this.quickSort(srcDatas,0,srcDatas.length-1); } private int[] quickSort(int[] srcDatas,int first,int last){ if(first<last){ int pos=partion(srcDatas,first,last); quickSort(srcDatas,first,pos-1); quickSort(srcDatas,pos+1,last); } return srcDatas; } //根据数组的第一个数分治 //比第一个数大的往后排,比第一个数小的往前排 private int partion(int[] srcDatas,int first,int last ){ int temp=srcDatas[first]; int pos=first; for(int i=first+1;i<=last;i++){ if(srcDatas[i]<temp){ pos++; swap(srcDatas,pos,i); } } swap(srcDatas,first,pos); return pos; } private void swap(int[] data,int src,int dest){ int temp=data[src]; data[src]=data[dest]; data[dest]=temp; } }
10、Singleton模式
(1)模式1
public class SingletonA { private static int id=1; private static SingletonA instance=new SingletonA(); private SingletonA() { } public static SingletonA getInstance(){ return instance; } public synchronized int getId(){ return id; } }
(2)模式2(lazy initialization)
public class SingletonA { private static int id=1; private static SingletonA instance=null; private SingletonA() { } public static SingletonA getInstance(){ if(instance==null){ instance=new SingletonA(); } return instance; } public synchronized int getId(){ return id; } }
在getInstance方法声明中使用synchronized(同步)关键字,以保证同一时刻只有一个进程进入该方法。保证只创建一个对象。
11、Factory模式
(1)用一个接口抽象产品功能,所有具体的产品都实现该接口
(2)Factory类定义一个创建产品的方法,参数为产品的具体类型,返回一个产品接口对象。用户通过产品接口使用产品功能。
如下面的例子,该Factory类可以根据用户需求创建不同的用于排序的产品。
public class Factory { public static final String SELECTION_SORT="selection"; public static final String BUBBLE_SORT="bubble"; public static final String LINEARINSERT_SORT="linearinsert"; public static final String QUICK_SORT="quick"; public static ISortNumber getOrderNumber(String id){ if(SELECTION_SORT.equalsIgnoreCase(id)){ return new SelectionSort(); }else if(BUBBLE_SORT.equalsIgnoreCase(id)){ return new BubbleSort(); }else if(LINEARINSERT_SORT.equalsIgnoreCase(id)){ return new LinearInsertSort(); }else if(QUICK_SORT.equalsIgnoreCase(id)){ return new QuickSort(); }else{ return null; } } }
12、Adapter类
public class Printer { public static void printIntArray(int[] array){ if(array!=null){ for(int i=0;i<array.length;i++){ System.out.print(array[i]+" "); } System.out.println(); } } } public class PrinterAdapter extends Printer implements ISortNumber{ private ISortNumber mySort; public PrinterAdapter(ISortNumber mySort) { super(); this.mySort = mySort; } @Override public int[] sortASC(int[] intArray) { if(this.mySort!=null){ return this.mySort.sortASC(intArray); } return null; } }
PrinterAdapter是Adapter,将Printer和ISortNumber进行适配,具有两者定义的所有功能。
ISortNumber是Adaptee。Adapter的构造方法中串入一个具体的Adaptee对象,在实现Adaptee接口定义的方法中,调用Adaptee的相应方法。
Printer是目标类。
二、数字
13、数字与数字封装类的相互转换
(1)byte与Byte
byte b1=5; Byte b2=new Byte(b1); //或者 Byte b2=Byte.valueOf(b1); byte b3=b2.byteValue();
(2)int与Integer
int i1=5; Integer i2=new Integer(i1);//或者 Integer i2=Integer.valueof(i1); int i3=i2.intValue();
14、格式化数字,使用DecimalFormat类。
DecimalFormat df=new DecimalFormat(); double data=1234.4650238903; String pattern="0.0";//显示格式 df.applyPattern(pattern); String str=df.format(data);//格式化后为1234.5 //pattern ="00000.000 kg" 格式化为001234.465 kg //pattern ="##000.000 kg" 格式化为1234.465 kg //pattern ="-000.000" 格式化为-1234.465 //pattern ="-0,000.000" 格式化为-1,234.465 //pattern ="0.00E000" 格式化为1.23E003 //pattern ="0.00%" 格式化为123446.50% //pattern ="0.00\u2030" 格式化为1234465.02‰,显示为千分数
15、数字的舍入
用BigDecimal类的setScale方法来实现,支持不同的舍入模式。
16、数制的转换
Integer或Long的toString(int i,int radix)、toBinaryString()、toOctalString()、toHexString()等方法。
17、生成随机数,用Random类来实现。
18、高精度运算
使用BigInteger和BigDecimal类。
下例,计算阶乘。
public BigInteger getFactorial(int n){ if((n<0)||(n>17)){ return new BigInteger("-1"); }else if(n==0 || n==1){ return new BigInteger("1"); }else{ BigInteger result=new BigInteger("n"); do{ result.multiply(new BigInteger(new Integer(--n).toString())); }while(n>1); return result; } }
BigInteger和BigDecimal类都是不可变的,每一步运算都会产生一个新对象,不适合大量的数学运算。这两个类常常用在商业计算的精确大整数和小数。
要获得精确小数,应使用String来构造BigDecimal,避免使用double来构造,因为double类型并不精确。
从数值上比较两个BigDecimal的值时,应使用compareTo方法,而不是equals方法,因为后者会认为0.10和0.1不相等。
三、数组与集合
1、Arrays
填充数组,
int[] array0=new int[10]; Arrays.fill(array0,3);//给数组所有元素赋值为5 Arrays.fill(array0,2,5,7);//给array0[2]~array0[4]赋值为7
排序
Arrays.sort(array0,2,7);//将array0[2]~array0[6]排序 Arrays.sort(array0);//整个数组排序
2、求质数
/** * 用筛选法求range范围内的质数 * @param range 范围的上限 * @return */ private boolean[] sieve(int range){ if(range<0){ return null; } boolean[] isPrime=new boolean[range+1]; isPrime[1]=false; Arrays.fill(isPrime, 2, range+1, true); int n=(int)Math.sqrt(range); for(int i=1;i<=n;i++){ if(isPrime[i]){ //如果i是质数,则i的倍数不是质数 for(int j=2*i;j<=range;j+=i){ isPrime[j]=false; } } } return isPrime; }
3、动态调整数组的长度
新建一个新的数组,然后将原数组的数据拷贝到新数组中。
Integer[] result=new Integer[src.length+length];
System.arraycopy(src,0,result,0,src.length);
4、矩阵
用double二维数组创建矩阵,并实现矩阵的加减乘除算法。
1 public class Matrix implements Cloneable{ 2 private double[][] matrixData; 3 4 public Matrix() { 5 this.init(); 6 } 7 8 public Matrix(double[][] matrixData) { 9 if(!this.canConvert2Matrix(matrixData)){ 10 this.init(); 11 } else{ 12 this.matrixData = this.cloneArray(matrixData); 13 } 14 } 15 16 private void init(){ 17 this.matrixData=new double[][]{ 18 {1.0,0.0,0.0}, 19 {0.0,1.0,0.0}, 20 {0.0,0.0,1.0}}; 21 } 22 23 private boolean canConvert2Matrix(double[][] matrixData){ 24 if(matrixData==null){ 25 return false; 26 } 27 for(int i=0;i<matrixData.length-1;i++){ 28 if(matrixData[i].length!=matrixData[i+1].length){ 29 return false; 30 } 31 } 32 return true; 33 } 34 35 private double[][] cloneArray(double[][] src){ 36 if(src==null){ 37 return null; 38 } 39 return (double[][]) src.clone(); 40 } 41 /** 42 * 矩阵相加 43 * @param b 44 * @return 45 */ 46 public Matrix add(Matrix b){ 47 if(b==null){ 48 return null; 49 } 50 51 Matrix c=null; 52 double[][] bData=b.getMatrixData(); 53 if(this.matrixData.length!=bData.length 54 || this.matrixData[0].length!=bData[0].length){ 55 System.out.println("两个矩阵长度不一致,不能相加"); 56 return c; 57 } 58 59 double[][] cData=new double[this.matrixData.length][this.matrixData[0].length]; 60 for(int i=0;i<this.matrixData.length;i++){ 61 for(int j=0;j<this.matrixData[0].length;j++){ 62 cData[i][j]=this.matrixData[i][j]+bData[i][j]; 63 } 64 } 65 c=new Matrix(cData); 66 return c; 67 68 } 69 70 /** 71 * 矩阵相减 72 * @param b 73 * @return 74 */ 75 public Matrix sub(Matrix b){ 76 if(b==null){ 77 return null; 78 } 79 80 Matrix c=null; 81 double[][] bData=b.getMatrixData(); 82 if(this.matrixData.length!=bData.length 83 || this.matrixData[0].length!=bData[0].length){ 84 System.out.println("两个矩阵长度不一致,不能相减"); 85 return c; 86 } 87 88 double[][] cData=new double[this.matrixData.length][this.matrixData[0].length]; 89 for(int i=0;i<this.matrixData.length;i++){ 90 for(int j=0;j<this.matrixData[0].length;j++){ 91 cData[i][j]=this.matrixData[i][j]-bData[i][j]; 92 } 93 } 94 c=new Matrix(cData); 95 return c; 96 97 } 98 99 /** 100 * 矩阵数乘 101 * @param num 102 * @return 103 */ 104 public Matrix multiplyNum(double num){ 105 double[][] cData=new double[this.matrixData.length][this.matrixData[0].length]; 106 for(int i=0;i<this.matrixData.length;i++){ 107 for(int j=0;j<this.matrixData[0].length;j++){ 108 cData[i][j]=this.matrixData[i][j] * num; 109 } 110 } 111 return new Matrix(cData); 112 } 113 114 115 /** 116 * 矩阵乘法 117 * @param b 118 * @return 119 */ 120 public Matrix multiply(Matrix b){ 121 if(b==null) 122 return null; 123 double[][] bData=b.getMatrixData(); 124 if(this.matrixData[0].length!=bData.length){ 125 System.out.println("矩阵的A的列数不等于矩阵B的行数,不能相乘"); 126 return null; 127 } 128 double[][] cData=new double[this.matrixData.length][bData[0].length]; 129 for(int i=0;i<this.matrixData.length;i++){ 130 for(int j=0;j<bData[0].length;j++){ 131 cData[i][j]=0; 132 for(int k=0;k<this.matrixData[0].length;k++){ 133 cData[i][j]+=this.matrixData[i][k]*bData[k][j]; 134 } 135 } 136 } 137 return new Matrix(cData); 138 } 139 140 /** 141 * 矩阵除法 142 * @param b 143 * @return 144 */ 145 public Matrix divide(Matrix b){ 146 if(b==null){ 147 return null; 148 } 149 if(!this.isSquareMatrix() 150 || (!b.isSquareMatrix()) 151 || (this.matrixData.length!=b.getMatrixData().length)){ 152 System.out.println("不能相除"); 153 return null; 154 } 155 Matrix c=b.inverseMatrix(); 156 if(c!=null) 157 return this.multiply(c); 158 else{ 159 System.out.println("不能相除"); 160 return null; 161 } 162 } 163 /** 164 * 逆矩阵 165 * @return 166 */ 167 public Matrix inverseMatrix() { 168 if(!this.isSquareMatrix()){ 169 System.out.println("不是方阵,不能求逆"); 170 return null; 171 } 172 173 Matrix tempM=this.appendUnitMatrix(); 174 double[][] tempData=tempM.getMatrixData(); 175 int line=0; 176 double bs=0; 177 double swap=0; 178 for(int i=0;i<tempData.length;i++){ 179 if(tempData[i][i]==0){ 180 if(++line>=tempData.length){ 181 System.out.println("没有逆矩阵"); 182 return null; 183 } 184 for(int j=0;j<tempData[0].length;j++){ 185 swap=tempData[i][j]; 186 tempData[i][j]=tempData[line][j]; 187 tempData[line][j]=swap; 188 } 189 continue; 190 } 191 192 if(tempData[i][i]!=1){ 193 bs=tempData[i][i]; 194 for(int j=tempData[0].length-1;j>=0;j--){ 195 tempData[i][j]/=bs; 196 } 197 for(int iNow=i+1;iNow<tempData.length;iNow++){ 198 for(int j=tempData[0].length-1;j>=i;j--){ 199 tempData[iNow][j]-=tempData[i][j]*tempData[iNow][i]; 200 } 201 } 202 } 203 } 204 //将左边矩阵变为单位矩阵 205 for(int i=0;i<tempData.length-1;i++){ 206 for(int iNow=i;iNow<tempData.length-1;iNow++){ 207 for(int j=tempData[0].length-1;j>=0;j--){ 208 tempData[i][j]-=tempData[i][iNow+1]*tempData[iNow+1][j]; 209 } 210 } 211 } 212 213 //右边部分为逆矩阵 214 double[][] cData=new double[this.matrixData.length][this.matrixData[0].length]; 215 for(int i=0;i<this.matrixData.length;i++){ 216 for(int j=0;j<this.matrixData[0].length;j++){ 217 cData[i][j] =tempData[i][j+this.matrixData[0].length]; 218 } 219 } 220 return new Matrix(cData); 221 } 222 /** 223 * 给矩阵右边加上单位矩阵 224 * @return 225 */ 226 private Matrix appendUnitMatrix(){ 227 double[][] cData=new double[this.matrixData.length][this.matrixData[0].length*2]; 228 for(int i=0;i<this.matrixData.length;i++){ 229 for(int j=0;j<this.matrixData[0].length*2;j++){ 230 if(j<this.matrixData[0].length){ 231 cData[i][j]=this.matrixData[i][j]; 232 }else{ 233 if((j-this.matrixData[0].length)==i){ 234 cData[i][j]=1.0; 235 }else{ 236 cData[i][j]=0.0; 237 } 238 } 239 } 240 } 241 return new Matrix(cData); 242 } 243 244 /** 245 * 转置矩阵 246 * @return 247 */ 248 public Matrix transposeMatrix(){ 249 double[][] cData=new double[this.matrixData[0].length][this.matrixData.length]; 250 for(int i=0;i<this.matrixData[0].length;i++){ 251 for(int j=0;j<this.matrixData.length;j++){ 252 cData[i][j]=this.matrixData[j][i]; 253 } 254 } 255 return new Matrix(cData); 256 } 257 258 /** 259 * 矩阵是否为方阵 260 * @return 261 */ 262 public boolean isSquareMatrix(){ 263 if(this.matrixData.length==this.matrixData[0].length){ 264 return true; 265 } 266 return false; 267 } 268 269 public double[][] getMatrixData(){ 270 return this.cloneArray(this.matrixData); 271 } 272 273 public void setMatrixData(double[][] matrixData){ 274 if(this.canConvert2Matrix(matrixData)){ 275 this.matrixData=this.cloneArray(matrixData); 276 } 277 } 278 279 @Override 280 public String toString() { 281 DecimalFormat df=new DecimalFormat("0.00"); 282 StringBuffer sb=new StringBuffer(""); 283 for(int i=0;i<this.matrixData.length;i++){ 284 for(int j=0;j<this.matrixData[0].length;j++){ 285 sb.append(df.format(this.matrixData[i][j])).append(" "); 286 } 287 sb.append("\n"); 288 } 289 return sb.toString(); 290 } 291 292 @Override 293 public int hashCode() { 294 return this.toString().hashCode(); 295 } 296 297 @Override 298 public boolean equals(Object obj) { 299 if (obj == null) { 300 return false; 301 } 302 if (getClass() != obj.getClass()) { 303 return false; 304 } 305 final Matrix other = (Matrix) obj; 306 if (!Arrays.deepEquals(this.matrixData, other.matrixData)) { 307 return false; 308 } 309 return true; 310 } 311 312 @Override 313 protected Object clone(){ 314 try{ 315 Matrix matrix=(Matrix) super.clone(); 316 matrix.setMatrixData(this.matrixData); 317 return matrix; 318 }catch(CloneNotSupportedException e){ 319 } 320 return null; 321 } 322 }
5、ArrayList、Vector和LinkedList
(1)ArrayList、Vector都是用数组实现,不同的是Vector支持线程同步
(2)LinkedList使用链表结构存储数据,方便操作列表头和列表尾元素。
(3)可以为List生成ListIterator,支持双向遍历。
6、生成不重复的随机数序列
(1)排除法
如果新生成的数字不包含在结果列表中,则将数字添加到列表,否则,重新生成随机数。
(2)筛选法
将所有可能的数字放到候选列表中,将生成的随机数k作为下标,对应的候选列表中的数字添加到结果列表中,并从候选列表中删除。
7、用LinkedList可以方便地实现Queue
8、对List进行排序,用Collections.sort()方法,可以设置自定义的比较器(实现Comparator接口)。
9、HashSet
采用散列函数对元素进行排序。存入HashSet中的对象必须定义hashCode方法。
10、TreeSet
采用红黑树的数据结构进行排序,可以提取有序的序列。存入TreeSet中的自定义类对象需要实现Comparable接口并定义compareTo方法。
11、LinkedHashSet
使用链表维护元素的插入次序。元素的次序就是插入时的次序。
12、数组、List和Set之间的相互转化
(1)List转化为数组
String[] strArray=(String[])list.toArray(new String[list.size()]);
(2)Set转化为数组
String[] strArray=(String[])set.toArray(new String[set.size()]);
(3)数组转化为List
list=Arrays.asList(strArray);
(4)数组转化为Set,先转为List,再构造Set
set=new HashSet(Arrays.asList(strArray));
13、Map 键值对存储
(1)HashMap
不支持线程同步,键或值可以为null。
(2)HashTable
键或值都不能为null。支持线程同步。
(3)LinkedHashMap
保存记录的插入次序。
(4)TreeMap
记录按照Key来排序。
14、对Map排序
(1)其他Map转换成TreeMap,便可以进行按Key排序。
(2)TreeMap默认升序排列,可以指定比较器。
15、Properties属性文件
能从输入流(文件)中获取键值对信息,也可以将键值对信息存放到输出流(文件)中。
Properties props=new Properties(); //存放数据 props.setProperty("name","zhangsan"); //读取数据 String str=props.getProperty("name"); //保存到输出流 FileOutputStream out=new FileOutputStream("C:/test.properties"); props.store(out,"test"); out.close(); //从输出流中加载数据 Properties newProps=new Properties(); FileInputStream in=new FileInputStream("C:/test.properties"); newProps,load(in); in.close();
四、字符串
1、String是不变类,修改String会得到新的String对象,如果要频繁修改字符串,应使用StringBuilder类。
2、IP地址转换为整数
public static long ipToLong(String strIP){ long[] ip=new long[4]; int position1=strIP.indexOf("."); int position2=strIP.indexOf(".",position1+1); int position3=strIP.indexOf(".",position2+1); ip[0]=Long.parseLong(strIP.substring(0, position1)); ip[1]=Long.parseLong(strIP.substring(position1+1, position2)); ip[2]=Long.parseLong(strIP.substring(position2+1, position3)); ip[3]=Long.parseLong(strIP.substring(position3+1)); return (ip[0]<<24)+(ip[1]<<16)+(ip[2]<<8)+ip[3]; } public static String longToIP(long longIP){ StringBuilder sb=new StringBuilder(""); sb.append(String.valueOf(longIP>>>24)).append("."); sb.append(String.valueOf((longIP&0x00FFFFFF)>>>16)).append("."); sb.append(String.valueOf((longIP&0x0000FFFF)>>>8)).append("."); sb.append(String.valueOf(longIP&0x000000FF)); return sb.toString(); }
3、更改字符串的编码
先调用String的getBytes方法对字符串进行解码,再用得到的字节数组和新的字符编码构造一个新的String对象。
4、对字符串进行MD5编码
MD5是一种不可逆的加密方式,常用于管理账户信息数据库,数据库存储的是用户密码的MD5编码,这样可以防止用户的密码信息被管理员知道。
public static String encodeByMD5(String originString){ String[] hexDigits={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; if(originString!=null){ try{ MessageDigest md=MessageDigest.getInstance("MD5"); byte[] result=md.digest(originString.getBytes()); StringBuilder sb=new StringBuilder(); for(int i=0;i<result.length;i++){ int n=result[i]; if(n<0) n=256+n; int d1=n/16; int d2=n%16; sb.append(hexDigits[d1]+hexDigits[d2]); } return sb.toString(); }catch(Exception e){ } } return null; }
5、制作命令行程序
难点在于解析命令行参数,可以使用Apache组织的cli项目的类库来完成。
6、StringTokenizer可以使字符串分写成多个标记。
7、使用正则表达式操作字符串
(1)java.util.regex.Pattern类 对正则表达式字符串进行编译
(2)java.util.regex.Matcher类,通过解释Pattern对字符串进行匹配,find方法返回查找匹配的结果,matches方法返回精确匹配的结果。
8、使用正则表达式验证电话号码格式
public static boolean isMatch(String phoneNum){ String patternStr="^([0-9]{3}-?[0-9]{8}) |([0-9]{4}-?[0-9]{7})$"; if(phoneNum!=null){ return phoneNum.matches(patternStr); } return false; }
五、异常处理
1、避免使用异常
可以提前检测语句的使用条件,避免异常出现
2、不要为每个可能出现异常的语句单独设置try catch,尽量将这些语句都放在一个try块中。
3、避免在方法中抛出或捕获RuntimeException和Error
4、尽量catch具体的异常,不要总是catch Exception
5、不能处理的异常要往外抛
6、不要在循环体中使用try...catch
六、线程
1、线程的互斥
在某一个时刻,只允许一个线程访问对象的临界区
。如果一个对象有多个方法都要修改同一个变量的值,应将这些方法置为synchronized。
2、线程协作
wait、notify、notifyAll等关键字必须放在synchronized代码块中。
static class Printer extends Thread{ Vector task=new Vector(); boolean running=false; public void start(){ this.running=true; super.start(); } @Override public void run() { try{ while(running){ synchronized(this){ while((task.size()==0)&&running){ //如果任务为空,线程允许运行,则等待任务 //进入等待状态,释放对象锁 wait(); } } //执行任务 System.out.println("print the task:"+task.remove(0)); } }catch(InterruptedException e){ e.printStackTrace(); } } //添加打印任务 public void adddTask(String str){ synchronized(this){ this.task.add(str); //唤醒等待的线程 notify(); } } //停止线程 public void stopPrinter(){ this.running=false; synchronized(this){ //唤醒其他等待的线程 notify(); } } }
3、join
调用子线程的join方法,表示当前线程必须等待子线程运行结束,才能继续运行。
4、消费者与生产者
用线程模拟消费者和生产者,不断从仓库类中消费/生产产品。
在仓库类中,消费产品时,如果产品数量为0,则wait,使消费线程等待,当有新产品存入时,notify,唤醒等待的消费线程。同理,生产产品时,如果产品数量达到上限,则wait,使生产线程等待,当有产品被消费后,notify,唤醒等待的生产线程。
注意:调用某个对象的wait、notify、notifyAll等方法时,必须用synchronized先获得对象锁,否则会抛出IllegalMonitorStateException异常。
1 //(1)产品 2 public class Product { 3 private String name; 4 5 public Product(String name) { 6 this.name = name; 7 } 8 } 9 //(2)消费者线程 10 public class Consumer extends Thread { 11 private Warehouse warehouse; 12 private boolean running=false; 13 14 public Consumer(Warehouse warehouse, String name) { 15 super(name); 16 this.warehouse = warehouse; 17 } 18 19 public boolean isRunning() { 20 return running; 21 } 22 23 @Override 24 public synchronized void start() { 25 this.running=true; 26 super.start(); 27 } 28 29 @Override 30 public void run() { 31 Product product; 32 try{ 33 while(running){ 34 product=warehouse.getProduct(); 35 sleep(500); 36 } 37 }catch(InterruptedException e){ 38 e.printStackTrace(); 39 } 40 } 41 42 public void stopConsumer(){ 43 synchronized(warehouse){ 44 this.running=false; 45 warehouse.notifyAll(); 46 } 47 } 48 } 49 //(3)生产者线程 50 public class Producer extends Thread{ 51 52 private Warehouse warehouse; 53 private static int productName=0; 54 private boolean running=false; 55 56 public Producer(Warehouse warehouse, String name) { 57 super(name); 58 this.warehouse = warehouse; 59 } 60 61 public boolean isRunning() { 62 return running; 63 } 64 65 @Override 66 public synchronized void start() { 67 this.running=true; 68 super.start(); 69 } 70 71 @Override 72 public void run() { 73 Product product; 74 try{ 75 while(running){ 76 product=new Product("pro"+(++productName)); 77 this.warehouse.storageProduct(product); 78 sleep(300); 79 } 80 }catch(InterruptedException e){ 81 e.printStackTrace(); 82 } 83 } 84 85 86 public void stopProducer(){ 87 synchronized(warehouse){ 88 this.running=false; 89 warehouse.notifyAll(); 90 } 91 } 92 93 } 94 //(4)仓库类 95 public class Warehouse { 96 private static int CAPACITY=11;//仓库容量 97 private Product[] products; 98 99 private int front=0;//当前第一个未被消费的产品下标 100 private int rear=0;//当前最后一个未被消费的产品下标+1; 101 102 public Warehouse() { 103 this.products = new Product[CAPACITY]; 104 } 105 106 public Warehouse(int capacity) { 107 this(); 108 if(capacity>0){ 109 CAPACITY=capacity+1; 110 this.products = new Product[CAPACITY]; 111 } 112 } 113 114 public Product getProduct() throws InterruptedException { 115 synchronized(this){ 116 boolean consumerRunning=true; 117 Thread currentThread=Thread.currentThread(); 118 if(currentThread instanceof Consumer){ 119 consumerRunning=((Consumer)currentThread).isRunning(); 120 }else{ 121 return null; 122 } 123 //仓库中没有产品,则消费线程等待 124 while((front==rear) && consumerRunning){ 125 wait(); 126 consumerRunning=((Consumer)currentThread).isRunning(); 127 } 128 129 if(!consumerRunning){ 130 return null; 131 } 132 133 Product product=products[front]; 134 front=(front+1+CAPACITY) % CAPACITY; 135 System.out.println("Concumer"+Thread.currentThread().getName()); 136 System.out.println("剩余产品"+(rear+CAPACITY-front)%CAPACITY); 137 notify(); 138 return product; 139 } 140 } 141 142 public void storageProduct(Product product) throws InterruptedException { 143 synchronized(this){ 144 boolean producerRunning=true; 145 Thread currentThread=Thread.currentThread(); 146 if(currentThread instanceof Producer){ 147 producerRunning=((Producer)currentThread).isRunning(); 148 }else{ 149 return; 150 } 151 //仓库中没有产品,则消费线程等待 152 while(((rear+1)%CAPACITY==front) && producerRunning){ 153 wait(); 154 producerRunning=((Producer)currentThread).isRunning(); 155 } 156 157 if(!producerRunning){ 158 return; 159 } 160 161 products[rear]=product; 162 rear=(rear+1)%CAPACITY; 163 System.out.println("Producer"+Thread.currentThread().getName()); 164 System.out.println("剩余产品"+(rear+CAPACITY-front)%CAPACITY); 165 notify(); 166 } 167 } 168 169 }
5、两个同时启动的线程,通常优先级高的线程会先运行。
6、守护线程(Daemon线程)
Thread的setDaemon方法设置线程是否为守护线程。必须在调用start之前调用该方法,否则无效。
只有当程序中所有的非守护线程都结束时,守护线程才会无条件地立即结束,并且不会调用finally中的语句。
7、线程池
将执行某一类任务的线程放在线程池中,有任务要执行时,从池中取出一个空闲线程来处理任务,处理结束后,再将线程池放入池中。
自定义线程池
(1)任务接口
public interface Task { public void perform() throws Exception; }
(2)自定义任务类
public class MyTask implements Task { private int taskId=0; public MyTask(int id) { this.taskId=id; } @Override public void perform() throws Exception { System.out.println("task "+taskId+" begin"); try{ Thread.sleep(1000); }catch(InterruptedException e){ } System.out.println("task "+taskId+" end"); } }
(3)线程池
public class MyThreadPool extends ThreadGroup{ private boolean isAlive; private LinkedList taskQueue; private int threadId; private static int threadPoolId; public MyThreadPool(int numThreads) { super("ThreadPool-"+(threadPoolId++)); super.setDaemon(true); //线程池中所有线程被销毁时,线程池自动销毁 this.isAlive=true; this.taskQueue=new LinkedList(); for(int i=0;i<numThreads;i++){ new PooledThread().start(); } } //内部类,工作线程 private class PooledThread extends Thread{ public PooledThread() { super(MyThreadPool.this,"PooledThread-"+(threadId++)); } @Override public void run() { while(!isInterrupted()){ Task task=null; try{ task=getTask(); }catch(InterruptedException e){ } if(task==null){ return; } try{ task.perform(); }catch(Throwable t){ uncaughtException(this,t); } } } } protected synchronized Task getTask() throws InterruptedException{ if(!this.isAlive){ return null; } while(this.taskQueue.size()==0){ wait(); } return (Task)this.taskQueue.removeFirst(); } public synchronized void performTask(Task task){ if(!this.isAlive){ throw new IllegalStateException(); } if(task!=null){ this.taskQueue.add(task); notify(); } } //关闭线程池,所有线程停止,不再执行任务 public synchronized void close(){ if(isAlive){ this.isAlive=false; this.taskQueue.clear(); this.interrupt(); } } //关闭线程池,等待所有任务执行完成 public void join(){ synchronized(this){ this.isAlive=false; this.notifyAll(); } Thread[] threads=new Thread[this.activeCount()]; //将线程池中活动线程拷贝到新的线程组中 int count=this.enumerate(threads); for(int i=0;i<count;i++){ try{ threads[i].join(); }catch(InterruptedException e){ } } } }
8、当线程进入对象的synchronized代码块时,占有了该资源,直到退出该代码块或者调用wait方法,才会释放该资源,在此期间,其他线程将不能进入该代码块。synchronized尝试占有对象资源,如果不能占有,将一直等待。
线程相互占有对方等待的资源且都不主动释放所占有的资源时,将发生线程死锁。
9、定时器的使用
(1)实现一个继承TimerTask抽象类的自定义类MyTimerTask
(2)结合Timer实现定时执行任务的功能
Timer timer=new Timer(); TimerTask myTask1=new MyTimerTask(); timer.schedule(myTask1,200,300);//200ms后执行myTask1,之后每隔300ms执行一次myTask1
(3)中止定时任务
timer.cancle();
六、反射
1、反射(Reflection)允许Java程序对自身进行检查,并能直接操作程序的内部属性。
2、instanceof 在运行时判断对象的类型
3、java.lang.reflect包实现了java的反射机制。
七、网络编程
1、URL通信
2、Socket通信
3、UDP通信