一個demo學會java
阿新 • • 發佈:2018-12-26
全棧工程師開發手冊 (作者:欒鵬)
這篇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必須在同步控制方法(塊)中呼叫
}
}
}
}