温习之Java中的重点和难点

433人浏览 / 0人评论

  Java中有很多内容在开发项目的过程中并不常用,但是却是很重要的部分,为了避免忘记,今天重新温习了一遍Java中的重点和难点,借此机会记录一下方便以后查找。

本文主要分为以下几个部分:

  1.进制的相互转换

  2.Java中位运算符的解释和运用

  3.Java数组中常用的排序算法分析

  4.Java中折半查找方法的分析和运用

  5.Java中对象的初始化过程

  6.Java抽象类在模板方法模式中的运用

  7.Java多线程的难点和设计多线程程序时需要注意的问题

  8.Java中集合框架运用时需要注意的问题

  9.Java中IO难点和重点的分析

  10.Java网络编程的分析和运用

  11.Java中常用正则表达式的运用和技巧

 

第一部分:进制的相互转换

  1.十进制和二进制的相互转换

十进制转二进制:

 
  1. int num = 102;

  2. StringBuffer sb = new StringBuffer();

  3. while(num >= 1) {

  4.     sb.append(num%2);

  5.     num = (int) (num / 2);  

  6. }

  7. System.out.println(sb.reverse());

二进制转十进制:

 
  1. String binaryStr = "1100110";

  2. int num = 0;

  3. for (int i = 0; i < binaryStr.length(); i++){

  4.     num += Integer.parseInt(String.valueOf(binaryStr.charAt(binaryStr.length() - 1 - i))) << i;

  5. }

  6. System.out.println(num);

 

第二部分:Java中位运算符的解释和运用

Java中一共有7个位运算符分别是<<、>>、&、|、^、~、>>>

 

1.“<<”--左移运算符,参与左移运算的数字乘以2的左移位数次方,例如3<<2=3*22

 

2.“>>”--右移运算符,参与右移运算的数字除以2的右移位数次方,例如3>>2=3/22

 

3.“&” --与运算符,参与与运算的两个数字的二进制等位都为1时结果值的该位为1,其余情况为0,例如3&2=0011&0010=0010,与运算符和“>>>”运算符结合可以实现十进制转十六进制的功能,num&15 -> num>>>4,这样一组运算就能得到一个十六进制位,再将超过10的通过(num-10)+'A'转换为十六进制位

 

4.“|” --或运算符,参与或运算的两个数字的二进制等位至少有一个为1时结果值的该位为1,其余情况为0,例如3|2=0011|0010=0011

 

5.“^” --异或运算符,参与异或运算的两个数字的二进制等位如果不相同则为1,相同则为0,一个数字异或同一个数字两次则等于原数字。其中一个应用是在不使用第三个变量的情况下交换两个×××变量的值。

 
  1. int n = 4,m = 6;

  2. //此时n = n ^ m的值

  3. n = n ^ m; 

  4.  
  5. //此时m = n ^ m,因为上句代码执行后n = n ^ m,所以这里m = n ^ m = n ^ m ^ m = n(这里的m = n中的n = 4)

  6. m = n ^ m;

  7.  
  8. //此时m = n,n = n ^ m , 所以n = n ^ m = n ^ m ^ n=m(这里的n = m中的m = 6)

  9. n = n ^ m;

 

6.“~” --取反运算符,参与取反运算的数字的所有二进制位都取相反的值,0变成1,1变成0,因为一个正数的负数或者一个负数的正数等于它取反然后加1,所以一个数取反则等于该数乘以-1然后减去1

 

7.“>>>” --无符号右移,高位补零,功能和右移类似

 

第三部分:Java数组中常用的排序算法

  1.选择排序

 
  1. int[] attr = {3,6,5,85,2,44,1,46,67,0,45,4,134,123,112};

  2.  
  3. for(int x = 0;x < attr.length() - 1, x++) {

  4.     for(int y = x + 1; y < attr.length(); y++) {

  5.         if(attr[x]<attr[y]) {

  6.             attr[x] = attr[x] ^ attr[y];

  7.             attr[y] = attr[x] ^ attr[y];

  8.             attr[x] = attr[x] ^ attr[y];

  9.         }

  10.     }

  11. }

  12.  
  13. for(int i in attr) {

  14.     System.out.print(i + " ");

  15. }

 2.冒泡排序

 
  1. int[] attr = {3,6,5,85,2,44,1,46,67,0,45,4,134,123,112};

  2.  
  3. for(int x = attr.length() - 1;x >= 0; x--) {

  4.     for(int y = 0; y < x;y++) {

  5.         if(attr[y] < attr[y + 1]) {

  6.             attr[y] = attr[y] ^ attr[y + 1];

  7.             attr[x] = attr[y] ^ attr[y + 1];

  8.             attr[y] = attr[y] ^ attr[y + 1];

  9.         }

  10.     }

  11. }

  12.  
  13. for(int i in attr) {

  14.     System.out.print(i + " ");

  15. }

 

