1. 程式人生 > >一個demo學會java

一個demo學會java

全棧工程師開發手冊 (作者:欒鵬)

這篇demo較長,包含了java基本的內容,若不是出於校驗自己java基礎能力的朋友,建議按照上面的連結分章節學習。本demo包含了java的陣列、物件、物件屬性、介面,面向物件,過載,多型、封裝、字串、正則表示式、函式、引數、容器、演算法、執行緒、異常等方面的知識,可以全面檢驗你的java學習效果。

此demo包括檔案:測試檔案index.java和介面interface1.java、介面interface2.java、基類Student.java、派生類Monitor.java檔案

Student.java實現了一個java基類

//static int var=10;                                                            //java禁止使用全域性資料
//一個包可以包含多個類,類預設訪問修飾符為包訪問,每個檔案只能有一個public類,類只能是包訪問或public public class Student implements Comparable<Student>{ //implements繼承介面關鍵字,Comparable<Student>類比較介面 public static void main(String[] args) {} //每個類中都可以有一個main函式,用於除錯 public
Student(){ //不接受任何引數的叫預設構造器,沒定義構造器,編譯器會自動建立 this("student",12); //通過this僅能呼叫一個構造器,必須將構造器呼叫置於起始處 getname(); //構造器會呼叫成員函式和資料,所有在初始化構造器前會初始化成員資料
printf("基類無參構造器"); } public Student(String name,int age){ //有參構造器 this.age = age;this.name = name; printf("基類有參構造器"+name); } public Student(String name,Character...args){ //可變引數列表args是一個引數陣列,過載方法中應只有一個可變引數列表,編譯器 this.name = name; printf("基類變參構造器"); //args[0]表示變參中的第一個引數 } public void setname(String name){this.name=name;printf("基類設定名稱:"+name);} //this表示對當前物件的引用 public String getname(){printf("基類獲取名稱"+name);return name;} //使用public方法實現對private資料的控制,保證類內資料安全 void setage(int age){printf("基類設定名稱"+age);this.age=age;} private int getage(){return age;} //private屬於final方法 static long time=10; //所有型別資料均可在定義時初始化,資料均有預設值,所有類的靜態資料最先初始化 private int age=0; //private外部不可以訪問 String name = "student"; //不加訪問修飾符,預設為包訪問 public enum allsex{man,woman} //列舉型別,等價於類內組合class allsex{man,woman},列舉型別可以有建構函式,有幾個列舉例項就呼叫幾次建構函式 class Sextype{ //內部類,在內部類宣告為static時為巢狀類,巢狀類不屬於物件,而屬於類名 public void setsex(allsex sextype){ //列舉型別,可作為變數,相當於const printf("設定內部類性別"); switch (sextype) { //列舉型別用在switch中,用於限制引數的可選項 case man:sexstring="boy";break; case woman:sexstring="girl";break; default:break; } } public Student getStudent(){ sexstring+=name; //內部類,巢狀類可以任意訪問外部類資料,無論巢狀多少層 return Student.this; //返回外部類引用,當內部類是static時,內部類不存在對外部類的引用 } private String sexstring; } public static <T> void printf(T str) //泛型方法, { System.out.println(str.toString()); //System.out.println列印輸出 } //重寫equals虛擬函式,java中除了static和final都是虛擬函式,(private屬於final方法) public final boolean equals(Student another){ //final標記的函式不能被派生類重寫 printf("比較了兩個基類"); if(this.age==another.age && this.name==another.name) return true; return false; } //垃圾回收器準備收回物件佔用記憶體時執行,java虛擬機器並未面臨記憶體耗盡的情形不會浪費時間執行垃圾回收,(垃圾回收:停止-複製,標記-清掃) public void finalize(){ printf("基類物件"+name+"記憶體被收回"); } void dispose(){ printf("基類物件"+name+"清理函式"); } @Override public int compareTo(Student arg0){ //要實現排序,必須要實現的比較介面 return age<arg0.age?-1:(age==arg0.age?0:1); //返回-1表示小於,0不表示等於,1表示大於 } } //一個檔案可以包含多個類,但是檔名必須和public類名相同,否則只能使用預設的包訪問許可權 abstract class Teacher{ //abstract關鍵字表示為抽象類 abstract void setname(); //abstract抽象方法 public String getname(){return name;} //使用public方法實現對private資料的控制,保證類內資料安全 String name="teacher"; //不加修飾符預設為報訪問 }

Interface1.java定義了一個介面

public interface Interface1{                                                    //interface介面宣告,完全抽象類
    abstract void init1();                                                      //abstract抽象方法,介面自動是public的,介面中,不能定義函式體,只能宣告,abstract可以不寫
    class manclass implements Interface1{                                       //介面內部類自動是public和static的。屬於巢狀類,介面內部類實現介面函式,為了建立介面所有不同實現的公共程式碼
        @Override
        public void init1() {
            System.out.println("介面內部類,實現公共程式碼");
        }

    }
}

Interface2.java實現了一個派生介面

public interface Interface2<A> extends Interface1{                      //介面也支援繼承,介面可以多繼承,extends後可以有多個子介面,介面可以巢狀在類中<A>泛型介面
    abstract void init2(A name);                                        //abstract抽象方法,介面自動是public的
    void init1();                                                       //介面重寫了函式

    int DEFAULT_GAE =12;                                                //介面中的任何域都是自動的static和final的,static final使用大寫風格
    String DEFAULT_NAME ="name";  

}

Monitor.java檔案實現了一個繼承自Student,並繼承自Interface1和Interface2的派生類

import java.util.EnumSet;


final class Monitor<T> extends Student implements Interface1,Interface2<String>{    //<>泛型,extends繼承類,implements繼承介面,final終態類,不能再被繼承
    Monitor(){                                                                      //派生類無參構造器
        super("monitor");printf("派生類無參構造器");                                //關鍵字super顯示呼叫基類構造器,printf呼叫基類函式
    }                                                                               //構造前會呼叫父類無參建構函式,如果父類沒有建構函式,則會預設生成。如果有建構函式(無參),則會呼叫無參建構函式。如果只有有參建構函式,必須顯示呼叫
    Monitor(int age){printf("派生類有參構造器");}                                   //派生類有參構造器,
    static Student mysStudent = new Student("monitor",12);                          //靜態資料初始化只在呼叫時刻才會進行,在第一次建立類物件或者第一次訪問靜態資料時最先被初始化
    final static Student student1;                                                  //final用於,保持引用不變,物件可變
    static Student student2;
    static{                                                                         //靜態塊,僅執行一次,物件建立或靜態資料訪問時執行,僅定義物件的話不執行
        student1 = new Student();
        student2 = new Student();
        printf("派生類靜態塊執行");
    }
    //重寫函式的返回型別可以是基型別的派生型別,訪問許可權必須大於原訪問許可權,子類丟擲異常小於等於父類方法丟擲異常
    public String getname(){                                                        //重寫虛擬函式不需要關鍵字,因為在java中除了static和final都是虛擬函式(private屬於final方法)
        printf("派生類獲取名稱:"+name);                                                //
        //name = super.name+"的派生";                                                  //super代表基類
        return name;
    }
    public int getage(){return 11;}                                                 //private不能重寫,派生類重名,覆蓋了基類私有方法


    String name="monitor";                                                              //同名變數和靜態函式,不能動態繫結到基類引用上,和基類資料儲存在不同的區域
    String task ="幫助老師管理班級";  

    private T a;                                                                    //設定泛型,也可以使用原始基類Object
    public T getT(){return a;}                                                      //設定泛型函式,泛型會自動擦除傳遞過來的物件的類資訊
    public void setT(T a){this.a=a;printf("派生類設定泛型變數");}

    public enum Group{                                                              //列舉型別,函式列舉
        SHUXUE{void action(){printf("數學");}},
        YINGYU{void action(){printf("英語");}},
        YUNWEN{void action(){printf("語文");}};
        abstract void action();                                                     //每個列舉元素要實現的函式
    }

    EnumSet<Group> allgroup=EnumSet.of(Group.SHUXUE,Group.YINGYU);                  //EnumSet列舉集合,EnumMap列舉對映
    public void printfgroup(){
        for(Group g:allgroup)
            g.action();
    }


    @Override
    public void init2(String name) {                                                //泛型介面
        printf("派生類實現介面2初始化函式");
    }
    @Override
    public void init1() {
        printf("派生類實現介面1初始化函式,或介面2初始化函式");
    }

}

index.java檔案實現了所有知識點的測試。

import java.io.ByteArrayInputStream;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.Stack;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.prefs.Preferences;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.List;

import javax.naming.InitialContext;

public class index implements Runnable{                                         //Runnable多執行緒,任務介面,如果類不是抽象類,必須實現介面函式,可以建立Thread的派生類,Callable<>有返回值的執行緒介面

    static String stringtemp;                                                   //類內共享變數
    public static void main(String[] args)
    {

        printf("===========基類相關操作==============");
        Preferences prefs=Preferences.userNodeForPackage(index.class);          //Preferences只能存放基本型別和字串的鍵值對
        prefs.put("default_name", "student");                                   //Preferences用作屬性配置
        prefs.putInt("default_age", 12);
        Student.time+=Student.time<<2+0x21^26;                                  //靜態資料,可以銅鼓型別訪問,<<位左移動,低位補0,^按位異或,0X表示16進位制
        Student student1=new Student();                                         //所有的物件都必須通過new來建立,基本資料型別可以定義建立
        student1.name = student1.name+1;                                        //訪問類內資料,字串+過載
        student1.setage(-2*-6);                                                 //通過類內函式訪問類資料,一元減號用於轉變資料的符號
        Student.Sextype student1_sextype = student1.new Sextype();              //建立內部類,必須通過外部類變數new構造
        student1_sextype.setsex(Student.allsex.man);                            //呼叫列舉型別
        Student student2=student1;                                              //僅是複製引用,兩個變數名指向同一塊記憶體
        if(student1==student2)                                                  //==和!=只是比較物件的引用,不比較物件內容
            if(student1.equals(student2))                                       //物件的比較實用equals,比較物件的實際內容,但是定義類的equals預設行為還是比較引用,要在自定義類中重寫equals函式
                //if(1)                                                         //非布林值不能用在邏輯表示式中
                printf("建立了兩個相同的類引用");

        Field[] fileds = student1.getClass().getDeclaredFields();               //反射獲取物件類的屬性
        try{                                                                    //嘗試執行程式碼
            for(Field field:fileds){
                if(!field.isAccessible())
                    field.setAccessible(true);                                  //設定物件屬性可讀取
                    Object obj=field.get(student2);                             //從例項物件中獲取欄位屬性的值,(私有的沒法獲取,數值或物件統一為物件,沒有值返回的)
            }
        }
         catch (Exception e) {
            printf("錯誤內容:"+e.toString());                                   //catch函式在try出錯時呼叫,exception是所有異常類的基類,異常類可以捕獲派生類異常
            e.printStackTrace(System.out);                                      //堆軌跡,出錯原因和位置
            //throw e;                                                          //丟擲異常,停止執行
        }
        finally{                                                                //finally函式總要執行
            printf("finally函式總要執行");
        }





        printf("===========派生類相關操作==============");
        Monitor monitor1 =new Monitor(Interface2.DEFAULT_GAE);                      //基類建構函式(繫結後函式),派生類成員,派生類建構函式,介面中的域相當於列舉常量
        monitor1.name = "monitor1";                                                 //基類靜態-派生類靜態-基類私有-基類構造-派生類私有-派生類構造。函式在構造前已經存在
        printf("===========11111111111111111==============");
        sprintf(monitor1,null);                                                     //可變引數,null為引數為空
        sprintf(monitor1);                                                          //傳遞實現介面的類,向上轉型為介面,實現函式回撥
        printf("===========2222222222222222==============");
        Student student3 = new Monitor();                                       //基類引用,派生類物件
        student3.getname();                                                     //呼叫引用動態繫結的方法
        ((Monitor)student3).getage();                                           //向下轉型成功,getage為派生類的公共函式


        printf("===========介面相關操作==============");
        Interface1 interface1=new Monitor();                                    //向上轉型,interface1是基類,普通類,介面,無所謂,實現介面的類(包括內部類),都可以向上轉型轉化為介面
        interface1.init1();                                                     //呼叫動態繫結的函式
        interface1=getInterface1();                                             //通過匿名內部類實現介面函式的實現
        interface1.init1();


        printf("===========容器相關操作==============");
        //Collection介面,獨立元素序列(List介面,Set介面,Queue介面)
        //List介面,插入順序儲存陣列,(ArrayList陣列,LinkedList連結串列)
        //Set介面,不能重複元素,(HashSet雜湊函式,TreeSet紅黑樹,LinkedHashList連結串列下的雜湊)
        //Queue介面,先進先出佇列,(LinkedList連結串列,PriorityQueue優先順序佇列)

        //Map介面,鍵值對(字典,對映),HashMap(快速訪問),TreeMap(鍵值排序),LinkedHashMap(保持元素插入順序,通過雜湊提供快速訪問)
        //list整體賦值,Arrays.asList方法返回的ArrayList是繼承自AbstractList,不可變大小陣列,作為引數生成可變大小的ArrayList
        List<String> allname = new ArrayList<String>(Arrays.asList("小明","小紅","曉剛","小劉"));  //ArrayList實現向上轉型為list介面,動態連續陣列,<>內的物件型別可以不寫,不能是基本,<>內型別擦除,編譯器無法獲取,
        allname.set(2,"小剛");                                                    //list元素賦值
        if(!allname.contains("小王"))                                             //元素包含
            allname.add("小王");                                                  //新增元素
        allname.remove(0);                                                      //刪除元素
        stringtemp=allname.get(1);                                              //讀取元素
        Iterator<String> iterator = allname.iterator();                         //集合的迭代器,next為首個元素的迭代器,ListIterator迭代器更厲害
        iterator.next();                                                        //指向第一個元素
        iterator.remove();                                                      //刪除迭代器的對應元素,刪除可以繼續使用此元素的迭代器了
        while(iterator.hasNext())                                               //迭代器是否有一下個元素
            printf(iterator.next());                                            //獲取序列的下一個元素

        Stack<String> allname1 = new Stack<String>();                           //stack先進後出堆疊,各種佇列和棧基於LinkedList連結串列實現
        LinkedList<String> allname2 = new LinkedList<String>();                 //雙端佇列,佇列
        Set<String> allname3 = new HashSet<String>();                           //不重複集合
        Map<String,String> map = new HashMap<String,String>();                  //或者是SortedMap
        map.put("小明", "12");
        Object x_name = map.get("小明");
        Iterator iterator1 = map.entrySet().iterator();                         //Map物件有keySet方法,返回key的Set集合,values()返回Collection集合,entrySet函式返回集合,元素型別為Map.Entry(一個<key,vlaue>的泛型介面)
        Map.Entry entry = (Map.Entry)iterator1.next();
        Object key=entry.getKey();
        Iterator iterator2 = map.keySet().iterator();
        key=iterator2.next();
        x_name=map.get(key);
        for(Map.Entry<String, String> entry2:map.entrySet()){
            entry2.getKey();
            entry2.getValue();
        }
        List<Map.Entry<String, String>> info_student= new ArrayList<Map.Entry<String,String>>(map.entrySet());







        printf("===========字串相關操作==============");                                                             
        StringBuilder sb = new StringBuilder();                             //StringBuilder包括insert,replace,substring,reverse,append,tostring,delete方法
        sb.append(String.format("這裡%s字串相關操作", "shi"));             //string.format()格式化函式,內部建立formatter類設定字串格式
        String outStr=sb.toString().replace("shi", "是");                    //string是不可變數,取值變化是生成新的類,replace替換,repalceAll,replaceFirst
        outStr=outStr.substring(3)+outStr.length();                         //substring取子字串,length字串長度,+過載連線字串和整型
        if(outStr.indexOf("shi")<0)                                         //indexof插敘子字串所在位置,不存在返回-1,其他字串相關操作較多
            printf("字串\""+outStr+"\"不存在指定子字串");
        outStr = "luanpeng luanpeng";
        outStr=outStr.split(" ")[0];                                        //split分割字串,返回陣列,讀取第一個陣列賦值給outstr
        Pattern pattern = Pattern.compile("lu[a-n]");                       //建立正則法則,將正則字串編譯成正則表示式
        Matcher matcher = pattern.matcher(outStr);                          //建立匹配器
        while (matcher.find())                                              //依次查詢是否存在匹配項
            printf(matcher.group()+"起點"+matcher.start()+"終點"+matcher.end());//group匹配值,start起始位置,end結束位置
        matcher.reset("luan");                                              //將正則法則重新使用到新的字串上

        Integer nn= Integer.parseInt("123");                                //字串轉化為整型
        String str = String.valueOf(nn);                                    //整型轉化為字串
        char[] temparr ={'a','b'};                                          //字元陣列
        str=new String(temparr);                                            //字元陣列轉化為字串
        temparr = str.toCharArray();                                        //字串轉化為字元陣列
        byte[] temp1=str.getBytes();                                        //字串轉化為位元組陣列

        StringBuffer buf=new StringBuffer();                                //字串的StringBuffer表示,
        buf.append(str+"\r\n");                                             //StringBuffer可以追加
        buf.deleteCharAt(buf.length()-1);                                   //StringBuffer與StringBuilder有很多類似功能,這裡不一一列舉




        printf("===========陣列相關操作==============");
        Random random =new Random(17);                                          //隨機數
        int farrat[] =new int[10];                                              //陣列建立int var[] 和int[] var等效
        for(int x:farrat){                                                      //for語句的遍歷形式
            x=random.nextInt();                                                 //讀取偽隨機序列
        }
        Student[] all1 = new Student[7];  
        Student[] all2 = new Student[10]; 
        Arrays.fill(all1, student1);                                            //陣列填充,填充物件時,只是填充了引用
        Arrays.fill(all2, student3);
        System.arraycopy(all1, 0, all2, 2, all1.length);                        //ii第0個開始複製到jj第2個開始,長度ii.length
        Arrays.sort(all2);                                                      //呼叫重寫的比較函式執行陣列排序
        int location = Arrays.binarySearch(all2, student1);                     //在陣列中查詢,不存在返回-1
        if(!Arrays.equals(all1, all2))                                          //陣列相等   個數和每個元素均相等
            printf(Arrays.toString(all2));  

        Monitor<Student> monitor2 = new Monitor<Student>();                         //包含泛型的型別呼叫,也可以不使用泛型建立物件
        monitor2.setT(student1);


        //註解
        //資料流
        //序列化
        printf("===========執行緒相關操作==============");
        new index().run();                                                      //在主執行緒中呼叫執行緒類中的run函式,不是多執行緒,只是呼叫函式
        Thread thread=new Thread(new index());                                  //呼叫子函式,執行執行緒類中run函式,thread構造引數為runnable介面,執行緒類向上轉型為介面
        thread.setDaemon(true);                                                 //設定執行緒為後臺執行緒,否則為非後臺執行緒
        thread.start();                                                         //執行緒啟動,thread.join()等待執行緒執行完畢
        thread.interrupt();                                                     //執行緒中斷,會線上程執行至阻塞時中斷,彈出中斷異常
        ExecutorService exec= Executors.newCachedThreadPool();                  //建立執行緒池管理器
        exec.execute(new index());                                              //向執行緒管理器中新增一個執行緒實現介面,自動執行
        exec.submit(new index());                                               //呼叫有返回的執行緒
        exec.shutdown();                                                        //關閉執行緒管理器,執行緒池繼續執行

        synchronized (stringtemp) {                                             //物件鎖控制同步塊,需要鎖才能進入
            try {
                printf("進入同步塊,釋放物件鎖");                                  //物件釋放鎖,進入等待鎖定池,當接收到物件notify、notifyAll後進入物件鎖定池,準備重新獲取物件繼續執行
                stringtemp.wait();                                              //wait,會丟擲異常,synchronized 的目標與 wait() 方法的物件不相同,會有 IllegalMonitorStateException
                printf("同步控制塊恢復繼續執行");                                  //java裡面有專門捕獲異常的try catch。異常是向上依次丟擲的,如果在某一層被捕獲就不會退出。如果一直沒有被捕獲直到丟擲到系統層就是退出。
            } catch (InterruptedException e) {                                  //中斷異常類,會線上程執行至阻塞時中斷,彈出中斷異常
                e.printStackTrace();
            }
        }



        printf("結束");
        printf(Student.allsex.woman);


    }


    public static void sprintf(Student student,Object[] args)                   //基類引數允許傳遞派生類引用,//Object[] args用於可變引數列表,可以無參呼叫
    {
        student.setname("student1");                                            //呼叫引用動態繫結的方法-基類函式,修改的是基類屬性
        student.getname();                                                      //呼叫引用動態繫結的方法-派生類重寫的虛擬函式,獲取的是派生類屬性
    }
    public static void sprintf(Interface1 interface1)                           //介面引數允許傳遞介面類為引數,sprintf函式名相同實現過載
    {
        if(interface1 instanceof Monitor){                                      //判斷引用的型別是否是指定型別
            Student student=(Student)interface1;                                //先向下轉型為monitor,在向上轉型為student
            printf("介面型別:"+interface1.getClass().getName());                //獲取引用指向的物件型別
            student.getname();                                                  //呼叫動態繫結的方法
        }
        interface1.init1();                                                     //介面相當於純抽象類,呼叫動態繫結的方法   
    }



    public static Interface1 getInterface1() {                                  //不用建立實現介面的類,而直接實現介面的方法的定義
        return new Interface1(){                                                //匿名內部類,可以傳遞引數
            public void init1(){
                System.out.println("通過匿名內部類實現向上轉型為介面");
            }
        };
    }


    public static synchronized <T> void printf(T str)                           //泛型方法,synchronized同步函式,檢查鎖,獲取鎖,執行程式碼,釋放鎖
    {
        System.out.println(str.toString());
    }

    int num=0;
    @Override                                                                   //多執行緒,任務介面,只有呼叫執行緒接口才會執行
    public void run(){                                                          //執行緒介面過載函式
        Thread.currentThread().setPriority(++num);                              //設定執行緒優先順序,優先順序不會導致死鎖,優先順序低的執行頻率低
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");      //設定日期格式
        printf(df.format(new Date())+"執行了執行緒"+num);                          // new Date()為獲取當前系統時間
        Lock lock = new ReentrantLock();                                        //建立執行緒鎖
        lock.lock();                                                            //鎖定資源
        try {
            Thread.yield();                                                     //執行緒讓步,不釋放鎖,yield不能設定時間,只能控制同優先順序
            Thread.sleep(1000);                                                 //sleep可以使低優先順序的執行緒得到執行的機會,執行緒睡眠,不釋放鎖,保持監控,自動恢復,sleep不操作鎖,所以可以在非同步控制方法(塊)中呼叫
        } catch (Exception e) {
            printf(df.format(new Date())+"執行緒錯誤"+e.toString());
        }
        finally{
            lock.unlock();                                                      //釋放鎖
            printf(df.format(new Date())+"釋放鎖");                    
            synchronized (stringtemp) {                                         //物件鎖控制同步塊,需要鎖才能進入
                stringtemp.notifyAll();                                         //stringtemp呼叫執行緒恢復通知所有等待執行緒,wait、notify、notifyAll必須在同步控制方法(塊)中呼叫                                             
            }
        }

    }

}