精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java和C++在細節上的差異:接口與內部類

開發 后端
本文主要從接口與內部類以及異常和斷言方面講解了Java和C++在細節上的差異。

繼上篇文章:Java和C++在細節上的差異:枚舉與反射

 六、接口與內部類:

1. 接口和抽象類:Java通過interface關鍵字來表示接口,接口中不能包含非靜態域字段,所有的域成員均是公有的抽象方法,如Comparable接口,如果希望利用Arrays.sort方法,數組的成員必須實現該接口。抽象類中包含抽象方法,和接口一樣抽象類也不能被實例化。

1) 接口不能被實例化,但是可以聲明接口的變量指向其實現類的對象。

2) 每個類只能有一個超類,但是可以實現多個接口。

以下為Java的接口和抽象類的定義方式:

  1. public interface Comparable { 
  2. int compareTo(Object other); 
  3.  
  4. public interface Comparable<T> { 
  5. int compareTo(T other); 
  6.  
  7. abstract class Employee implements Comparable { 
  8. public abstract int compareTo(Object other); 

在C++中同樣存在接口和抽象類的概念,也和Java一樣不能被實例化,但是并沒有相應的關鍵字存在,而是以一種潛在規則的方式存在,見如下代碼:

  1. //Comparable對象聲明的方法中只有純虛方法存在(析構函數除外),且沒有任何成員變量。 
  2. class Comparable { 
  3. public
  4. virtual ~Comparable() {} 
  5. //compareTo為純虛方法 
  6. virtual int compareTo(Comparable& other) = 0
  7.  
  8. //Employee對象中存在部分純虛方法,且可以有成員變量存在。 
  9. class Employee { 
  10. public
  11. virtual int compareTo(Comparable& other) { return 0; } 
  12. virtual int backgroud() = 0
  13.  
  14. private
  15. int _age; 

在C++的實現中,基于接口編程,同時導出C接口的工廠方法對于跨編譯器極為重要,該方式比較類似于Windows中的COM技術。

C++支持多重繼承,因此也存在虛基類(菱形結構)等問題帶來的負面影響,既子類的兩個父類中同時存在相同簽名的虛方法。見如下代碼:

  1. class TcpServerTask { 
  2. public
  3. virtual void run() {} 
  4.  
  5. class SentObjectTask { 
  6. public
  7. virtual void run() {} 
  8.  
  9. class TcpServerSentTask : public TcpServerTask, public SentObjectTask { } 

2. 對象克隆: Object對象中存在protected類型的clone方法,該方法將會完成子類對象clone的缺省操作,既對象域字段的淺拷貝,如果該對象的成員均為原始類型,如int、float等,或者為不可變類型,如String。這樣的淺拷貝將能夠達到對象clone的預期。換言之,如果對象內部存在可變對象的引用,淺拷貝將會帶來原始對象和cloned對象引用相同對象引用的問題。如果希望避免該問題的發生,子類需要實現Cloneable接口。這里需要指出的是Cloneable接口并未提供clone方法,只是提供了一種契約簽名。子類真正做的還是重載Object方法中的clone方法,由于Object中該方法為protected方法,所以caller不能直接調用它,只能將子類的clone方法聲明為共有類型,caller才能調用。

  1. //該實現類使用淺拷貝已經可以滿足其需要了 
  2. public class implements Cloneable { 
  3. //這里已經提升了clone方法的級別為public。 
  4. public Employee clone() throws CloneNotSupportedException { 
  5. return (Employee)super.clone(); 
  6. //深拷貝clone方法,必須clone對象內部所有可變的實例域,其中這些可變類 
  7. //必須全部都實現了自己的clone方法,否則將會跑出異常。 
  8. public class Employee implements Cloneable { 
  9. public Employee clone() throws CloneNotSupportedException { 
  10. //缺省clone完成了域字段的按位淺拷貝。 
  11. Employee cloned = (Employee)super.clone(); 
  12. cloned.hireday = (Date)hireday.clone(); 
  13. private Date hireday; 

注:數組對象可以通過Array的clone(public)方法完成元素的拷貝。

在C++中由于并不存在Object這樣的單根結構的框架,因此C++是以另外一種方式表現該問題的,既缺省拷貝構造和缺省等于操作符重載。和Java類似,這兩個方法也是member bitwise拷貝的,但這是由編譯器在生成對象模型時自動完成的缺省行為,如果該類重載了拷貝構造函數和等于操作符,在需要copy的時候則會調用重載后的方法,類的實現者應該在這兩個方法中完成深拷貝。C++中還可以通過將這兩個方法顯示的聲明為private類型的方法來禁用這種對象之間的copy行為,一旦出現,編譯器將會在在編譯器報錯。在C++中還存在一個explicit的關鍵字,可以有效的防止編譯器通過自行推演隱式的調用對象的拷貝構造函數和等于操作符函數,見如下代碼:

  1. //該類將會使用缺省的copy constructor,因此也會出現兩個對象 
  2. //引用相同_name變量地址的問題。 
  3. class Employee { 
  4. private
  5. char* _name; 
  6. }; 
  7. //該類由于將這兩個方法私有化,一旦出現對象的隱式拷貝構造, 
  8. //將會導致編譯錯誤。 
  9. class Employee { 
  10. private
  11. Employee(Employee& other); 
  12. const Employee& operator= (Employee& other); 
  13. private
  14. char* _name; 
  15. }; 
  16. //將會調用重載后的這兩個函數 
  17. class Employee { 
  18. Employee(Employee& other); 
  19. const Employee& operator= (Employee& other); 
  20. private
  21. char* _name; 
  22. }; 

注:C++中有一種被稱為引用計數的技術,經常會用在這個地方,以便提高對象copy的效率。

3. 接口與回調:嚴格意義上講,回調這個屬于更多的應用于C/C++這些支持基于過程編程的語言,Java中的回調是通過接口的方式來實現的,由于在接口的實現類中可以附帶更多的信息,因此其表達能力要由于C/C++中的函數指針,見如下代碼:

  1. public class Thread { 
  2. public Thread(Runnable r) {} 
  3.  
  4. public class MyTask implements Runnable { 
  5. public MyTask(int taskID) { 
  6. _taskID = taskID; 
  7.  
  8. public void setOk(bool ok) { 
  9. _ok = ok; 
  10.  
  11. public void run() {} 
  12.  
  13. public static void main(String[] args){ 
  14. MyTask t = new MyTask(5); 
  15. Thread thrd = new Thread(t); 
  16. t.setOk(true); 
  17. thrd.start(); 

這里的Runnable參數既為接口,Thread對象在啟動的時候會調用該接口實現對象的run方法,但是在調用之前可以給該實現類傳入更多的狀態等相關數據,以便在線程類調用run方法時可以得到更多的信息。
以下為回調函數在C/C++中的實現:

  1. typedef int(*TestCallback)(int,int); 
  2. int testCaller(TestCallback cb,int a,int b) { 
  3. return cb(a,b); 
  4.  
  5. int testCallback(int a,int b) { 
  6. return a * b; 
  7.  
  8. int main() { 
  9. TestCallback cb = testCallback; 
  10. return testCall(cb,5,6); 

在C++中還可以通過模板以更加松散的方式完成類似Java的基于接口的回調(Java的回調方式,C++完全可以做到),見如下代碼:

  1. template<typename T> 
  2. class Thread { 
  3. public
  4. Thread(T* r) _r = r {} 
  5. void start() { if (_r) _r->run(); } 
  6. private
  7. T* _r; 

在以上的實現中,T無需是某個接口的實現類,只要保證該類型包含run()方法即可,注意:C++中的模板是引用才編譯的方式,如果沒有任何Thread<T>的聲明,不會導致任何編譯錯誤,只有當聲明的類型對象中不包含run()方法時才會導致編譯錯誤。

4. 內部類:Java中內部類可以為私有內部類,既只有外部類可以訪問該內部類,而Java外部類的可見性只有包可見和public兩種。C++中的內部類比較類似于Java中的靜態內部類,只是一種作用域限制的行為,以下為Java非靜態內部類的說明:

1) 內部類可以訪問外部類的所有域成員和域字段,這也同樣包括私有的字段和成員。

2) Java的編譯器在構造外部類調用內部類構造方法時,自動將外部類的this變量作為一個隱式參數傳給了內部類的構造函數,內部類則在構造函數中保留了this變量的引用,該行為為編譯器隱式行為。

  1. public class Employee { 
  2. public class InnerClass { 
  3. bool test() { 
  4. //這里的_jobYears為外部類域字段。 
  5. return _jobYears > 10
  6.  
  7. public Employee(int jobYears,String name) {  
  8. _name = name;  
  9. _jobYears = jobYears;  
  10. _salary = 0
  11.  
  12. public void raiseSalary() { 
  13. //編譯器的會將以下構造隱式替換為InnerClass inner = new InnerClass(this); 
  14. //因為Java在為其編譯的時候發現InnerClass為非靜態內部類,則自動添加了以下構造: 
  15. //public InnerClass(Employee e) 
  16. InnerClass inner = new InnerClass(); 
  17. if (test())  
  18. _salary += 1000
  19. private String _name; 
  20. private int _jobYears; 
  21. private int _salary; 

注:針對以上事例,內部類InnerClass可以通過Employee.this._jobYears的全稱來顯式的代替_jobYears > 10 中的_jobYears。反過來在raiseSalary方法中可以通過this.new InnerClass()語法格式更加明確的創建InnerClass的對象。

  1. public class Employee {  
  2. public class InnerClass {  
  3. bool test() {  
  4. //這里的_jobYears為外部類域字段。  
  5. return Employee.this._jobYears > 10;  
  6. }  
  7. }  
  8.   
  9. public Employee(int jobYears,String name) {   
  10. _name = name;   
  11. _jobYears = jobYears;   
  12. _salary = 0;  
  13. }  
  14.   
  15. public void raiseSalary() {  
  16. //這里也可以不使用this作為內部該內部類對象的外部類對象  
  17. //引用,可以根據需要替換為其他外部類對象的引用,如:  
  18. // Employee other = new Employee();  
  19. // InnerClass innser = other.new InnerClass();  
  20. InnerClass inner = this.new InnerClass();  
  21. if (test())   
  22. _salary += 1000;  
  23. }  
  24. ......  
  25. }  

注:在外部類的作用域之外調用public內部類的語法為 OutClass.InnerClass。

3) 局部內部類的可見范圍僅僅限于聲明該局部類的函數內部,見如下代碼:

  1. public void start() { 
  2. class TimePrinter implements ActionListener { 
  3. public void actionPerformed(ActionEvent e) { 
  4. Date now = new Date(); 
  5. System.out.println("At the tone,the time is " + now); 
  6. //beep為外部類的域字段 
  7. if (beep) 
  8. Tookkit.getDefaultToolkit().beep(); 
  9. ActionListener l = new TimePrinter(); 
  10. new Timer(interval,l).start(); 

局部類同樣可以訪問函數內部的局部變量,但是要求該變量必須是final的。

  1. public void start(final bool beep) { 
  2. class TimePrinter implements ActionListener { 
  3. public void actionPerformed(ActionEvent e) { 
  4. Date now = new Date(); 
  5. System.out.println("At the tone,the time is " + now); 
  6. //beep為外部函數的局部變量。 
  7. if (beep) 
  8. Tookkit.getDefaultToolkit().beep(); 
  9. ActionListener l = new TimePrinter(); 
  10. new Timer(interval,l).start(); 

為了規避局部類只能訪問final局部變量的限制,既一次賦值之后不能再被重新賦值。但是我們可以通過數組的方式進行巧妙的規避,在下例中數組counter對象本身是final的,因此他不可以被重新賦值,然而其引用的數組元素則可以被重新賦值,見下例:

  1. public void test() { 
  2. final int[] counter = new int[1]; 
  3. for (int i = 0; i < dates.length; ++i) { 
  4. dates[i] = new Date() { 
  5. public int compareTo(Date other) { 
  6. //這里如果counter不是數組,而是被定義為final int counter, 
  7. //則會導致編譯失敗。 
  8. counter[0]++; 
  9. return super.compareTo(other); 

C++中同樣可以做到這些,其規則和Java的主要差異為C++的內部類無法直接訪問外部類的任何成員。

  1. class OuterClass { 
  2. public
  3. void testOuter() { 
  4. class FunctionInnerClass { 
  5. public
  6. void test() { 
  7. printf("This is FunctionInnerClass.\n"); 
  8. }; 
  9. FunctionInnerClass innerClass; 
  10. innerClass.test(); 
  11. }; 
  12.  
  13. int main() 
  14. OuterClass outer; 
  15. outer.testOuter(); 
  16. return 0; 

4) 匿名內部類,其基本規則和局部內部類相似,差別在于該內部類不能有聲明構造函數,這主要是因為Java要求類的構造函數和類名相同,而匿名內部類自身沒有類名,因此在new新對象的時候,傳入的構造函數參數為超類的構造函數參數。C++中不支持匿名類。見下例:

  1. public void start(final bool beep) { 
  2. ActionListener l = new ActionListener() { 
  3. public void actionPerformed(ActionEvent e) { 
  4. Date now = new Date(); 
  5. System.out.println("At the tone,the time is " + now); 
  6. //beep為外部函數的局部變量。 
  7. if (beep) 
  8. Tookkit.getDefaultToolkit().beep(); 
  9. new Timer(interval,l).start(); 

5) 靜態內部類,其功能和C++中的嵌套類非常相似,但是和Java自身的非靜態內部類之間還是存在一些差異,如靜態內部類不能直接訪問外圍類的對象引用域字段,但是可以訪問外部類的static域字段(包括private)。在Java中只有內部類可以被定義為static的,外圍類是不可以這樣定義的。

  1. public class TestMain { 
  2. private static boolean classField = false
  3. private boolean objectField = false
  4. static class InnerClass { 
  5. public void test() { 
  6. //這里由于classField是靜態域字段,所以靜態內部類可以直接訪問, 
  7. //但是對于objectField對象域字段而言,由于靜態內部類中沒有包含 
  8. //外部類的引用,因此不能直接訪問objectField. 
  9. if (classField)  
  10. System.out.println("Hello."); 
  11.  
  12. public static void main(String[] args) { 
  13. classField = true
  14. new InnerClass().test(); 

以下示例中的內部類只能是靜態內部類,因為該外部類的靜態方法在返回內部類的實例時,無法將一個外部類的對象引用傳遞給該內部類,因為必須要求該內部類為靜態內部類,否則將會報編譯錯誤。

  1. public class TestMain { 
  2. static class InnerClass { 
  3. public void test() { 
  4. System.out.println("Hello.\n"); 
  5.  
  6. private static InnerClass createInnerClass() { 
  7. return new InnerClass(); 
  8. public static void main(String[] args) { 
  9. createInnerClass().test(); 

如果InnerClass不是靜態內部類,則需要將上例改寫為:

  1. public class TestMain { 
  2. class InnerClass { 
  3. public void test() { 
  4. System.out.println("Hello.\n"); 
  5.  
  6. private static InnerClass createInnerClass() { 
  7. //為了確保InnerClass可以得到外部類的對象引用。 
  8. return new TestMain().new InnerClass(); 
  9. public static void main(String[] args) { 
  10. createInnerClass().test(); 

6) 代理類:通過以下代碼step by step解釋代理類的機制

  1. import java.lang.reflect.InvocationHandler; 
  2. import java.lang.reflect.Proxy; 
  3. import java.util.Arrays; 
  4. import java.util.Random; 
  5.  
  6. public class TestMain { 
  7. public static void main(String[] args) { 
  8. Object[] elements = new Object[1000]; 
  9. for (int i = 0; i < elements.length; ++i) { 
  10. Integer v = i + 1
  11. //h(調用處理接口)是代理類的核心處理單元。由于代理類對象只是包含了InvocationHandler 
  12. //這樣一個對象實例,并且是存放于超類Proxy中的,而實際的被代理實例必須存放于InvocationHandler 
  13. //的實現類中,如這里的Integer對象v。其中的核心代理代碼也是在InvocationHandler子類的 
  14. //invoke方法中完成的。 
  15. InvocationHandler h = new TraceHandler(v); 
  16. //1. 第一個參數表示ClassLoader,這里使用缺省加載器,因此傳入null即可。 
  17. //2. 第二個參數表示該代理類需要implement的接口數組(Java中可以實現多個接口)。 
  18. //3. 調用處理器接口,是代理類如果實現代理的核心,后面會介紹該類。 
  19. //4. 將該代理類作為Integer的代理存入數組。 
  20. elements[i] = Proxy.newProxyInstance(nullnew Class[] {Comparable.class}, h); 
  21. Integer key = new Random().nextInt(elements.length) + 1
  22. //1. 由于代理類也都實現Comparable接口,因此可以用于Arrays.binarySearch中。 
  23. //2. 對代理類進行二分查找的比較時,將會直接調用代理類的compareTo方法。 
  24. //3. 該自動生成的Proxy的子類,其中的compareTo方法會將所有外部調用的信息,連同 
  25. // 方法名一并傳給其內部調用處理器對象的invoke方法,并調用該方法(invoke). 
  26. //4. 這里Proxy子類會將所有實例化時指定接口(Comparable)的方法(compareTo),以及 
  27. // Object中toString、equals和hashCode方法的調用都會傳遞給調用處理器的invoke方法。 
  28. //5. 因此在輸出結果中不僅可以看到compareTo方法的調用被打印出,toString也可打印。 
  29. int result = Arrays.binarySearch(elements, key); 
  30. if (result >= 0
  31. System.out.println(elements[result]); 
  32.  
  33. class TraceHandler implements InvocationHandler { 
  34. //由于Proxy的子類是動態生成的,其具體的實現也是編譯器動態生成后傳給JVM的。 
  35. //因此這里是整個代理機制中唯一存放被代理對象的地方。 
  36. public TraceHandler(Object t) { 
  37. target = t; 
  38.  
  39. //在此例中,該方法是被Comparable接口中的compareTo方法調用的,該實現邏輯是位于該 
  40. //動態生成的Proxy子類中,如  
  41. //public MyProxy extends Proxy implements Comparable { 
  42. // int compareTo(Object other) { h.invoke(...); } 
  43. @Override 
  44. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  45. //打印出實際被調用方法的名稱和參數值。 
  46. System.out.print(target); 
  47. System.out.print("." + method.getName() + "("); 
  48. if (args != null) { 
  49. for (int i = 0; i < args.length; ++i) { 
  50. System.out.print(args[i]); 
  51. if (i < args.length - 1
  52. System.out.print(", "); 
  53. System.out.println(")"); 
  54. //交給被代理類做實際的比較。 
  55. return method.invoke(target, args); 
  56. private Object target = null
  57. /* 輸出結果如下: 
  58. 500.compareTo(128) 
  59. 250.compareTo(128) 
  60. 125.compareTo(128) 
  61. 187.compareTo(128) 
  62. 156.compareTo(128) 
  63. 140.compareTo(128) 
  64. 132.compareTo(128) 
  65. 128.compareTo(128) 
  66. 128.toString() 
  67. 128 */ 

#p#

七、異常和斷言:

1. 異常處理:

1) 異常規范表示對于"已檢查"(checked)異常,如FileNotFoundException等,既在程序運行期間可以預測到的邏輯問題引發的異常,對于該類異常,需要在包含該異常的函數聲明部分標識出來,該函數可能會引發此類異常,如:

  1. public Image loadImage(String s) throws IOException, MalformedURLException 

如果在loadImage中仍然存在其他"已檢查",但是沒有在函數的異常規范中聲明出來,那么將會導致編譯失敗,因此對于函數中所有"已檢查"必須按照Java異常規范的要求,在函數的聲明中予以標識。對于該函數(loadImage)的調用者而言,在調用該函數時,必須將其放入try塊中,同時在catch字句中捕捉異常規范中標識的異常或他們的超類。
對于"運行時異常"(unchecked or runtime),由于大多是程序Bug或JVM問題所致,因此不可預測性極強,如ArrayIndexOutOfBoundException,對于該類異常無需在函數的異常規范部分予以聲明。

在C++標準中也同樣存在異常規范的說法,如

  1. File* loadFile(const char* s) throw std::bad_error 

所不同的是C++沒有明確的要求如果函數內部拋出了該異常,則必須在函數聲明的異常規范部分予以聲明,對于函數調用者而言也同樣沒有這樣的規定,必須捕獲其中的異常,因此異常規范在目前的C++編譯器中只是一種提示性的聲明。Java和C++在異常規范方面還存在的另一個區別是,C++中,如果函數沒有throw字句,那么該函數仍然可以拋出任何異常,但是對于Java的"已檢查"(checked)異常則必須通過throws字句聲明。

2) 如何拋出異常,在此方面,Java和C++沒有太大的差異,唯一的不同是Java拋出的異常必須是Throwable的實現類,C++中則沒有這樣的限制,也不存在這樣的異常接口。見如下代碼:

  1. public void howToThrowException() { 
  2. if (someErrorOccurred) 
  3. //1. 通過throw關鍵字直接拋出指定異常類型的對象即可。 
  4. throw new MyCheckedException(); 

3) 異常捕捉:由于Java中所有的異常均繼承自Throwable,所以catch(Throwable e)可以捕捉所有類型的異常,無論該異常是否為checked or unchecked異常,但是C++中并不存在這樣的異常祖先接口,因此如果想達到這樣的效果需要使用catch(...)關鍵字,這同樣表示捕捉所有的異常。

4) 異常鏈:當異常第一次拋出并且被catch住的時候,catch塊中的代碼可以再次拋出捕捉到的異常,同時也可以為了使上層業務邏輯能夠得到更加清晰的判斷,在第一次捕捉到異常后重新定義一個新的異常并再次拋出。有的時候,如果上層邏輯在需要的時候依然可以看到原始異常,將會對錯誤的處理更加合理。在Java中可以通過異常鏈的方式達到這樣的效果,見如下代碼:

  1. public void testExceptionChain() throws MyCustomizedFileException { 
  2. try { 
  3. FileInputStream in = new FileInputStream("myfile"); 
  4. catch (FileNotFoundException e) { 
  5. //定義了新的,準備再次被拋出的異常對象。 
  6. Throwable te = new MyCustomizedFileException("access file error."); 
  7. //將原始異常鏈接到該異常對象的內部,以供之后需要時通過getCause()方法重新獲取。 
  8. te.initCause(e); 
  9. throw te; 
  10.  
  11. public static void main(String[] args) { 
  12. try { 
  13. testExceptionChain(); 
  14. catch (MyCustomizedFileException e) { 
  15. //獲取該異常對象的原始異常。 
  16. Throwable te = e.getCause(); 
  17. System.out.println(te.getClass().getName()); 
  18. /* 輸出結果如下: 
  19. FileNotFoundException 
  20. */ 

5) finally字句:在Java的異常機制中存在finally這樣的關鍵字,其塊中的代碼無論異常是否發生都將會被執行,從而可以確保函數內部分配或者打開的資源都能在函數內部進行釋放或者關閉,如Socket連接、DB連接,見如下代碼:

  1. public void testFinally() { 
  2. InputStream in = null
  3. try { 
  4. in = new FileInputStream("myfile"); 
  5. catch (IOException e) { 
  6. //TODO: do something for this exception. 
  7. finally { 
  8. in.close(); 
  9. //Do the following code. 

在以上的代碼中,無論try塊中異常是否發生,finally塊中的代碼"in.close()" 都將會在函數退出之前或catch處理之后被執行,從而保證了FileInputStream對象能夠在函數退出之前被關閉。然而這樣的做法仍然可能導致一些影響代碼流程的問題,如果try塊中的代碼沒有產生異常,而是在finally中的in.close引發了異常,那么整個try{}catch{}finally{}代碼塊之后的代碼將不會被執行,而是直接退出該函數,同時拋出in.close()引發的異常給該函數的調用者。修正代碼如下:

  1. public void testFinally() { 
  2. InputStream in = null
  3. try { 
  4. in = new FileInputStream("myfile"); 
  5. catch (IOException e) { 
  6. //TODO: do something for this exception. 
  7. finally { 
  8. try { 
  9. in.close(); 
  10. catch (IOException e) { 
  11. //Do the following code. 

在C++中,由于對象是可以在棧上聲明并且分配空間的,當棧退出后會自行調用該對象的析構函數,因此該對象的資源釋放代碼可以放在類的析構函數中。該方式對于一個多出口的函數而言也是非常有效的,特別是對于加鎖和解鎖操作需要在同一個函數中完成,為了防止在某個退出分支前意外的漏掉解鎖操作,可以采用該技巧,見如下代碼:

  1. template<typename LockT> 
  2. class ScopedLock { 
  3. public
  4. ScopedLock(T& lock) : _lock(lock) { 
  5. _lock.lock(); 
  6.  
  7. ~ScopedLock() { 
  8. _lock.unlock(); 
  9. private
  10. LockT _lock; 
  11. }; 
  12.  
  13. void testFunc() { 
  14. ScopedLock s1(myLock); 
  15. if (cond1) { 
  16. return
  17. else if (cond2) { 
  18. //TODO: do something 
  19. return
  20. else { 
  21. //TODO: do something 
  22. return

對于以上代碼,無論函數從哪個分支退出,s1的析構函數都將調用,因此myLock的解鎖操作也會被調用。

6) 異常堆棧跟蹤:通過Throwable的getStackTrace方法獲取在異常即將被拋出的時間點上程序的調用堆棧,這樣有利于日志的輸出和錯誤的分析,見如下代碼:

  1. public void testStackTrace() { 
  2. try { 
  3. //TODO: call function, which may be raise some exception. 
  4. catch (Throwable e) { 
  5. StackTraceElement[] frames = e.getStackTrace(); 
  6. for (StackTraceElement f : frames) { 
  7. System.out.printf("Filename is = %s\n",f.getFileName()); 
  8. System.out.printf("LineNumber is = %d\n",f.getLineNumber()); 
  9. System.out.printf("ClassName is = %s\n",f.getClassName()); 
  10. System.out.printf("Methodname is = %s\n",f.getMethodName()); 
  11. System.out.printf("isNativeMethod = %s\n",f.isNativeMethod() ? "true" : "false"); 

也可以直接通過Throwable對象函數當前函數的運行棧信息,見如下代碼:

  1. public static void main(String[] args) { 
  2. Throwable e = new Throwable(); 
  3. StackTraceElement[] frames = e.getStackTrace(); 
  4. for (StackTraceElement f : frames) { 
  5. System.out.printf("Filename is = %s\n",f.getFileName()); 
  6. System.out.printf("LineNumber is = %d\n",f.getLineNumber()); 
  7. System.out.printf("ClassName is = %s\n",f.getClassName()); 
  8. System.out.printf("Methodname is = %s\n",f.getMethodName()); 
  9. System.out.printf("isNativeMethod = %s\n",f.isNativeMethod() ? "true" : "false");  
  10. }  
  11. /* 輸入如下: 
  12. Filename is = TestMain.java 
  13. LineNumber is = 3 
  14. ClassName is = TestMain 
  15. Methodname is = main 
  16. isNativeMethod = false */ 

C++語言本身并未提供這樣的方法,只是提供了__FUNCTION__、__LINE__、__FILE__這樣的3個宏來獲取當前函數的函數名、行號和文件名,但是無法得到調用棧信息,如果確實需要這樣的信息,只能通過操作系統的工具包來協助完成(僅針對Debug版本),目前Windows(vc)和Linux(gcc)都提供這樣的開發包。

2. 斷言:是主要用于開發、調試和系統集成測試期間進行Debug的一種方式和技巧,語法如下:

  1. assert condition OR assert condition : expression 

其中assert為關鍵字,當condition為false時,程序運行中斷,同時報出指定的錯誤信息,如果使用assert的后面一種形式,expression的結果將會同時輸出,這樣更有助于錯誤的判斷,見如下兩種代碼形式:

  1. public static void main(String[] args) { 
  2. int a = 5
  3. assert a > 10 : a; 
  4. System.out.println("Ok."); 
  5. /* 輸出結果: 
  6. Exception in thread "main" java.lang.AssertionError: 5 
  7. at TestMain.main(TestMain.java:4) 
  8. */ 
  9. public static void main(String[] args) { 
  10. int[] a = null
  11. assert a != null
  12. System.out.println("Ok."); 
  13. /* 輸出結果: 
  14. Exception in thread "main" java.lang.AssertionError 
  15. at TestMain.main(TestMain.java:4) 
  16. */ 

在eclipse中,缺省情況下斷言是被禁用的,如果需要開啟斷言,則需要在Run(Debug) As->Run(Debug) Configurations...->Arguments->VM arguments中添加"-enableassertions" 運行期參數。如果斷言被禁用,assert中的代碼不會被執行,因此在系統發布后也不會影響程序的運行時效率。使用者也可以通過該命令行參數-ea:MyClass -ea:com.mypackage.mylib 來指定需要啟用斷言的class和package,如果啟用的是package,那么該包內的所有class都將啟用斷言。在C++中,是依靠crt中的assert(cond)函數來實現的,如果cond為false,程序將會立即停止,但是在使用前首先需要保證assert.h文件被包含進當前文件,再有就是當前編譯的程序必須是Debug版本,對于Release版本,無論Win32和Linux,斷言的語句都將不會被執行。

原文鏈接:http://www.cnblogs.com/stephen-liu74/archive/2011/08/09/2131740.html

【系列文章】

  1. Java和C++在細節上的差異:泛型程序設計
  2. Java和C++在細節上的差異:程序設計結構
  3. Java和C++在細節上的差異:枚舉與反射
責任編輯:林師授 來源: Stephen_Liu的博客
相關推薦

2011-12-06 10:48:32

Java

2011-12-06 09:42:51

Java

2011-12-06 12:16:58

Java

2009-06-01 08:48:19

作用域變量作用域對象作用域

2023-10-19 13:24:00

Java工具

2020-01-15 11:14:21

Java算法排序

2020-12-14 10:23:23

Java內部類外部類

2024-07-01 12:48:00

C++內部類開發

2010-01-28 15:22:12

C++嵌套類

2009-08-26 18:00:07

C#內部類

2010-02-05 15:32:33

Java內部類

2012-11-08 09:49:30

C++Java程序員

2009-06-11 13:08:29

Java內部類Java編程思想

2020-09-21 07:00:42

Java內部類接口

2011-03-29 14:11:15

內部類

2011-07-20 16:30:42

C++

2011-07-21 15:44:33

Java內部類

2009-06-11 11:07:25

Java局部內部類Final類型

2010-08-26 10:41:45

C#內部類

2023-03-06 07:53:36

JavaN種內部類
點贊
收藏

51CTO技術棧公眾號

国产精品17p| 肥臀熟女一区二区三区| 三级精品视频| 在线精品视频小说1| 亚洲精品久久区二区三区蜜桃臀 | 97caopor国产在线视频| 国产精品自拍av| 2019中文字幕在线| 国产大屁股喷水视频在线观看| 97久久精品一区二区三区的观看方式 | 在线视频精品| 一区二区三区四区在线观看视频| 日韩不卡的av| 欧美电影免费看| 亚洲欧美另类图片小说| 六月婷婷久久| www.国产三级| 人人爽香蕉精品| 久久久久久久久久婷婷| 你懂得视频在线观看| 精品精品国产三级a∨在线| 在线观看www91| 国产va亚洲va在线va| www亚洲人| 95精品视频在线| 91原创国产| 欧美综合激情网| 日韩一级片播放| 密臀av在线| 最新久久zyz资源站| 久久综合给合久久狠狠色| 国产女人高潮的av毛片| 日本三级亚洲精品| 4k岛国日韩精品**专区| 久久精品www人人爽人人| 久久97视频| 日韩高清av在线| 丰满少妇xbxb毛片日本| 精品国产欧美| 欧美精品1区2区3区| 免费看黄色一级大片| 日本黄色免费在线| 午夜精品一区在线观看| 91看片淫黄大片91| 免费av网站在线看| 中文字幕免费观看一区| 欧美午夜精品理论片a级大开眼界| 国产综合在线播放| 国产一区免费电影| 91亚洲va在线va天堂va国| 亚洲一二区视频| 免播放器亚洲一区| 国产精品视频xxxx| 中文字幕在线观看免费| 日韩成人免费看| 国产精品91在线| 在线观看你懂的网站| 视频在线观看国产精品| 日本午夜精品理论片a级appf发布| 日韩av电影网| 亚洲在线成人| 国产91免费观看| 国产99久久久久久免费看| 久久最新视频| 国产精品免费久久久| 做爰视频毛片视频| 韩国一区二区视频| 99一区二区| 亚洲国产精品久久久久久6q| 高清久久久久久| 国产专区一区二区| 日本一区高清| 中文字幕电影一区| 91免费视频黄| 黄色羞羞视频在线观看| 欧美日韩国产中文精品字幕自在自线| 疯狂欧美牲乱大交777| 成人免费视频网站| 黄频网站在线观看| 26uuu欧美| 午夜欧美性电影| 成人免费网址| 欧美日韩国产色视频| 日本新janpanese乱熟| 四虎精品在线观看| 精品国产污污免费网站入口 | 在线视频 中文字幕| 激情欧美一区二区三区在线观看| 97se亚洲综合| 青青草在线视频免费观看| 国产日韩欧美一区二区三区乱码| 伊人久久青草| 国产欧洲在线| 欧美另类高清zo欧美| 国产女主播在线播放| 亚洲宅男一区| 操日韩av在线电影| a v视频在线观看| 久久精品国产**网站演员| 操人视频欧美| 777电影在线观看| 亚洲免费观看高清完整版在线观看 | 少妇高潮在线观看| 国产最新视频在线| 真实原创一区二区影院| 一区二区三区视频观看| 国产真人真事毛片| 美女视频黄 久久| 狠狠色狠狠色综合人人| 男女啪啪在线观看| 欧美午夜精品伦理| 永久av免费在线观看| 亚洲香蕉视频| 欧美激情2020午夜免费观看| 成人黄色激情视频| 成人高清视频在线观看| youjizz.com亚洲| gay欧美网站| 精品国精品自拍自在线| 中国美女黄色一级片| 99日韩精品| 91九色极品视频| 99精品老司机免费视频| 欧美日韩激情美女| 日韩精品――色哟哟| 99九九热只有国产精品| 日本91av在线播放| 无码国产精品高潮久久99| 亚洲日本丝袜连裤袜办公室| 欧美性猛交xxx乱久交| 噜噜噜天天躁狠狠躁夜夜精品| 久久夜色精品亚洲噜噜国产mv| 精品免费囯产一区二区三区| 成人福利视频网站| 国产片侵犯亲女视频播放| 深夜福利亚洲| 中文字幕在线国产精品| 无码人妻精品一区二| 91免费国产在线| 老太脱裤子让老头玩xxxxx| 亚洲日本va午夜在线电影| 久久精品视频在线观看| 亚洲天堂网在线观看视频| 国产日产欧美一区二区视频| 国产精品-区区久久久狼| 欧美天堂社区| 17婷婷久久www| 刘亦菲久久免费一区二区| 洋洋成人永久网站入口| 制服下的诱惑暮生| 午夜日韩av| 99c视频在线| 欧美黄色视屏| 亚洲国产精品大全| 青青草av在线播放| 91婷婷韩国欧美一区二区| av黄色在线网站| 五月国产精品| 国产ts一区二区| 成全电影播放在线观看国语| 欧美主播一区二区三区| 9.1片黄在线观看| 久久国产尿小便嘘嘘| 国产成年人在线观看| 日本精品一区二区三区在线观看视频| 欧美成人sm免费视频| 亚洲毛片欧洲毛片国产一品色| 夜色激情一区二区| 亚洲av片不卡无码久久| 三级在线观看一区二区| 亚洲日本无吗高清不卡| 精品网站999| 欧美激情一区二区三区高清视频| 免费看黄色一级视频| 欧美性猛交xxxxx水多| 91激情视频在线观看| 免费成人性网站| 999一区二区三区| 天美av一区二区三区久久| 国产精品激情自拍| 成人在线app| 亚洲激情在线视频| 日本视频www色| 亚洲男人的天堂一区二区| 秘密基地免费观看完整版中文 | 98精品国产自产在线观看| 欧美一区二区三区少妇| 欧美日韩国产成人在线免费| 免费在线观看国产精品| 2017欧美狠狠色| 国内外成人免费在线视频| 国内精品久久久久久久影视蜜臀 | 午夜精品av| 欧美精品一区在线| 免费观看性欧美大片无片| 国产91精品青草社区| 男人影院在线观看| 亚洲精品av在线| 97精品人妻一区二区三区| 亚洲成人一二三| 日本 欧美 国产| 99r精品视频| 日本高清免费在线视频| 中文日韩欧美| 亚洲国产一二三精品无码| 亚洲另类av| av成人午夜| 福利一区和二区| 91精品国产91久久久久久久久| 日本亚洲精品| 亚洲欧美日韩图片| 亚洲AV无码精品色毛片浪潮| 欧美性生活一区| 91国产丝袜播放在线| 有码一区二区三区| 青青草自拍偷拍| 久久亚洲精品国产精品紫薇| 一区二区三区人妻| 免费一级片91| 国产aaa一级片| 怡红院精品视频在线观看极品| 超碰成人在线免费观看| 精品国产中文字幕第一页| 国产日韩欧美二区| 一区二区三区在线免费看 | 久久97精品| 97免费资源站| 不卡一区视频| 国产精品一区久久久| 美女100%一区| 8050国产精品久久久久久| 日本动漫理论片在线观看网站| 色婷婷综合成人av| 成人综合影院| 亚洲欧美制服丝袜| 欧美黄色小说| 亚洲精品一区二区三区婷婷月| 日本毛片在线观看| 精品区一区二区| 国产成人精品一区二区无码呦| 欧美日韩国产乱码电影| 欧美性受xxx黑人xyx性爽| 在线亚洲+欧美+日本专区| 特黄视频免费看| 欧美色另类天堂2015| 一区二区三区视频免费看| 亚洲一区二区精品视频| 国产一级理论片| 亚洲r级在线视频| 国产无遮挡又黄又爽又色| 亚洲午夜羞羞片| 国产精品111| 午夜精品一区二区三区电影天堂| 激情五月婷婷在线| 亚洲大片在线观看| 免费日韩一级片| 欧美性69xxxx肥| jizz国产在线观看| 欧美系列日韩一区| 一二三四区在线| 91精品国产高清一区二区三区蜜臀| 国产精品久久久久久在线| 欧美一区二区在线不卡| 亚洲AV无码精品国产| 亚洲国产91精品在线观看| 头脑特工队2在线播放| 亚洲免费福利视频| 成人77777| 毛片精品免费在线观看| www欧美xxxx| 欧洲日韩成人av| 国产精品66| 99久久99久久| 欧洲亚洲一区二区三区| 日韩av图片| 一级欧洲+日本+国产| 日本手机在线视频| 久久九九国产| www.国产福利| 99视频一区二区三区| 亚洲第一综合网| 亚洲黄色免费电影| 激情五月婷婷网| 欧美一区二区三区四区五区| 国模私拍视频在线| 国产亚洲精品一区二555| 免费av网站在线观看| 97婷婷大伊香蕉精品视频| 精品肉辣文txt下载| 亚洲综合视频1区| 亚洲丝袜啪啪| 午夜探花在线观看| 老司机精品福利视频| 亚洲黄色片免费看| 91麻豆视频网站| 国产探花在线免费观看| 欧美日韩午夜视频在线观看| 一级特黄aaa| 日韩精品免费在线视频观看| 国产丝袜在线| 日韩女在线观看| 高清精品视频| 一区二区三区四区欧美日韩| 日韩午夜免费| 亚洲一区二区三区三州| 久久精品欧美日韩精品| 麻豆亚洲av熟女国产一区二| 欧美影院精品一区| 天天爽夜夜爽夜夜爽| 久久精品国产亚洲| 欧美日韩五区| 久久99精品久久久久久青青日本| 香蕉久久网站| 91激情视频在线| 91丨国产丨九色丨pron| 免费一级全黄少妇性色生活片| 在线观看国产日韩| 天天av综合网| 欧美激情喷水视频| 欧美成人精品一级| 亚洲人成网站在线观看播放| 久久久久久穴| www.88av| 亚洲一区二区黄色| 国产女人高潮毛片| 日韩在线www| 精品成人av| 秋霞毛片久久久久久久久| 日韩午夜av| 美女扒开腿免费视频| 伊人色综合久久天天| 一区二区www| 日韩在线免费视频观看| 成人免费福利| 蜜桃网站成人| 免费中文字幕日韩欧美| 在线观看国产网站| 偷偷要91色婷婷| 人妻一区二区三区四区| 欧美激情手机在线视频| 亚洲综合色婷婷在线观看| 伊人网在线免费| 国产一本一道久久香蕉| 中日韩一级黄色片| 欧美精品在线观看播放| 免费在线观看av网站| 国产精品视频网站| 日韩精品欧美| 女人高潮一级片| 亚洲欧洲综合另类| 国产成人久久精品77777综合| 裸体女人亚洲精品一区| 日韩精品中文字幕一区二区| 天天成人综合网| 精品一区二区三区免费| 老妇女50岁三级| 精品久久久久久久久久久久久久久 | 欧美久久精品午夜青青大伊人| 国产一区二区三区亚洲综合| 黄色网址在线免费看| 国产精品888| 日本三级免费看| 日韩久久精品电影| 欧美色999| 超碰在线免费观看97| 国产jizzjizz一区二区| 日韩三级视频在线| 亚洲视频在线免费观看| 青娱乐极品盛宴一区二区| 国产又粗又大又爽的视频| 国产91丝袜在线观看| 国产欧美一区二区三区在线看蜜臂| 亚洲欧洲国产伦综合| 久久久免费人体| 国产在线视频综合| 久久女同精品一区二区| 中文字幕乱伦视频| 欧美精品做受xxx性少妇| 亚洲亚洲免费| 欧美视频国产视频| 午夜精品久久久久久久99水蜜桃 | 女人抽搐喷水高潮国产精品| 日本老熟妇毛茸茸| 亚洲欧美日本韩国| 国产又爽又黄网站亚洲视频123| 国产精品久久网| 亚洲视频中文| 欧美三级视频网站| 精品久久久网站| 久久久成人av毛片免费观看| 好色先生视频污| 久久综合久色欧美综合狠狠| ,亚洲人成毛片在线播放| 97国产在线观看| 97精品国产一区二区三区| 美女黄色一级视频| 欧美老女人第四色| 波多野结衣亚洲一二三| 久久久久久久久网| 久久久久久久av麻豆果冻|