第四部分:Java中折半查找方法的分析和运用

  折半查找的原理是先将数组排序(从小到大,如果是从大到小则需要一些改变),然后找到数组中的中间数,然后把中间数和需要查找的数进行比较,如果需要查找的数小于中间数则将最大索引赋值为中间结果索引+1,反之则把最小索引赋值为中间结果-1。代码如下:

 
  1. int[] attr = {3,6,5,85,2,44,1,46,67,0,45,4,134,123,112};

  2.  
  3. int min = 0;

  4. int max = attr.length();

  5. int mid = (int) (min + max) / 2;

  6.  
  7. Arrays.sort(attr);

  8.  
  9. int key = 67;

  10. int keyIndex = -1;

  11. while(min <= max) {

  12.     

  13.     if(key < attr[mid]) {

  14.         max = mid + 1;

  15.     } else if(key > attr[mid]) {

  16.         min = mid - 1;

  17.     } else {

  18.         keyIndex = mid;

  19.         break;

  20.     }

  21.     

  22.     mid = (int) (min + max) / 2;

  23. }

  24.  
  25. if(keyIndex != -1) {

  26.     System.out.println(attr[mid]);

  27. }

 

 

第五部分:Java中对象的初始化过程

  1. 初始化静态代码块

  2. 初始化属性默认值

  3. 初始化属性显示设置值

  4. 初始化构造代码块

  5. 初始化构造函数

 

第六部分:Java抽象类在模板方法模式中的运用

这里举一个简单的示例代码来说明,代码如下:

 
  1. //首先声明一个抽象类,这个抽象类的作用是计算一段代码的执行时间

  2. public abstract class GetTime {

  3.     public final void getDoWorkTime() {

  4.         int start = System.currentTimeMillis();

  5.         doWork();

  6.         int end = System.currentTimeMillis();

  7.         

  8.         System.out.println("工作时间:" + (start - end));

  9.     }

  10.     

  11.     public abstract void doWork();

  12. }

  13.  
  14. //声明一个GetTime类的子类,并实现doWork方法

  15. public class SubGetTime extends GetTime {

  16.     @Override

  17.     public void doWork() {

  18.         System.out.println("做一些工作");

  19.     }

  20. }

  21.  
  22. public class Test {

  23.     public static void main(String[] args) {

  24.         SubGetTime getTime = new SubGetTime();

  25.         getTime.getDoWorkTime();

  26.     }

  27. }

  28.  
  29. //这里的doWork方法声明为抽象方法,然后交给子类去实现需要做的工作,这种方式就是模板方法模式,这是设计模式中行为模式中的一种

 

第七部分:Java多线程的难点和设计多线程程序时需要注意的问题

  Java多线程中的难点和重点主要是线程安全的问题,这里就主要说一下线程安全的问题,因为在JDK1.5后Java引入了Lock和Condition来代替synchronized、wait和notify,所以这里分两种情况来讨论。

  首先在Java中创建线程的方式有两种,第一种是继承Thread类然后复写run方法,第二种方式是实现Runable接口并实现run方法。

  继承Thread:

 
  1. public class SaveMoney extends Thread {

  2.     @Override

  3.     public void run() {

  4.         System.out.println("存钱");

  5.     }

  6. }

  7. public class GetMoney extends Thread {

  8.     @Override

  9.     public void run() {

  10.         System.out.println("取钱");

  11.     }

  12. }

  13. public class BankTest {

  14.     public static void main(String[] args) {

  15.         SaveMoney saveMoneyThread = new SaveMoney();

  16.         GetMoney  getMoneyThread  = new GetMoney();

  17.         saveMoneyThread.start();//启动线程,这里如果调用run是执行run方法不是启动线程,需要注意

  18.         getMoneyThread.start();

  19.     }

  20. }

  实现Runable接口:

 
  1. public class SaveMoney implements Runable {

  2.     public void run() {

  3.         System.out.println("存钱");

  4.     }

  5. }

  6. public class GetMoney implements Runable {

  7.     public void run() {

  8.         System.out.println("取钱");

  9.     }

  10. }

  11. public class BankTest {

  12.     public static void main(String[] args) {

  13.         new Thread(new SaveMoney()).start();//启动线程,这里如果调用run是执行run方法不是启动线程,需要注意

  14.         new Thread(new GetMoney()).start();

  15.     }

  16. }

下面就在JDK1.5之前和JDK1.5之后两种情况下结合银行取钱和存钱的例子来说明线程同步的问题

