java基礎知識一覽(二)

1、java基礎知識java

  1.一個文件中只能有一個public的類,由於他的類名要求和文件名相同。
  2.classpath變量能夠設置其它目錄下的類。
    例如:類文件所在目錄是:F:\Javajdk,那麼沒有設置classpath變量時,在F:\下是訪問不到類文件的。能夠經過如下方式設置classpath變量,就能夠訪問不一樣目錄的文件(注意classpath變量中等號的左邊和右邊的目錄文件名稱中間是不能有空格,例如一個名爲「my Java」的文件夾是不能夠的):
    a.當前目錄爲F:\的目錄下,設置 set classpath=F:\Java jdk,而後執行 F:\java test,輸出成功。
    b.當前目錄爲F:\Javajdk下,給 set classpath=c:\myJava 隨便設置了一個變量,在執行 F:\Javajdk>java test時會失敗,若是給它的變量後面加一個分號(set classpath=c:\myJava; 或者給分號後面加一個「.」,他表示當前目錄),就能夠執行成功了。
  3.對象的比較:
    == 表示:比較的是兩個對象的在棧內存中的地址是否相等。
    equals 表示:不進的是兩個對象的值是否相等。
  4. super和this不能同時出如今一個構造函數中,當他們在構造函數中獨自出現時,必須在第一行出現。
  5. final關鍵字:
  6.implements關鍵字可使一個類實現接口,接口之間的繼承使用extends關鍵字,當一個類沒有實現接口中全部的方法時,該類被聲明爲抽象類。
  7.判斷對象是否相同:使用關鍵字instanceof.
  8.java中包package在磁盤中自動建立:javac -d . 文件名.java。其中d表示目錄,.表示當前目錄。缺省的訪問修飾符在不一樣的包之間是不能夠訪問的,在同一個包中不一樣的類之間的private修飾符是不能夠訪問的。在不一樣的包中,若是一個包中的類從另外一個包中的類繼承而來,那麼在子類能夠訪問方法的修飾符有protected,public。例如包是package obj.java;
那麼要訪問java目錄下的文件時,經過包名+類名才能夠,如訪問Test類,就要使用obj.java.Test才能夠。classpath應該指向包名所在的父目錄上。在JCreator中若是要運行帶包的文件時,從包名開始的目錄進行訪問。
  9.jar 命令。
     壓縮:jar cvf myJava.jar test test2 :表示將當前目錄下的test和test2文件夾的文件壓縮的myJava.jar中。當文件找不到時,注意查看jar文件的目錄結構。
     jar -twf d:\java\org\rt.jar > 1.txt :表示當jar文件中的內容很是多時,那麼就將它重定向到當前命令1.txt文件中;不過用rar來查看也是很是方便的。
  10.多線程:使用多線程執行代碼塊時,一旦代碼塊中有暫停語句時,那麼可能在這一瞬間,有多個線程進入,這會形成線程的不安全性。所以要使用一個synchronized(參數是一個對象)關鍵字,達到線程同步,可是該對象必須是同一個對象。顯然,速度將會下降。也能夠將該代碼塊設置成一個函數,而且在該函數前面加上synchronized關鍵字,也能夠達到線程之間的同步。
  11.Collection 、set 和 list 的區別:
      Collection: 各元素對象之間沒有指定的順序,容許有重複元素和多個null元素對象。
      Set: 各元素對象之間沒有指定的順序,不容許有重複元素,最多容許有一個null元素對象。
      List: 各元素對象之間沒有指定的順序,容許有重複元素和多個null元素對象。
  12.Properties類的應用:
     它繼承自Hashtable類,增長了將Hashtable對象中的關鍵字和值保存到文件和從文件中讀取關鍵字和值到Hashtable對象中的方法。用Properties.store方法存儲Properties對象中的內容,每一個屬性的關鍵字和值都必須是String類型。用到的主要方法有getProperty,setProperty,load和store,其中後面兩個方法FileInputStream和FileOutputStream。獲取和設置系統屬性System.getProperties和System.setProperties. 在Runtime類中能夠啓動進程。
  13.時間和日期 Date,Calendar,DateFormat和SimpleDateFormat類 :
     Calendar類中的getInstance靜態方法返回一個Calendar對象,經過get方法獲取時間,set設置時間,add增長多少時間。SimpleDateFormat主要設置日期的格式。
  14.Timer和TimeTask類:
     Timer類的schedule方法有一些重載方法。 其中一個參數就是TimerTask的實例,該類實現了Runnable接口,所以要設計一個TimerTask的子類,而且實現run方法。隔多長時間執行代碼和定時執行代碼。
  

 

  1.位運算:
            int num = 2<<3; //左移n位,相等於該數字乘以2的n次方。結果是16
  2.==和equal的區別:
    == : 專門用來比較兩個變量的值是否相等,也就是用於比較變量所對應的內存中所存儲的數值是否相同,要比較兩個基本類型的數據或兩個引用變量是否相等,只能用==操做符。
    equals: 方法是用於比較兩個獨立對象的內容是否相同,就比如去比較兩我的的長相是否相同,它比較的兩個對象是獨立的。
             s1 = new String("hehe");   s2 = new String("hehe");
         System.out.println(s1==s2);//false  System.out.println(s1.equals(s2));//true
   3.Integer與int的區別
     int是java提供的8種原始數據類型之一。Java爲每一個原始類型提供了封裝類,Integer是java爲int提供的封裝類。int的默認值爲0,而Integer的默認值爲null,即Integer能夠區分出未賦值和值爲0的區別,int則沒法表達出未賦值的狀況,例如,要想表達出沒有參加考試和考試成績爲0的區別,則只能使用Integer。在JSP開發中,Integer的默認爲null,因此用el表達式在文本框中顯示時,值爲空白字符串,而int默認的默認值爲0,因此用el表達式在文本框中顯示時,結果爲0,因此,int不適合做爲web層的表單數據的類型。
   4.重載和重寫:
     重寫:      
1、覆蓋的方法的標誌必需要和被覆蓋的方法的標誌徹底匹配,才能達到覆蓋的效果; 2、覆蓋的方法的返回值必須和被覆蓋的方法的返回一致; 3、覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類; 4、被覆蓋的方法不能爲private,不然在其子類中只是新定義了一個方法,並無對其進行覆蓋。 重載: 一、在使用重載時只能經過不一樣的參數樣式。例如,不一樣的參數類型,不一樣的參數個數,不一樣的參數順序(固然,同一方法內的幾個參數類型必須不同,例如能夠是fun(int,float),可是不能爲fun(int,int)); 2、不能經過訪問權限、返回類型、拋出的異常進行重載; 3、方法的異常類型和數目不會對重載形成影響; 4、對於繼承來講,若是某一方法在父類中是訪問權限是priavte,那麼就不能在子類對其進行重載,若是定義的話,也只是定義了一個新方法,而不會達到重載的效果。 5. 接口能夠繼承接口。抽象類能夠實現(implements)接口,抽象類可繼承具體類。抽象類中能夠有靜態的main方法。 6. 封裝,繼承,多態和抽象: 封裝: 封裝的目標就是要實現軟件部件的「高內聚、低耦合」,封裝就是把描述一個對象的屬性和行爲的代碼封裝在一個「模塊」中,也就是一個類中,屬性用變量定義,行爲用方法進行定義,方法能夠直接訪問同一個對象中的屬性。    繼承: 在定義和實現一個類的時候,能夠在一個已經存在的類的基礎之上來進行,把這個已經存在的類所定義的內容做爲本身的內容,並能夠加入若干新的內容,或修改原來的方法使之更適合特殊的須要,這就是繼承。    抽象: 抽象就是找出一些事物的類似和共性之處,而後將這些事物歸爲一個類,這個類只考慮這些事物的類似和共性之處,而且會忽略與當前主題和目標無關的那些方面,將注意力集中在與當前目標有關的方面。 7.內部類   內部類就是在一個類的內部定義的類,內部類中不能定義靜態成員,內部類能夠直接訪問外部類中的成員變量,內部類能夠定義在外部類的方法外面,也能夠定義在外部類的方法體中。靜態內部類不能訪問外部類的實例成員。 8. 匿名內部類:   匿名內部類繼承其餘類或者是實現接口指的是類自己定義的時候繼承其餘類和實現了接口。 interface Out{ public void save(); } class A { int i; } class Testadf{ public void get(){ new Thread() extends A implements Out{ //無論是繼承A仍是實現Out接口,都是編譯不經過的。 public void run(){ System.out.println("run"); } }; } } 9. try catch finally執行順序: 也許你的答案是在return以前,但往更細地說,個人答案是在return中間執行。 結論: finally中的代碼比return 和break語句後執行。

 

   1.靜態導入: import static java.lang.Math.*; //表示將Math類下的全部靜態方法所有導入,那麼在程序中就能夠直接省略Math.max(3,6)中的Math。
   2.可變參數: 定義 public static int Add(int x,int ... args) { }
        它是用三個點號來定義的,只能出如今列表的最後,點號位於類型和變量名之間,調用可變參數的方法時,編譯器爲可變參數隱含建立了一個數組。
   3.加強for循環:for(變量類型 參數名稱 : 集合,但它還要實現Iterable接口)
               for(int arg : args)  {  sum+=arg; }
   4.枚舉:枚舉能夠當作一個類,它的成員能夠當作類的實例對象。
      直接輸出枚舉對象時,已經調用了該枚舉的toString方法。
      ordinal方法: 返回的是數字,即在枚舉中的位置
      Direction.valueOf("EAST")  :調用枚舉的valueOf方法能夠將字符串轉換成枚舉
   5.如何獲取字節碼
     類名.class   , 實例對象.getClass  和 Class.forName("全名稱")三種,可是對於同一類型來講,他們在內存中的字節碼形同,好比String。
     一共有9個基本類型
   6.反射:就是講java類中的各類成分映射成相應的java類。
   7.ArrayList和HastSet的區別:
         ArrayList:添加的內容能夠重複,按必定的順序排列起來。
         HastSet: 當放入一個對象時,它先判斷有沒有這個對象。若是有,則不放;沒有則放。一旦存放到hashSet集合中,就不能修改參與存放字段的值。若是一改,而後刪除對象,可是它的hashCode值將會改變,那麼在這個區域就找不到剛纔的對象,就沒有刪除,就會形成內存泄露。
         hashCode: 它把集合分紅若干個區域,每個存進來的對象算出它的值,而後放到相應的區域。當查找某個值是,先算出hashCode值是屬於哪一個區域,而後就直接到這個區域中查找就能夠了。前期是對象存儲到hash算法的集合。例如:存放了3個對象他們的值分別是1,2,1,若是沒有實現hashCode方法,儘管第一個和第三個對象相等,可是它們hashCode卻不相等,所以,當存放第三個對象時根據他本身的hashCode存放到其它區域,結果就是在不一樣的區域中存放着兩個相等的對象。
   8.類加載器:能夠加載配置文件
     InputStream ips = ArrayListHashSet.class.getClassLoader().getResourceAsStream("Flection/config.properties");
     InputStream ips = ArrayListHashSet.class.getResourceAsStream("resource/config.properties");
     InputStream ips = ArrayListHashSet.class.getResourceAsStream("config.properties");
   9.javaBean的取值操做:
                Person per1 = new Person(20,"tom");
        String propertyName = "age";
                PropertyDescriptor pd = new PropertyDescriptor(propertyName,per1.getClass());
                Method methodAge = pd.getReadMethod();
        System.out.println(methodAge.invoke(per1));
      BeanUtils.setProperty(per,"birthday.time","12321"); //這個工具包支持級聯操做,其中birthday它的類型爲Date類項。
   10.java註解:
        /**
     * 註解有三個階段:java源文件 -- class文件 -- 內存中的字節碼
     * 默認狀況下是保存在class文件中
     * 一個註解就是一個類,用這個註解就是建立這個類的實例對象
     */
         @SuppressWarnings("deprecation")                     //發出警告,我知道這個方法過期了
         @Deprecated                                          //它放在方法上,表示該方法已通過時了
         @Retention(RetentionPolicy.RUNTIME)                  //表示該註解保存到運行時
         @Target({ ElementType.METHOD, ElementType.TYPE})     //@Target表示將註解加在什麼上,這裏的Type包括class,enum和interface等。
         @Override                                            //能夠檢查是否覆蓋父類方法
      註解的類型及其用法:
         public @interface ItCastAnnotation {
    //給註解定義屬性
        String color() default "blue";
        String value();
        int[] arrayAttr() default {1,2,3}; //數組類型
        //EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;
        cn.itcast.one.EnumTest.TrafficLamp lamp() default cn.itcast.one.EnumTest.TrafficLamp.RED;
        //類型爲註解,也就是註解的註解
        AnnotationAttr annotationAttr() default @AnnotationAttr("annotation");
    }
        @ItCastAnnotation(annotationAttr=@AnnotationAttr("annotationAttr"),color="red",value="abc",arrayAttr={ 3,4,5}) //用法

 

2、面向對象程序員

   1. 面向過程 
    在一個結構體中定義窗口的大小,位置,顏色,背景等屬性,對窗口操做的函數與窗口自己的定義沒有任何關係,如HideWindow,MoveWindow,MinimizeWindow,這些函數都須要接受一個表明要被操做的窗口參數 ,是一種謂語與賓語的關係 。
   2.  面向對象 
     定義窗口時,除了要指定在面向過程當中規定的那些屬性,如大小,位置,顏色,背景等外,還要指定該窗口可能具備的動做 ,如隱藏,移動,最小化等。這些函數被調用時,都是以某個窗口要隱藏,某個窗口要移動的語法格式來使用的 ,這是一種主語與謂語的關係。
   3. 類與對象
     類是對某一類事物的描述,是抽象的、概念上的定義;對象是實際存在的該類事物的每一個個體,於是也稱實例(instance)。 
   4. 類的封裝性
     若是外面的程序能夠隨意修改一個類的成員變量,會形成不可預料的程序錯誤,就象一我的的身高,不能被外部隨意修改,只能經過各類攝取養分的方法去修改這個屬性。 
在定義一個類的成員(包括變量和方法)時,使用private關鍵字說明這個成員的訪問權限,這個成員成了類的私有成員,只能被這個類的其餘成員方法調用,而不能被其餘的類中的方法所調用。 
      爲了實現良好的封裝性,咱們一般將類的成員變量聲明爲private,再經過public的方法來對這個變量進行訪問。對一個變量的操做,通常都有讀取和賦值操做,咱們分別定義兩個方法來實現這兩種操做,一個是getXxx()(Xxx表示要訪問的成員變量的名字),用來讀取這個成員變量操做,另一個是setXxx()用來對這個成員變量賦值。
一個類一般就是一個小的模塊,咱們應該讓模塊僅僅公開必需要讓外界知道的內容,而隱藏其它一切內容。咱們在進行程序的詳細設計時,應儘可能避免一個模塊直接修改或操做另外一個模塊的數據,模塊設計追求強內聚(許多功能儘可能在類的內部獨立完成,不讓外面干預),弱耦合(提供給外部儘可能少的方法調用)。用總統指揮一支軍隊的例子來講明這種效果。 
       隱藏類的實現細節;
       讓使用者只能經過事先定製好的方法來訪問數據,能夠方便地加入控制邏輯,限制對屬性的不合理操做;
       便於修改,加強代碼的可維護性;
    5.構造函數的定義和做用
      構造方法的特徵
          它具備與類相同的名稱;
          它不含返回值;
          它不能在方法中用return語句返回一個值
          注意:在構造方法裏不含返回值的概念是不一樣於「void」的,在定義構造方法時加了「void」,結果這個方法就再也不被自動調用了。
       構造方法的做用:當一個類的實例對象剛產生時,這個類的構造方法就會被自動調用,咱們能夠在這個方法中加入要完成初始化工做的代碼。這就好像咱們規定每一個「人」一出生就必須先洗澡,咱們就能夠在「人」的構造方法中加入完成「洗澡」的程序代碼,因而每一個「人」一出生就會自動完成「洗澡」,程序就沒必要再在每一個人剛出生時一個一個地告訴他們要「洗澡」了。   
     6. 構造方法的重載
          和通常的方法重載同樣,重載的構造方法具備不一樣個數或不一樣類型的參數,編譯器就能夠根據這一點判斷出用new 關鍵字產生對象時,該調用哪一個構造方法了。產生對象的格式是:new 類名(參數列表)  ;
          重載構造方法能夠完成不一樣初始化的操做, 如:p3=new Person(「Tom」,18);語句,會作這樣幾件事:建立指定類的新實例對象,在堆內存中爲實例對象分配內存空間,並調用指定類的構造方法,最後將實例對象的首地址賦值給引用變量p3。  
          在java每一個類裏都至少有一個構造方法,若是程序員沒有在一個類裏定義構造方法,系統會自動爲這個類產生一個默認的構造方法,這個默認構造方法沒有參數,在其方法體中也沒有任何代碼,即什麼也不作。 
因爲系統提供的默認構造方法每每不能知足編程者的需求,咱們能夠本身定義類的構造方法,來知足咱們的須要,一旦編程者爲該類定義了構造方法,系統就再也不提供默認的構造方法了。 
聲明構造方法,如無特殊須要,應使用public關鍵字,在咱們前面例子中,可使用private訪問修飾符嗎? 
     7. this的用法
          一個類中的成員方法能夠直接調用同類中的其餘成員,其實咱們在一個方法內部使用「this.其餘成員」的引用方式和直接使用「其餘成員」的效果是同樣的,那this還有多大的做用呢?在有些狀況下,咱們仍是非得用this關鍵字不可的 :
讓類的成員變量名和對其進行賦值的成員方法的形參變量同名是必要的,這樣的代碼誰看了都能明白這兩個變量是彼此相關的,老手看到函數的定義,就能揣摩出函數中的代碼,大大節省了別人和本身往後閱讀程序的時間。 
          假設咱們有一個容器類和一個部件類,在容器類的某個方法中要建立部件類的實例對象,而部件類的構造方法要接收一個表明其所在容器的參數。
構造方法是在產生對象時被java系統自動調用的,咱們不能在程序中象調用其餘方法同樣去調用構造方法。但咱們能夠在一個構造方法裏調用其餘重載的構造方法,不是用構造方法名,而是用this(參數列表)的形式,根據其中的參數列表,選擇相應的構造方法。 
     8. static 的靜態變量
          當咱們編寫一個類時,其實就是在描述其對象的屬性和行爲,而並無產生實質上的對象,只有經過new關鍵字纔會產生出對象,這時系統纔會分配內存空間給對象,其方法才能夠供外部調用。咱們有時候但願不管是否產生了對象或不管產生了多少對象的狀況下,某些特定的數據在內存空間裏只有一份,例如全部的中國人都有個國家名稱,每個中國人都共享這個國家名稱,沒必要在每個中國人的實例對象中都單獨分配一個用於表明國家名稱的變量。
          靜態方法裏只能直接調用同類中其它的靜態成員(包括變量和方法),而不能直接訪問類中的非靜態成員。這是由於,對於非靜態的方法和變量,須要先建立類的實例對象後纔可以使用,而靜態方法在使用前不用建立任何對象。
 靜態方法不能以任何方式引用this和super關鍵字(super關鍵字在下一章講解)。與上面的道理同樣,由於靜態方法在使用前不用建立任何實例對象,當靜態方法被調用時,this所引用的對象根本就沒有產生。
           main() 方法是靜態的,所以JVM在執行main方法時不建立main方法所在的類的實例對象,於是在main()方法中,咱們不能直接訪問該類中的非靜態成員,必須建立該類的一個實例對象後,才能經過這個對象去訪問類中的非靜態成員,這種狀況,咱們在之後的例子中會屢次碰到。
           一個類中可使用不包含在任何方法體中的靜態代碼塊(static block ),當類被載入時,靜態代碼塊被執行,且只被執行一次,靜態塊常常用來進行類屬性的初始化。 
類中的靜態代碼塊被自動執行,儘管咱們產生了類的多個實例對象,但其中的靜態代碼塊只被執行了一次。當一個程序中用到了其餘的類,類是在第一次被使用的時候才被裝載,而不是在程序啓動時就裝載程序中全部可能要用到的類。 
     9. 單態設計模式
         設計模式是在大量的實踐中總結和理論化以後優選的代碼結構、編程風格、以及解決問題的思考方式。設計模式就想是經典的棋譜,不一樣的棋局,咱們用不一樣的棋譜,省得咱們本身再去思考和摸索。失敗爲成功之母,可是要以大量的時間和精力爲代價,若是有成功經驗可借鑑,沒有人再願意去甘冒失敗的風險,咱們沒有理由不去了解和掌握設計模式,這也是Java開發者提升自身素質的一個很好選擇。使用設計模式也許會制約你去創新,不過真正有意義的創新只能出自少數天才,即便你就是那個天才,雖沒必要因循守舊,但也不可能徹底不去了解和借鑑前人的成功經驗。
         所謂類的單態設計模式,就是採起必定的方法保證在整個的軟件系統中,對某個類只能存在一個對象實例,而且該類只提供一個取得其對象實例的方法。若是咱們要讓類在一個虛擬機中只能產生一個對象,咱們首先必須將類的構造方法的訪問權限設置爲private,這樣,就不能用new 操做符在類的外部產生類的對象了,但在類內部仍能夠產生該類的對象。由於在類的外部開始還沒法獲得類的對象,只能調用該類的某個靜態方法以返回類內部建立的對象,靜態方法只能訪問類中的靜態成員變量,因此,指向類內部產生的該類對象的變量也必須定義成靜態的。 
      10. 理解main方法的語法
          因爲java虛擬機須要調用類的main()方法,因此該方法的訪問權限必須是public,又由於java虛擬機在執行main()方法時沒必要建立對象,因此該方法必須是static的,該方法接收一個String類型的數組參數,該數組中保存執行java命令時傳遞給所運行的類的參數。 
      11. 內部類
          嵌套類並不是只能在類裏定義,也能夠在幾個程序塊的範圍以內定義內部類。例如,在方法中,或甚至在for循環體內部,均可以定義嵌套類 。
          在方法中定義的內部類只能訪問方法中的final類型的局部變量,用final定義的局部變量至關因而一個常量,它的生命週期超出方法運行的生命週期。 
      12. 文檔註釋
          檔註釋以「/**」開始,以「*/」標誌結束,相應的信息和批註所對應的位置很重要! 類的說明應在類定義以前,方法的說明應在方法的定義以前。 
          批註參數來標記一些特殊的屬性及其相應的說明 。
           @author<做者姓名>
           @version<版本信息>
           @param<參數名稱><參數說明>
           @return<返回值說明>
      13. 類的繼承
          經過繼承能夠簡化類的定義 。
         Java只支持單繼承,不容許多重繼承。 
         能夠有多層繼承,即一個類能夠繼承某一個類的子類,如類B繼承了類A,類C又能夠繼承類B,那麼類C也間接繼承了類A。 
         子類繼承父類全部的成員變量和成員方法,但不繼承父類的構造方法。在子類的構造方法中可以使用語句super(參數列表) 調用父類的構造方法。 
          若是子類的構造方法中沒有顯式地調用父類構造方法,也沒有使用this關鍵字調用重載的其它構造方法,則在產生子類的實例對象時,系統默認調用父類無參數的構造方法。  
      子類的實例化過程:
         分配成員變量的存儲空間並進行默認的初始化,就是用new關鍵字產生對象後,對類中的成員變量按第三章的表3.1中的對應關係對對象中的成員變量進行初始化賦值。
綁定構造方法參數,就是new Person(實際參數列表)中所傳遞進的參數賦值給構造方法中的形式參數變量。
 若有this()調用,則調用相應的重載構造方法(被調用的重載構造方法又從步驟2開始執行這些流程),被調用的重載構造方法的執行流程結束後,回到當前構造方法,當前構造方法直接跳轉到步驟6執行顯式或隱式追溯調用父類的構造方法(一直到Object類爲止,Object是全部Java類的最頂層父類,在本章後面部分有詳細講解),父類的構造方法又從步驟2開始對父類執行這些流程,父類的構造方法的執行流程結束後,回到當前構造方法,當前構造方法繼續往下執行。
 進行實例變量的顯式初始化操做,也就是執行在定義成員變量時就對其進行賦值的語句,如:執行當前構造方法的方法體中的程序代碼 
       14. 覆蓋父類方法
           覆蓋方法必須和被覆蓋方法具備相同的方法名稱、參數列表和返回值類型。若是在子類中想調用父類中的那個被覆蓋的方法,咱們能夠用super.方法的格式 。
覆蓋方法時,不能使用比父類中被覆蓋的方法更嚴格的訪問權限 。
       15. 抽象類
           java中能夠定義一些不含方法體的方法,它的方法體的實現交給該類的子類根據本身的狀況去實現,這樣的方法就是抽象方法,包含抽象方法的類就叫抽象類。
           抽象類必須用abstract關鍵字來修飾;抽象方法也必須用abstract來修飾。
           抽象類不能被實例化,也就是不能用new關鍵字去產生對象。
           抽象方法只需聲明,而不需實現。
           含有抽象方法的類必須被聲明爲抽象類,抽象類的子類必須覆蓋全部的抽象方法後才能被實例化,不然這個子類仍是個抽象類。 
       16. 接口
           若是一個抽象類中的全部方法都是抽象的,咱們就能夠將這個類用另一種方式來定義,也就是接口定義。接口是抽象方法和常量值的定義的集合,從本質上講,接口是一種特殊的抽象類,這種抽象類中只包含常量和方法的定義,而沒有變量和方法的實現。 
接口中的成員都是public訪問類型的。接口裏的變量默認是用public static final標識的 。
咱們能夠定義一個新的接口用extends關鍵字去繼承一個已有的接口 
咱們也能夠定義一個類用implements關鍵字去實現一個接口中的全部方法,咱們還能夠去定義一個抽象類用implements關鍵字去實現一個接口中定義的部分方法。 
一個類能夠繼承一個父類的同時,實現一個或多個接口,extends關鍵字必須位於implemnets關鍵字以前 。
        17. 多態性
            1).應用程序沒必要爲每個派生類(子類)編寫功能調用,只須要對抽象基類進行處理便可。這一招叫「以不變應萬變」,能夠大大提升程序的可複用性。
2). 派生類的功能能夠被基類的引用變量引用,這叫向後兼容,能夠提升程序的可擴充性和可維護性。之前寫的程序能夠被後來程序調用不足爲奇,如今寫的程序(如callA方法)能調用之後寫的程序(之後編寫的一個類A的子類, 如類D)就了不得了。
         18. 異常
              異常定義了程序中遇到的非致命的錯誤, 而不是編譯時的語法錯誤,如程序要打開一個不存的文件、網絡鏈接中斷、操做數越界、裝載一個不存在的類等。 
try,catch語句 
throws關鍵字 
自定義異常與Throw關鍵字 
如何對多個異常做出處理 
咱們能夠在一個方法中使用throw,try…catch語句來實現程序的跳轉 
一個方法被覆蓋時,覆蓋它的方法必須扔出相同的異常或異常的子類。 
若是父類扔出多個異常,那麼重寫(覆蓋)方法必須扔出那些異常的一個子集,也就是說不能扔出新的異常。 
          19. 包
              package語句及應用
package語句做爲Java源文件的第一條語句。若是沒有package語句,則爲缺省無名包。 
import語句及應用 
jdk中經常使用的包
java.lang----包含一些Java語言的核心類,如String、Math、Integer、System和Thread,提供經常使用功能。
java.awt----包含了構成抽象窗口工具集(abstract window toolkits)的多個類,這些類被用來構建和管理應用程序的圖形用戶界面(GUI)。
java.applet----包含applet運行所需的一些類。
java.net----包含執行與網絡相關的操做的類。
java.io----包含能提供多種輸入/輸出功能的類。
java.util----包含一些實用工具類,如定義系統特性、使用與日期日曆相關的函數。

自己也有訪問控制,即在定義類的class關鍵字前加上訪問控制符,但類自己只有兩種訪問控制,即public 和默認,父類不能是private 和 protected,不然子類沒法繼承。public修飾的類能被全部的類訪問,默認修飾(即class關鍵字前沒有訪問控制符)的類,只能被同一包中的全部類訪問。 

 

3、IO通訊web

      
      1.RandomAccessFile類:
        它不只提供了衆多的文件訪問方法,而且還支持「隨機訪問」方式。它在隨機讀寫等長記錄格式的文件時有很大的優點。僅限於操做文件,不能訪問其餘的IO設備。有兩種構造方法:new RandomAccessFile(path,"rw")和new RandomAccessFile(path,"r"),"rw"和"r"分別表示讀寫方式和只讀方式。
      2.FileInputStream和FileOutputStream類操做文件:
        它們分別調用read方法和write方法向文件讀取和寫入數據,經過close關閉流。經過String的getBytes方法將字符串轉換成字節數組,經過實例化String對象將做爲參數傳入的字節數組能夠轉化成字符串。String result = new String(buf,0,len);
      3.FileReader和FileWriter類:
        操做比FileInputStream和FileOutputStream類簡單。    它的write方法裏面沒有調用flush方法,所以必需要關閉流才能使寫入的內容從緩衝區中刷新到硬盤上,然而FileOutputStream類裏面調用了flush方法,所以它就是沒有關閉流,也能將數據寫入到文件中。
      4.PipedInputStream和PipedOutputStream類:
        用於在應用程序中的建立管道通訊。
      5.ObjectOutputStream和ObjectInputStream類:
        它們所讀寫的對象必須實現了Serializable接口,對象中的transient和static類型的成員變量不會被讀取和寫入。
      6.InputStreamReader和OutputStreamWriter:
        是將字節流轉成字符流來讀寫的兩個類。可是,爲了不頻繁地在字符與字節間進行轉換,最好不要直接使用它們來讀寫數據,應儘可能使用BufferedWriter類包裝OutputStreamWriter類,用BufferedReader類包裝InputStreamReader。
        

 

  1.UDP通訊:
    DatagramSocket類有三個構造函數:
       close方法:   用於關閉DatagramSocket
        send方法:   用於發送數據,參數是DatagramPacket對象
       receive方法: 用於接收數據,參數是DatagramPacket對象
    DatagramPacket對象:用於發送和接收數據的集裝箱
        getInetAddress   //獲取IP地址
        getPort          //獲取端口號
        getData          //獲取數據
        getLength        //獲取實際數據的長度
     InetAddre類:用於表示計算機IP地址的一個類
        getByName        //返回相應的InetAddre實例對象
        getHostAddress   //將ip地址轉換成正常的字符串格式
    2.Tcp通訊:
      服務器端:
          ServerSocket類:用於監聽端口
                accept方法: 經過accept方法返回一個客戶端的Socket類,這個Socket類負責和客戶端通訊。
          Socket類: 是經過ServerSocket類返回的客戶端對象
                InputStream和OutputStream方法:    Tcp之間的通訊是經過InputStream和OutputStream兩個流對象進行信息的傳遞


                
      客戶端:Socket類
              PrintWriter類:能夠講數據在不一樣的應用程序窗口進行傳遞。
              InputStream和OutputStream方法:用來保存數據和發送數據的流對象
      3.對象經過TCP進行傳遞:
        首先,該對象須要實現Serializable接口;
        其次,要用到Tcp通訊的類,好比ServerSocket,Socket等;
        最後,須要ObjectOutputStream和ObjectInputStream類對getInputStrea和getOutputStrea方法進行包裝,而後經過他們的writeObject和readObject方法寫入和讀取對象。
        

 

     1、傳統線程:

       synchronized 關鍵字可使線程同步。若是它包含一個代碼塊,那麼跟在括號後面的參數必須保證惟一,不能使可變得。若是它做用在方法上,那麼默認它的鎖對象是this關鍵字。若是它做用在靜態方法上,它的鎖對象是當前類字節碼。
       synchronized 包含的代碼塊裏面不能同時在run方法裏面和synchronized裏面出現while(true){},不然就會進入死循環。

     線程同步案例:
 class SwitchThread {
    private boolean isSub=true; //表示到子線程執行,能夠稱爲控制器,控制那個線程執行。
    
    public synchronized void subThread() {
        while(!isSub){ //不是子線程,就等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }            
        for (int i = 0; i < 10; i++) {
            System.out.println("sub thread:\t" + i);
        }
        this.isSub=false; 
        this.notify(); //喚醒主線程
    }

    public synchronized void mainThread() {
        //這裏使用while而不使用if的緣由是,線程有多是假喚醒。使用while時,它還要檢查一次。
        while(isSub){ //是主線程
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (int i = 0; i < 50; i++) {
            System.out.println("=========main thread:\t" + i);
        }
        this.isSub=true; //交給子線程處理
        this.notify();//喚醒子線程
    }
}
    2、Java5中的線程併發庫
        Lock&Condition實現線程同步通訊,其中Lock中的lock方法相似synchronized關鍵字。Condition至關於wait和nofify兩個方法。
        Lock比傳統線程模型中的synchronized方式更加面向對象,與生活中的鎖相似,鎖自己也應該是一個對象。兩個線程執行的代碼片斷要實現同步互斥的效果,它們必須用同一個Lock對象。
    讀寫鎖:分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖與寫鎖互斥,這是由jvm本身控制的,你只要上好相應的鎖便可。若是你的代碼只讀數據,能夠不少人同時讀,但不能同時寫,那就上讀鎖;若是你的代碼修改數據,只能有一我的在寫,且不能同時讀取,那就上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖!
    在等待 Condition 時,容許發生「虛假喚醒」,這一般做爲對基礎平臺語義的讓步。對於大多數應用程序,這帶來的實際影響很小,由於 Condition 應該老是在一個循環中被等待,並測試正被等待的狀態聲明。某個實現能夠隨意移除可能的虛假喚醒,但建議應用程序程序員老是假定這些虛假喚醒可能發生,所以老是在一個循環中等待。
    一個鎖內部能夠有多個Condition,即有多路等待和通知,能夠參看jdk1.5提供的Lock與Condition實現的可阻塞隊列的應用案例,從中除了要體味算法,還要體味面向對象的封裝。在傳統的線程機制中一個監視器對象上只能有一路等待和通知,要想實現多路等待和通知,必須嵌套使用多個同步監視器對象。(若是隻用一個Condition,兩個放的都在等,一旦一個放的進去了,那麼它通知可能會致使另外一個放接着往下走。)

  class BoundedBuffer {
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }

4、其餘算法

  4.1 HashSet詳解:編程

java中HashSet詳解

程序人生 2010-08-25 14:45:19 閱讀1013 評論0   字號:大中小 訂閱
HashSet 的實現 

對於 HashSet 而言,它是基於 HashMap 實現的,HashSet 底層採用 HashMap 來保存全部元素,所以 HashSet 的實現比較簡單,查看 HashSet 的源代碼,能夠看到以下代碼: 

Java代碼 
public class HashSet<E>   
 extends AbstractSet<E>   
 implements Set<E>, Cloneable, java.io.Serializable   
{   
 // 使用 HashMap 的 key 保存 HashSet 中全部元素  
 private transient HashMap<E,Object> map;   
 // 定義一個虛擬的 Object 對象做爲 HashMap 的 value   
 private static final Object PRESENT = new Object();   
 ...   
 // 初始化 HashSet,底層會初始化一個 HashMap   
 public HashSet()   
 {   
     map = new HashMap<E,Object>();   
 }   
 // 以指定的 initialCapacity、loadFactor 建立 HashSet   
 // 其實就是以相應的參數建立 HashMap   
 public HashSet(int initialCapacity, float loadFactor)   
 {   
     map = new HashMap<E,Object>(initialCapacity, loadFactor);   
 }   
 public HashSet(int initialCapacity)   
 {   
     map = new HashMap<E,Object>(initialCapacity);   
 }   
 HashSet(int initialCapacity, float loadFactor, boolean dummy)   
 {   
     map = new LinkedHashMap<E,Object>(initialCapacity   
         , loadFactor);   
 }   
 // 調用 map 的 keySet 來返回全部的 key   
 public Iterator<E> iterator()   
 {   
     return map.keySet().iterator();   
 }   
 // 調用 HashMap 的 size() 方法返回 Entry 的數量,就獲得該 Set 裏元素的個數  
 public int size()   
 {   
     return map.size();   
 }   
 // 調用 HashMap 的 isEmpty() 判斷該 HashSet 是否爲空,  
 // 當 HashMap 爲空時,對應的 HashSet 也爲空  
 public boolean isEmpty()   
 {   
     return map.isEmpty();   
 }   
 // 調用 HashMap 的 containsKey 判斷是否包含指定 key   
 //HashSet 的全部元素就是經過 HashMap 的 key 來保存的  
 public boolean contains(Object o)   
 {   
     return map.containsKey(o);   
 }   
 // 將指定元素放入 HashSet 中,也就是將該元素做爲 key 放入 HashMap   
 public boolean add(E e)   
 {   
     return map.put(e, PRESENT) == null;   
 }   
 // 調用 HashMap 的 remove 方法刪除指定 Entry,也就刪除了 HashSet 中對應的元素  
 public boolean remove(Object o)   
 {   
     return map.remove(o)==PRESENT;   
 }   
 // 調用 Map 的 clear 方法清空全部 Entry,也就清空了 HashSet 中全部元素  
 public void clear()   
 {   
     map.clear();   
 }   
 ...   
}   



由上面源程序能夠看出,HashSet 的實現其實很是簡單,它只是封裝了一個 HashMap 對象來存儲全部的集合元素,全部放入 HashSet 中的集合元素實際上由 HashMap 的 key 來保存,而 HashMap 的 value 則存儲了一個 PRESENT,它是一個靜態的 Object 對象。 

HashSet 的絕大部分方法都是經過調用 HashMap 的方法來實現的,所以 HashSet 和 HashMap 兩個集合在實現本質上是相同的。 
掌握上面理論知識以後,接下來看一個示例程序,測試一下本身是否真正掌握了 HashMap 和 HashSet 集合的功能。 
Java代碼 
 class Name  
{  
    private String first;   
    private String last;   
      
    public Name(String first, String last)   
    {   
        this.first = first;   
        this.last = last;   
    }   
  
    public boolean equals(Object o)   
    {   
        if (this == o)   
        {   
            return true;   
        }   
          
    if (o.getClass() == Name.class)   
        {   
            Name n = (Name)o;   
            return n.first.equals(first)   
                && n.last.equals(last);   
        }   
        return false;   
    }   
}  
  
public class HashSetTest  
{  
    public static void main(String[] args)  
    {   
        Set<Name> s = new HashSet<Name>();  
        s.add(new Name("abc", "123"));  
        System.out.println(  
            s.contains(new Name("abc", "123")));  
    }  
}   



上面程序中向 HashSet 裏添加了一個 new Name("abc", "123") 對象以後,當即經過程序判斷該 HashSet 是否包含一個 new Name("abc", "123") 對象。粗看上去,很容易覺得該程序會輸出 true。 

實際運行上面程序將看到程序輸出 false,這是由於 HashSet 判斷兩個對象相等的標準除了要求經過 equals() 方法比較返回 true 以外,還要求兩個對象的 hashCode() 返回值相等。而上面程序沒有重寫 Name 類的 hashCode() 方法,兩個 Name 對象的 hashCode() 返回值並不相同,所以 HashSet 會把它們當成 2 個對象處理,所以程序返回 false。 

因而可知,當咱們試圖把某個類的對象當成 HashMap 的 key,或試圖將這個類的對象放入 HashSet 中保存時,重寫該類的 equals(Object obj) 方法和 hashCode() 方法很重要,並且這兩個方法的返回值必須保持一致:當該類的兩個的 hashCode() 返回值相同時,它們經過 equals() 方法比較也應該返回 true。一般來講,全部參與計算 hashCode() 返回值的關鍵屬性,都應該用於做爲 equals() 比較的標準。 
以下程序就正確重寫了 Name 類的 hashCode() 和 equals() 方法,程序以下: 
Java代碼 
class Name   
{   
    private String first;  
    private String last;  
    public Name(String first, String last)  
    {   
        this.first = first;   
        this.last = last;   
    }   
    // 根據 first 判斷兩個 Name 是否相等  
    public boolean equals(Object o)   
    {   
        if (this == o)   
        {   
            return true;   
        }   
        if (o.getClass() == Name.class)   
        {   
            Name n = (Name)o;   
            return n.first.equals(first);   
        }   
        return false;   
    }   
       
    // 根據 first 計算 Name 對象的 hashCode() 返回值  
    public int hashCode()   
    {   
        return first.hashCode();   
    }  
  
    public String toString()   
    {   
        return "Name[first=" + first + ", last=" + last + "]";   
    }   
 }   
   
 public class HashSetTest2   
 {   
    public static void main(String[] args)   
    {   
        HashSet<Name> set = new HashSet<Name>();   
        set.add(new Name("abc" , "123"));   
        set.add(new Name("abc" , "456"));   
        System.out.println(set);   
    }   
}  


上面程序中提供了一個 Name 類,該 Name 類重寫了 equals() 和 toString() 兩個方法,這兩個方法都是根據 Name 類的 first 實例變量來判斷的,當兩個 Name 對象的 first 實例變量相等時,這兩個 Name 對象的 hashCode() 返回值也相同,經過 equals() 比較也會返回 true。 

程序主方法先將第一個 Name 對象添加到 HashSet 中,該 Name 對象的 first 實例變量值爲"abc",接着程序再次試圖將一個 first 爲"abc"的 Name 對象添加到 HashSet 中,很明顯,此時無法將新的 Name 對象添加到該 HashSet 中,由於此處試圖添加的 Name 對象的 first 也是" abc",HashSet 會判斷此處新增的 Name 對象與原有的 Name 對象相同,所以沒法添加進入,程序在①號代碼處輸出 set 集合時將看到該集合裏只包含一個 Name 對象,就是第一個、last 爲"123"的 Name 對象。

4.2 代理:設計模式

    Collection proxy1 = (Collection) Proxy.newProxyInstance(
                 Collection.class.getClassLoader(), 
                 new Class[]{Collection.class}, 
                 new InvocationHandler() {        
                     ArrayList targer = new ArrayList();
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {
                        Object retVal = method.invoke(targer, args);
                        System.out.println(method.getName() +"  running");
                        return retVal;
                    }
     });

  4.3 泛型:數組

       
        ArrayList<String> arrList1 = new ArrayList<String>();
        
        ArrayList<Integer> arrList2 = new ArrayList<Integer>();
        arrList2.add(2);
        
        //在代碼運行時,在字節碼中取出了聲明泛型的類型,所以下面代碼返回true
        System.out.println(arrList1.getClass() == arrList2.getClass()); //true
        
        //由於運行時去除了類型,所以能夠經過反射繞過編譯器將字符串類型放到ArrayList<Integer>中
        arrList2.getClass().getMethod("add", Object.class).invoke(arrList2, "abc");
        System.out.println(arrList2.get(0));  //2
        System.out.println(arrList2.get(1));  //abc

        /**
     * 因爲泛型類型在編譯時去類型化,所以不能獲取它的泛型類型。
     * 可是能夠經過反射獲取方法的參數化類型,所以能夠定義一個方法來獲取泛型類型
     */

  4.4 集合:安全

  1. ArrayList和Vector的區別:
     共同點:這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,而且其中的數據是容許重複的。
     不一樣點:
           (1) Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不一樣步的。
           (2) 數據增加方式:即Vector增加原來的一倍,ArrayList增長原來的0.5倍。
      備註: 對於Vector&ArrayList、Hashtable&HashMap,要記住線程安全的問題,記住Vector與Hashtable是舊的,是java一誕生就提供了的,它們是線程安全的,ArrayList與HashMap是java2時才提供的,它們是線程不安全的。

   2. HashMap和Hashtable的區別:
      共同點: 都實現了Map接口。
      不一樣點:  (1).歷史緣由:Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現 
        (2).同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的 
        (3).值:只有HashMap可讓你將空值做爲一個表的條目的key或value 
   3. List 和 Map 區別:
      List是單列數據的集合,Map是雙列數據的集合,key和value兩部分組成。List中存儲的數據是有順序,而且容許重複;Map中存儲的數據是沒有順序的,其鍵是不能重複的,它的值是能夠有重複的
   4. List、Map、Set三個接口區別:
      (1) List與Set具備類似性,它們都是單列元素的集合,因此,它們有一個功共同的父接口,叫Collection。Set裏面不容許有重複的元素。Set取元素時,無法說取第幾個,只能以Iterator接口取得全部的元素,再逐一遍歷各個元素。
      (2) List表示有前後順序的集合。
      (3) Map與List和Set不一樣,它是雙列的集合,其中有put方法。
      (4) HashSet : 首先看hashcode方法是否相等,而後看equals方法是否相等。new 兩個Student插入到HashSet中,看HashSet的size,實現hashcode和equals方法後再看size。

       同一個對象能夠在Vector中加入屢次。往集合裏面加元素,至關於集合裏用一根繩子鏈接到了目標對象。往HashSet中卻加不了屢次的。
   5. Collection 和 Collections的區別:
    Collection是集合類的上級接口,繼承與他的接口主要有Set 和List. 
      Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各類集合的搜索、排序、線程安全化等操做。 

  4.5 枚舉深刻:服務器

  //  枚舉裏面的每一項能夠當作是這個枚舉的一個實例。定義了一個枚舉:

    public enum TrafficLamp{
        RED(5000){
            public TrafficLamp nextLamp() {
                try { Thread.sleep(time); }catch(Exception ex){ ex.printStackTrace();}
                return GREEN;
            }
            
        },
        GREEN(3000){
            @Override
            public TrafficLamp nextLamp() {
                try { Thread.sleep(time); }catch(Exception ex){ ex.printStackTrace();}
                return YELLOW;
            }
        },
        YELLOW(4000){
            @Override
            public TrafficLamp nextLamp() {
                try { Thread.sleep(time); }catch(Exception ex){ ex.printStackTrace();}
                return RED;
            }
        };
        
        public abstract TrafficLamp nextLamp();
        //time變量要在子類中訪問,所以將它設置成public
        public  int time=0;
        private  TrafficLamp(int time)
        {
            this.time = time;
        }
    }

   //   測試代碼:經過下面的代碼就能夠模擬交通燈的切換
      TrafficLamp currentLamp = TrafficLamp.RED;
        int i = 4;
        while(i>0)
        {
           currentLamp = currentLamp.nextLamp();
           System.out.println(currentLamp);
           i--;
        }
       
    //   枚舉還能夠實現單例模式
相關文章
相關標籤/搜索