JDK1.5之前:

 
  1. //首先创建一个用户帐户类

  2. public class BankAccont {

  3.     

  4.     private String accontName = "";

  5.     private Double totalMoney = 0d;

  6.     

  7.     public BankAccont(String accontName, Double initMoney) {

  8.         this.accontName = accontName;

  9.         this.totalMoney = initMoney;

  10.     }

  11.     

  12.     public void saveMoney(Double money) {

  13.         this.totalMoney += money;

  14.         System.out.println("存了" + money + "块钱");

  15.     }

  16.     

  17.     public void getMoney(Double money) {

  18.         this.totalMoney -= money;

  19.         System.out.println("取了" + money + "块钱");

  20.     }

  21.     

  22.     public String toString() {

  23.         System.out.println(this.accontName + "总共还有" + this.totalMoney + "元人民币");

  24.     }

  25. }

  26.  
  27. //分别创建存钱和取钱的线程,使用实现Runable接口的方式这种方式可以轻松的让不同的线程执行相同的任务,除非程序员打算修改或增强类的基本行为,否则不应为该类(Thread)创建子类

  28. public class SavaMoney implements Runable {

  29.     private BankAccont accont = null;

  30.     public SaveMoney(BankAccont accont) {

  31.         this.accont = accont;

  32.     }

  33.     public void run() {

  34.              //这里使用同一个锁进行同步

  35.              synchronized(BankAccont.class) {

  36.             while(true) {

  37.               this.accont.saveMoney(100);

  38.           }

  39.        }

  40.     }

  41. public class GetMoney implements Runable {

  42.     private BankAccont accont = null;

  43.     public GetMoney(BankAccont accont) {

  44.         this.accont = accont;

  45.     }

  46.     public void run() {

  47.             //这里使用同一个锁进行同步

  48.             synchronized(BankAccont.class) {

  49.             while(true) {

  50.                 this.accont.getMoney(100);

  51.             }

  52.         }

  53.     }

  54. }

  55. public class BankTest {

  56.     public static void main(String[] args) {

  57.         BankAccont accont = new BankAccont("张三", 1000);

  58.         

  59.         new Thread(new SaveMoney(accont)).start();

  60.         new Thread(new GetMoney(accont)).start();

  61.         

  62.         accont.toString();

  63.     }

  64. }

JDK1.5之后:

 
  1. //首先创建一个用户帐户类

  2. public class BankAccont {

  3.     

  4.     private String accontName = "";

  5.     private Double totalMoney = 0d;

  6.     

  7.     private final Lock lock = new RentrantLock();

  8.     private final Condition condition_save = lock.newCondition();

  9.     private final Condition condition_get  = lock.newCondition();

  10.     

  11.     public BankAccont(String accontName, Double initMoney) {

  12.         this.accontName = accontName;

  13.         this.totalMoney = initMoney;

  14.     }

  15.     

  16.     public void saveMoney(Double money) {

  17.         lock.lock();

  18.         condition_get.await();//这里引用不合适,只是一个示例

  19.         this.totalMoney += money;

  20.         System.out.println("存了" + money + "块钱");

  21.         condition_get.signal();//这里引用不合适,只是一个示例

  22.         lock.unlock();

  23.     }

  24.     

  25.     public void getMoney(Double money) {

  26.         lock.lock();

  27.         condition_save.await();//这里引用不合适,只是一个示例

  28.         this.totalMoney -= money;

  29.         System.out.println("取了" + money + "块钱");

  30.         condition_save.signal();//这里引用不合适,只是一个示例

  31.         lock.unlock();

  32.     }

  33.     

  34.     public String toString() {

  35.         System.out.println(this.accontName + "总共还有" + this.totalMoney + "元人民币");

  36.     }

  37. }

  38.  
  39. //分别创建存钱和取钱的线程,使用实现Runable接口的方式这种方式可以轻松的让不同的线程执行相同的任务,除非程序员打算修改或增强类的基本行为,否则不应为该类(Thread)创建子类

  40. public class SavaMoney implements Runable {

  41.     private BankAccont accont = null;

  42.     public SaveMoney(BankAccont accont) {

  43.         this.accont = accont;

  44.     }

  45.     public void run() {

  46.             while(true) {

  47.               this.accont.saveMoney(100);

  48.           }

  49.     }

  50. public class GetMoney implements Runable {

  51.     private BankAccont accont = null;

  52.     public GetMoney(BankAccont accont) {

  53.         this.accont = accont;

  54.     }

  55.     public void run() {

  56.             while(true) {

  57.                 this.accont.getMoney(100);

  58.             }

  59.     }

  60. }

  61. public class BankTest {

  62.     public static void main(String[] args) {

  63.         BankAccont accont = new BankAccont("张三", 1000);

  64.         

  65.         new Thread(new SaveMoney(accont)).start();

  66.         new Thread(new GetMoney(accont)).start();

  67.         

  68.         accont.toString();

  69.     }

  70. }

  以上只是一个简单的示例,需要根据需要进行修改。在设计多线程程序的时候需要多考虑线程同步的问题(线程安全),在多线程中还有一个问题就是Java中有哪些线程安全的集合?

  Java中线程安全的集合分别是Vector(向量,已经不常用了)、HashTable、Enumeration(枚举),除了这几个其余都为线程不安全集合。StringBuffer和StringBuider的差别也是StringBuffer为线程安全,StringBuider为线程不安全。

  Java多线程相关的问题,暂时只想到这些,再想起的时候再补充。

转载于:https://blog.51cto.com/chrischen/1743505

全部评论