Java快速入門!大專學歷自學Net看大仙如何快速轉(zhuǎn)職Java

學習java那是不可能的癌蓖,到為什么不學習一下呢。僅為總結婚肆。希望自己在不久的將來能書寫優(yōu)美的java程序租副。加油!奧利給

1.注釋

注釋的重要性不言而喻较性,我們不管寫什么代碼注釋必不可少用僧,那么java的注釋的書寫方式與注釋模板是怎么進行的呢?我們來看一下赞咙。

package frist;
/*
 * @Description HelloWorld類
 * @Author 王延領
 **/
class HelloWorld {
    /*
    這是我們Java程序的主入口责循,
    main方法也是程序的主線程。
    */
    public static void main(String[] arg)
    {
        //輸出
       System.out.println("wyl");
    }
}

1.1 注釋

以上可以看出java的注釋主要有三種
單行注釋:只能注釋當前行攀操,以//開始院仿,直到行結束

 //輸出

多行注釋:注釋一段文字,以/*開始, */結束歹垫!

 /*
    這是我們Java程序的主入口剥汤,
    main方法也是程序的主線程。
 */

文檔注釋:用于生產(chǎn)API文檔排惨,配合JavaDoc吭敢。

/*
 * @Description HelloWorld類
 * @Author 王延領
 **/

1.2 idea注釋模版配置

1.2.1 定義java文件頭部的注釋

File => setting => editor => File and Code Templates-class -Includes


/**
  * @創(chuàng)建人 王延領
  *@創(chuàng)建時間 ${DATE}
  *描述 Todo
**/

以上當你創(chuàng)建一個class的時候就會帶上以上信息了

1.2.2 給java類中的方法添加上注釋

第一步勾選Enable Live Templates
首先要在上一步中勾選中 Enable Live Templates


第二步新建一個Group
其次要打開LiveTemplates 然后新建一個Group
如圖:


在彈窗口中輸入你想要的group名稱,wyl


其中:Abbreviation 為快捷鍵,當輸入w的時候就會提示對應的方法注釋模板暮芭,j為類的注釋模板


Templete Text
注釋內(nèi)容鹿驼,$$ 為動態(tài)模板參數(shù)點擊Edit Vaariables 選擇對應動態(tài)值。

/*
 * @描述: TODO
 * @作者 王延領
 * @時間 2021/7/12
 * @版本 1.0
 */
public class wyl {
    /**
     *@描述
     *@參數(shù) [str]
     *@返回值 [java.lang.String]
     *@創(chuàng)建人 王延領
     *@創(chuàng)建時間 2021/7/12
     *@修改人和其它信息
     */
    public String CommentTemplate(String str)
    {
        return str;
    }
}

2.關鍵字

關鍵字 說明
private 一種訪問控制方式:私用模式
protected 一種訪問控制方式:保護模式
public 一種訪問控制方式:共用模式
abstract 表明類或者成員方法具有抽象屬性
class
extends 表明一個類型是另一個類型的子類型辕宏,這里常見的類型有類和接口
final 用來說明最終屬性蠢沿,表明一個類不能派生出子類,或者成員方法不能被覆蓋匾效,或者成員域的值不能被改變
implements 表明一個類實現(xiàn)了給定的接口
interface 接口
native 用來聲明一個方法是由與計算機相關的語言(如C/C++/FORTRAN語言)實現(xiàn)的
new 用來創(chuàng)建新實例對象
static 表明具有靜態(tài)屬性
strictfp 用來聲明FP_strict(單精度或雙精度浮點數(shù))表達式遵循IEEE 754算術規(guī)范
synchronized 表明一段代碼需要同步執(zhí)行
transient 聲明不用序列化的成員域
volatile 表明兩個或者多個變量必須同步地發(fā)生變化
break 提前跳出一個塊
continue 回到一個塊的開始處
return 從成員方法中返回數(shù)據(jù)
do 用在do-while循環(huán)結構中
while 用在循環(huán)結構中
if 條件語句的引導詞
else 用在條件語句中舷蟀,表明當條件不成立時的分支
for 一種循環(huán)結構的引導詞
instanceof 用來測試一個對象是否是指定類型的實例對象
switch 分支語句結構的引導詞
case 用在switch語句之中,表示其中的一個分支
default 默認面哼,例如野宜,用在switch語句中,表明一個默認的分支
try 嘗試一個可能拋出異常的程序塊
catch 用在異常處理中魔策,用來捕捉異常
throw 拋出一個異常
throws 聲明在當前定義的成員方法中所有需要拋出的異常
import 表明要訪問指定的類或包
package
boolean 基本數(shù)據(jù)類型之一匈子,布爾類型
byte 基本數(shù)據(jù)類型之一,字節(jié)類型
char 基本數(shù)據(jù)類型之一闯袒,字符類型
double 基本數(shù)據(jù)類型之一虎敦,雙精度浮點數(shù)類型
float 基本數(shù)據(jù)類型之一,單精度浮點數(shù)類型
int 基本數(shù)據(jù)類型之一政敢,整數(shù)類型
long 基本數(shù)據(jù)類型之一其徙,長整數(shù)類型
short 基本數(shù)據(jù)類型之一,短整數(shù)類型
super 表明當前對象的父類型的引用或者父類型的構造方法
this 指向當前實例對象的引用
void 聲明當前成員方法沒有返回值
goto 保留關鍵字,沒有具體含義
const 保留關鍵字喷户,沒有具體含義

3.數(shù)據(jù)類型

3.1.數(shù)據(jù)類型轉(zhuǎn)換

3.1.1自動類型轉(zhuǎn)換
自動類型轉(zhuǎn)換:容量小的數(shù)據(jù)類型可以自動轉(zhuǎn)換為容量大的數(shù)據(jù)類型唾那。

注:如果低級類型為char型,向高級類型(整型)轉(zhuǎn)換時褪尝,會轉(zhuǎn)換為對應ASCII碼值
3.1.2 強制類型轉(zhuǎn)換
強制類型轉(zhuǎn)換闹获,又被稱為造型,用于顯式的轉(zhuǎn)換一個數(shù)值的類型.
轉(zhuǎn)換方式為:(type)var 河哑,運算符“()”中的type表示將值var想要轉(zhuǎn)換成的目標數(shù)據(jù)類型避诽。 條件是轉(zhuǎn)換的數(shù)據(jù)類型必須是兼容的。

double x = 3.14;
int nx = (int)x; //值為3
char c = 'a';
int d = c+1;
System.out.println(d); //98
System.out.println((char)d); //b

3.1.3.包裝類過渡類型轉(zhuǎn)換

  • eg1:int i=Integer.parseInt(“123”)
    說明:此方法只能適用于字符串轉(zhuǎn)化成整型變量
  • eg2: float f=Float.valueOf(“123”).floatValue()
    說明:上例是將一個字符串轉(zhuǎn)化成一個Float對象璃谨,然后再調(diào)用這個對象的floatValue()方法返回其對應的float數(shù)值沙庐。
  • eg3: boolean b=Boolean.valueOf(“123”).booleanValue()
    說明:上例是將一個字符串轉(zhuǎn)化成一個Boolean對象,然后再調(diào)用這個對象的booleanValue()方法返回其對應的boolean數(shù)值。
  • eg4:double d=Double.valueOf(“123”).doublue()
    說明:上例是將一個字符串轉(zhuǎn)化成一個Double對象轨功,然后再調(diào)用這個對象的doublue()方法返回其對應的double數(shù)值旭斥。
  • eg5: long l=Long.valueOf(“123”).longValue()
    說明:上例是將一個字符串轉(zhuǎn)化成一個Long對象,然后再調(diào)用這個對象的longValue()方法返回其對應的long數(shù)值古涧。
  • eg6: char=Character.valueOf(“123”).charValue()
    說明:上例是將一個字符串轉(zhuǎn)化成一個Character對象

++++++++++++++++++++++++++++++++++++++++++++++++++++++

4.常量垂券、變量、運算符

常量

變量是什么:就是可以變化的量羡滑!
我們通過變量來操縱存儲空間中的數(shù)據(jù)菇爪,變量就是指代這個存儲空間!空間位置是確定的柒昏,但是里面放
置什么值不確定凳宙!Java是一種強類型語言,每個變量都必須聲明其類型职祷。

//數(shù)據(jù)類型 變量名 = 值氏涩;可以使用逗號隔開來聲明多個同類型變量。

注意事項:
每個變量都有類型有梆,類型可以是基本類型是尖,也可以是引用類型。
變量名必須是合法的標識符泥耀。
變量聲明是一條完整的語句饺汹,因此每一個聲明都必須以分號結束
變量作用域
類變量(靜態(tài)變量: static variable):獨立于方法之外的變量,用 static 修飾痰催。
實例變量(成員變量:member variable):獨立于方法之外的變量兜辞,不過沒有 static 修飾。
局部變量(lacal variable):類的方法中的變量夸溶。

變量

常量(Constant):初始化(initialize)后不能再改變值逸吵!不會變動的值。

final 常量名=值;
final double PI=3.14;

命名規(guī)范

  1. 所有變量蜘醋、方法胁塞、類名:見名知意
  2. 類成員變量:首字母小寫和駝峰原則 : monthSalary
  3. 局部變量:首字母小寫和駝峰原則
  4. 常量:大寫字母和下劃線:MAX_VALUE
  5. 類名:首字母大寫和駝峰原則: Man, GoodMan
  6. 方法名:首字母小寫和駝峰原則: run(), runRun()

運算符

Java 語言支持如下運算符:
算術運算符: +,-压语,,/编检,%胎食,++,--
賦值運算符 =
關系運算符: >允懂,<厕怜,>=,<=,==粥航,!= instanceof
邏輯運算符: &&琅捏,||,!
位運算符: &递雀,|柄延,^,~ 缀程, >>搜吧,<<,>>> (了解Q畲铡B四巍!)
條件運算符 撩满?:
擴展賦值運算符:+=蜒程,-=,
=伺帘,/=

5.java流轉(zhuǎn)控制

if...else昭躺、while、do...while曼追、for窍仰、switch...case 在這就不累述了。
跳轉(zhuǎn):
return
return從一個方法返回礼殊,并把控制權交給調(diào)用它的語句序驹吮;或者直接結束當前的程序;
break
break語句在for晶伦、while碟狞、do···while循環(huán)語句中,經(jīng)常用于強行退出當前循環(huán)婚陪;
continue
continue語句用于跳過此次循環(huán)族沃,執(zhí)行下次循環(huán);

6.方法

那么什么是方法呢泌参?
Java方法是語句的集合脆淹,它們在一起執(zhí)行一個功能。
方法是解決一類問題的步驟的有序組合
方法包含于類或?qū)ο笾?br> 方法在程序中被創(chuàng)建沽一,在其他地方被引用
設計方法的原則:方法的本意是功能塊盖溺,就是實現(xiàn)某個功能的語句塊的集合。我們設計方法的時候铣缠,最
好保持方法的原子性烘嘱,就是一個方法只完成1個功能昆禽,這樣利于我們后期的擴展。
方法的優(yōu)點
使程序變得更簡短而清晰蝇庭。
有利于程序維護醉鳖。
可以提高程序開發(fā)的效率。
提高了代碼的重用性哮内。

定義

修飾符 返回值類型 方法名(參數(shù)類型 參數(shù)名){
...
方法體
...c
return 返回值;
}

修飾符:修飾符盗棵,這是可選的,告訴編譯器如何調(diào)用該方法牍蜂。定義了該方法的訪問類型漾根。
返回值類型 :方法可能會返回值。returnValueType 是方法返回值的數(shù)據(jù)類型鲫竞。有些方法執(zhí)行所需
的操作辐怕,但沒有返回值。在這種情況下从绘,returnValueType 是關鍵字void寄疏。
方法名:是方法的實際名稱愉老。方法名和參數(shù)表共同構成方法簽名联喘。
參數(shù)類型:參數(shù)像是一個占位符。當方法被調(diào)用時逗载,傳遞值給參數(shù)批什。這個值被稱為實參或變量农曲。參
數(shù)列表是指方法的參數(shù)類型、順序和參數(shù)的個數(shù)驻债。參數(shù)是可選的乳规,方法可以不包含任何參數(shù)。
形式參數(shù):在方法被調(diào)用時用于接收外界輸入的數(shù)據(jù)合呐。
實參:調(diào)用方法時實際傳給方法的數(shù)據(jù)暮的。
方法體:方法體包含具體的語句,定義該方法的功能淌实。

方法的重載

就是說一個類的兩個方法擁有相同的名字冻辩,但是有不同的參數(shù)列表。

可變參數(shù)

在方法聲明中拆祈,在指定參數(shù)類型后加一個省略號(...) 恨闪。
一個方法中只能指定一個可變參數(shù),它必須是方法的最后一個參數(shù)放坏。任何普通的參數(shù)必須在它之前聲
明凛剥。

typeName... parameterName

遞歸

自己調(diào)用自己

7.數(shù)組

數(shù)組的定義:

數(shù)組是相同類型數(shù)據(jù)的有序集合.
數(shù)組描述的是相同類型的若干個數(shù)據(jù),按照一定的先后次序排列組合而成。
其中,每一個數(shù)據(jù)稱作一個數(shù)組元素,每個數(shù)組元素可以通過一個下標來訪問它們.

數(shù)組的四個基本特點:

  1. 其長度是確定的轻姿。數(shù)組一旦被創(chuàng)建犁珠,它的大小就是不可以改變的。
  2. 其元素必須是相同類型,不允許出現(xiàn)混合類型互亮。
  3. 數(shù)組中的元素可以是任何數(shù)據(jù)類型犁享,包括基本類型和引用類型。
  4. 數(shù)組變量屬引用類型豹休,數(shù)組也可以看成是對象炊昆,數(shù)組中的每個元素相當于該對象的成員變量

數(shù)組聲明

dataType[] arrayRefVar; // 首選的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首選方法

創(chuàng)建數(shù)組

arrayRefVar = new dataType[1 arraySize];

數(shù)組的元素是通過索引訪問的威根。數(shù)組索引從 0 開始凤巨,所以索引值從 0 到 arrayRefVar.length-1。

三種初始化

靜態(tài)初始化
除了用new關鍵字來產(chǎn)生數(shù)組以外,還可以直接在定義數(shù)組的同時就為數(shù)組元素分配空間并賦值洛搀。

int[] a = {1,2,3};
Man[] mans = {new Man(1,1),new Man(2,2)};

動態(tài)初始化
數(shù)組定義敢茁、為數(shù)組元素分配空間、賦值的操作留美、分開進行彰檬。

int[] a = new int[2];
a[0]=1;
a[1]=2;

數(shù)組的默認初始化
數(shù)組是引用類型,它的元素相當于類的實例變量谎砾,因此數(shù)組一經(jīng)分配空間逢倍,其中的每個元素也被按照實
例變量同樣的方式被隱式初始化。

public static void main(String[] args) {
int[] a=new int[2];
boolean[] b = new boolean[2];
String[] s = new String[2];
System.out.println(a[0]+":"+a[1]); //0,0
System.out.println(b[0]+":"+b[1]); //false,false
System.out.println(s[0]+":"+s[1]); //null, null
}

數(shù)組邊界

下標的合法區(qū)間:[0, length-1]景图,如果越界就會報錯较雕;

for 和For-Each 循環(huán)

for(type element: array){
System.out.println(element);
}

for (int i = 1; i < myList.length; i++) {
System.out.println(myList[i]);
}

多維數(shù)組

type[][] typeName = new type[typeLength1][1 typeLength2];

Arrays 類

數(shù)組的工具類java.util.Arrays
java.util.Arrays 類能方便地操作數(shù)組. 使用之前需要導包!
具有以下常用功能:
給數(shù)組賦值:通過 fill 方法挚币。
對數(shù)組排序:通過 sort 方法,按升序亮蒋。
比較數(shù)組:通過 equals 方法比較數(shù)組中元素值是否相等。
查找數(shù)組元素:通過 binarySearch 方法能對排序好的數(shù)組進行二分查找法操作忘晤。
轉(zhuǎn)換為list: 通過asList(a)進行轉(zhuǎn)換

8.面向?qū)ο?/h1>

萬物皆為對象M痱尽!设塔!對象是抽象概念的具體實例凄吏。

以類的方式組織代碼,以對象的組織(封裝)數(shù)據(jù)就是面向?qū)ο?/p>

繼承

繼承是java面向?qū)ο缶幊碳夹g的一塊基石闰蛔,因為它允許創(chuàng)建分等級層次的類痕钢。

class 父類 {
}
class 子類 extends 父類 {
}

public interface A {
    public void eat();
    public void sleep();
}

public interface B {
    public void show();
}

public class C implements A,B {
}

為什么要繼承,因為有重復序六。所以才繼承任连,進而我們就知道了。父類就是公共部分的定義或規(guī)則

Java 不支持多繼承(只能繼承一個類)例诀,但支持多重繼承随抠。

特點

  • 子類擁有父類非 private 的屬性裁着、方法。

  • 子類可以擁有自己的屬性和方法拱她,即子類可以對父類進行擴展二驰。

  • 子類可以用自己的方式實現(xiàn)父類的方法。

  • Java 的繼承是單繼承秉沼,但是可以多重繼承桶雀,單繼承就是一個子類只能繼承一個父類,多重繼承就是唬复,例如 B 類繼承 A 類矗积,C 類繼承 B 類,所以按照關系就是 B 類是 C 類的父類敞咧,A 類是 B 類的父類棘捣,這是 Java 繼承區(qū)別于 C++ 繼承的一個特性。

  • 提高了類之間的耦合性(繼承的缺點妄均,耦合度高就會造成代碼之間的聯(lián)系越緊密柱锹,代碼獨立性越差)

super 與 this 關鍵字

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}

class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 調(diào)用自己的方法
    super.eat();  // super 調(diào)用父類方法
  }
}

public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    a.eat();
    Dog d = new Dog();
    d.eatTest();
  }
}

animal : eat
dog : eat
animal : eat

final關鍵字
final 關鍵字聲明類可以把類定義為不能繼承的,即最終類丰包;

class SuperClass {
  private int n;
  SuperClass(){
    System.out.println("SuperClass()");
  }
  SuperClass(int n) {
    System.out.println("SuperClass(int n)");
    this.n = n;
  }
}
// SubClass 類繼承
class SubClass extends SuperClass{
  private int n;

  SubClass(){ // 自動調(diào)用父類的無參數(shù)構造器
    System.out.println("SubClass");
  }  

  public SubClass(int n){ 
    super(300);  // 調(diào)用父類中帶有參數(shù)的構造器
    System.out.println("SubClass(int n):"+n);
    this.n = n;
  }
}
// SubClass2 類繼承
class SubClass2 extends SuperClass{
  private int n;

  SubClass2(){
    super(300);  // 調(diào)用父類中帶有參數(shù)的構造器
    System.out.println("SubClass2");
  }  

  public SubClass2(int n){ // 自動調(diào)用父類的無參數(shù)構造器
    System.out.println("SubClass2(int n):"+n);
    this.n = n;
  }
}
public class TestSuperSub{
  public static void main (String args[]){
    System.out.println("------SubClass 類繼承------");
    SubClass sc1 = new SubClass();
    SubClass sc2 = new SubClass(100); 
    System.out.println("------SubClass2 類繼承------");
    SubClass2 sc3 = new SubClass2();
    SubClass2 sc4 = new SubClass2(200); 
  }
}

------SubClass 類繼承------
SuperClass()
SubClass
SuperClass(int n)
SubClass(int n):100
------SubClass2 類繼承------
SuperClass(int n)
SubClass2
SuperClass()
SubClass2(int n):200

構造函數(shù)

子類是不繼承父類的構造器(構造方法或者構造函數(shù))的禁熏,它只是調(diào)用(隱式或顯式)。如果父類的構造器帶有參數(shù)邑彪,則必須在子類的構造器中顯式地通過 super 關鍵字調(diào)用父類的構造器并配以適當?shù)膮?shù)列表瞧毙。

如果父類構造器沒有參數(shù),則在子類的構造器中不需要使用 super 關鍵字調(diào)用父類構造器寄症,系統(tǒng)會自動調(diào)用父類的無參構造器宙彪。

重寫(Override)與重載(Overload)

重寫(Override)

重寫是子類對父類的允許訪問的方法的實現(xiàn)過程進行重新編寫, 返回值和形參都不能改變。即外殼不變有巧,核心重寫

class Animal{
   public void move(){
      System.out.println("動物可以移動");
   }
}

class Dog extends Animal{
   public void move(){
      System.out.println("狗可以跑和走");
   }
}

public class TestDog{
   public static void main(String args[]){
      Animal a = new Animal(); // Animal 對象
      Animal b = new Dog(); // Dog 對象
      a.move();// 執(zhí)行 Animal 類的方法
      b.move();//執(zhí)行 Dog 類的方法
   }
}

動物可以移動
狗可以跑和走

方法的重寫規(guī)則

  • 參數(shù)列表與被重寫方法的參數(shù)列表必須完全相同释漆。

  • 返回類型與被重寫方法的返回類型可以不相同,但是必須是父類返回值的派生類(java5 及更早版本返回類型要一樣篮迎,java7 及更高版本可以不同)男图。

  • 訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:如果父類的一個方法被聲明為 public甜橱,那么在子類中重寫該方法就不能聲明為 protected逊笆。

  • 父類的成員方法只能被它的子類重寫。

  • 聲明為 final 的方法不能被重寫岂傲。

  • 聲明為 static 的方法不能被重寫难裆,但是能夠被再次聲明。

  • 子類和父類在同一個包中,那么子類可以重寫父類所有方法乃戈,除了聲明為 private 和 final 的方法褂痰。

  • 子類和父類不在同一個包中,那么子類只能夠重寫父類的聲明為 public 和 protected 的非 final 方法偏化。

  • 重寫的方法能夠拋出任何非強制異常脐恩,無論被重寫的方法是否拋出異常。但是侦讨,重寫的方法不能拋出新的強制性異常,或者比被重寫方法聲明的更廣泛的強制性異常苟翻,反之則可以韵卤。

  • 構造方法不能被重寫。

  • 如果不能繼承一個類崇猫,則不能重寫該類的方法沈条。

重載(Overload)

重載(overloading) 是在一個類里面,方法名字相同诅炉,而參數(shù)不同蜡歹。返回類型可以相同也可以不同。

每個重載的方法(或者構造函數(shù))都必須有一個獨一無二的參數(shù)類型列表涕烧。

最常用的地方就是構造器的重載月而。

public class Overloading {
    public int test(){
        System.out.println("test1");
        return 1;
    }

    public void test(int a){
        System.out.println("test2");
    }   

    //以下兩個參數(shù)類型順序不同
    public String test(int a,String s){
        System.out.println("test3");
        return "returntest3";
    }   

    public String test(String s,int a){
        System.out.println("test4");
        return "returntest4";
    }   

    public static void main(String[] args){
        Overloading o = new Overloading();
        System.out.println(o.test());
        o.test(1);
        System.out.println(o.test(1,"test3"));
        System.out.println(o.test("test4",1));
    }
}

重載規(guī)則:

  • 被重載的方法必須改變參數(shù)列表(參數(shù)個數(shù)或類型不一樣);

  • 被重載的方法可以改變返回類型议纯;

  • 被重載的方法可以改變訪問修飾符父款;

  • 被重載的方法可以聲明新的或更廣的檢查異常;

  • 方法能夠在同一個類中或者在一個子類中被重載瞻凤。

  • 無法以返回值類型作為重載函數(shù)的區(qū)分標準憨攒。

    區(qū)別點 重載方法 重寫方法
    參數(shù)列表 必須修改 一定不能修改
    返回類型 可以修改 一定不能修改
    異常 可以修改 可以減少或刪除,一定不能拋出新的或者更廣的異常
    訪問 可以修改 一定不能做更嚴格的限制(可以降低限制)

多態(tài)

多態(tài)是同一個行為具有多個不同表現(xiàn)形式或形態(tài)的能力阀参。

多態(tài)就是同一個接口肝集,使用不同的實例而執(zhí)行不同操作。

多態(tài)性是對象多種表現(xiàn)形式的體現(xiàn)蛛壳。

多態(tài)的優(yōu)點

  1. 消除類型之間的耦合關系
  2. 可替換性
  3. 可擴充性
  4. 接口性
  5. 靈活性
  6. 簡化性

多態(tài)存在的三個必要條件

繼承
重寫
父類引用指向子類對象:Parent p = new Child();

class Shape {
    void draw() {}
}

class Circle extends Shape {
    void draw() {
        System.out.println("Circle.draw()");
    }
}

class Square extends Shape {
    void draw() {
        System.out.println("Square.draw()");
    }
}

class Triangle extends Shape {
    void draw() {
        System.out.println("Triangle.draw()");
    }
}

虛函數(shù)

虛函數(shù)的存在是為了多態(tài)杏瞻。

Java 中其實沒有虛函數(shù)的概念,它的普通函數(shù)就相當于 C++ 的虛函數(shù)炕吸,動態(tài)綁定是Java的默認行為伐憾。如果 Java 中不希望某個函數(shù)具有虛函數(shù)特性,可以加上 final 關鍵字變成非虛函數(shù)赫模。

多態(tài)的實現(xiàn)方式

方式一:重寫:

方式二:接口

方式三:抽象類和抽象方法

抽象類

擁有抽象方法的類就是抽象類树肃,抽象類要使用abstract關鍵字聲明.

abstract class A{//定義一個抽象類
    public void fun(){//普通方法
        System.out.println("存在方法體的方法");
    }
    public abstract void print();//抽象方法,沒有方法體瀑罗,有abstract關鍵字做修飾

}

繼承抽象類

我們可以通過以下方式繼承 Employee 類的屬性

抽象類的使用原則
(1)抽象方法必須為public或者protected(因為如果為private胸嘴,則不能被子類繼承雏掠,子類便無法實現(xiàn)該方法),缺省情況下默認為public劣像;
(2)抽象類不能直接實例化乡话,需要依靠子類采用向上轉(zhuǎn)型的方式處理;
(3)抽象類必須有子類耳奕,使用extends繼承绑青,一個子類只能繼承一個抽象類;
(4)子類(如果不是抽象類)則必須覆寫抽象類之中的全部抽象方法(如果子類沒有實現(xiàn)父類的抽象方法屋群,則必須將子類也定義為為abstract類闸婴。);

package com.wz.abstractdemo;

abstract class A{//定義一個抽象類

    public void fun(){//普通方法
        System.out.println("存在方法體的方法");
    }

    public abstract void print();//抽象方法芍躏,沒有方法體邪乍,有abstract關鍵字做修飾

}
//單繼承
class B extends A{//B類是抽象類的子類,是一個普通類

    @Override
    public void print() {//強制要求覆寫
        System.out.println("Hello World !");
    }

}
public class TestDemo {

    public static void main(String[] args) {
        A a = new B();//向上轉(zhuǎn)型

        a.print();//被子類所覆寫的過的方法
    }
}

Hello World !

封裝

封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現(xiàn)細節(jié)部分包裝对竣、隱藏起來的方法庇楞。

封裝可以被認為是一個保護屏障,防止該類的代碼和數(shù)據(jù)被外部類定義的代碼隨機訪問否纬。

要訪問該類的代碼和數(shù)據(jù)吕晌,必須通過嚴格的接口控制。

封裝最主要的功能在于我們能修改自己的實現(xiàn)代碼烦味,而不用修改那些調(diào)用我們代碼的程序片段聂使。

適當?shù)姆庋b可以讓程式碼更容易理解與維護,也加強了程式碼的安全性谬俄。

封裝的優(yōu)點

  1. 良好的封裝能夠減少耦合柏靶。
  2. 類內(nèi)部的結構可以自由修改。
  3. 可以對成員變量進行更精確的控制溃论。
  4. 隱藏信息屎蜓,實現(xiàn)細節(jié)。

接口

在JAVA編程語言中是一個抽象類型钥勋,是抽象方法的集合炬转,接口通常以interface來聲明。一個類通過繼承接口的方式算灸,從而來繼承接口的抽象方法扼劈。

接口與類相似點

  1. 一個接口可以有多個方法。
  2. 接口文件保存在 .java 結尾的文件中菲驴,文件名使用接口名荐吵。
  3. 接口的字節(jié)碼文件保存在 .class 結尾的文件中。
  4. 接口相應的字節(jié)碼文件必須在與包名稱相匹配的目錄結構中。

接口與類的區(qū)別

  1. 接口不能用于實例化對象先煎。
  2. 接口沒有構造方法贼涩。
  3. 接口中所有的方法必須是抽象方法,Java 8 之后 接口中可以使用 default 關鍵字修飾的非抽象方法薯蝎。
  4. 接口不能包含成員變量遥倦,除了 static 和 final 變量。
  5. 接口不是被類繼承了占锯,而是要被類實現(xiàn)袒哥。
  6. 接口支持多繼承。

接口特性

  1. 接口中每一個方法也是隱式抽象的,接口中的方法會被隱式的指定為 public abstract(只能是 public abstract烟央,其他修飾符都會報錯)统诺。
  2. 接口中可以含有變量,但是接口中的變量會被隱式的指定為 public static final 變量(并且只能是 public疑俭,用 private 修飾會報編譯錯誤)。
  3. 接口中的方法是不能在接口中實現(xiàn)的婿失,只能由實現(xiàn)接口的類來實現(xiàn)接口中的方法钞艇。

抽象類和接口的區(qū)別

  1. 抽象類中的方法可以有方法體,就是能實現(xiàn)方法的具體功能豪硅,但是接口中的方法不行哩照。

  2. 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是 public static final 類型的懒浮。

  3. 接口中不能含有靜態(tài)代碼塊以及靜態(tài)方法(用 static 修飾的方法)飘弧,而抽象類是可以有靜態(tài)代碼塊和靜態(tài)方法

  4. 一個類只能繼承一個抽象類,而一個類卻可以實現(xiàn)多個接口砚著。

[可見度] interface 接口名稱 [extends 其他的接口名] {
        // 聲明變量
        // 抽象方法
}

/* 文件名 : NameOfInterface.java */
import java.lang.*;
//引入包

public interface NameOfInterface
{
   //任何類型 final, static 字段
   //抽象方法
}

接口有以下特性

  • 接口是隱式抽象的次伶,當聲明一個接口的時候,不必使用abstract關鍵字稽穆。
  • 接口中每一個方法也是隱式抽象的冠王,聲明時同樣不需要abstract關鍵字。
  • 接口中的方法都是公有的舌镶。

枚舉

枚舉是一個特殊的類柱彻,一般表示一組常量.每個枚舉都是通過 Class 在內(nèi)部實現(xiàn)的,且所有的枚舉值都是 public static final 的餐胀。

enum Color
{
    RED, GREEN, BLUE;
}

public class Test
{
    // 執(zhí)行輸出結果
    public static void main(String[] args)
    {
        Color c1 = Color.RED;
        System.out.println(c1);
    }
}

RED

values(), ordinal() 和 valueOf() 方法

enum 定義的枚舉類默認繼承了 java.lang.Enum 類哟楷,并實現(xiàn)了 java.lang.Seriablizable 和 java.lang.Comparable 兩個接口。

values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 類中:

  • values() 返回枚舉類中所有的值否灾。

  • ordinal()方法可以找到每個枚舉常量的索引卖擅,就像數(shù)組索引一樣。

  • valueOf()方法返回指定字符串值的枚舉常量。

    enum Color
    {
        RED, GREEN, BLUE;
    }
    
    public class Test
    {
        public static void main(String[] args)
        {
            // 調(diào)用 values()
            Color[] arr = Color.values();
            // 迭代枚舉
            for (Color col : arr)
            {
                // 查看索引
                System.out.println(col + " at index " + col.ordinal());
            }
            // 使用 valueOf() 返回枚舉常量,不存在的會報錯 IllegalArgumentException
            System.out.println(Color.valueOf("RED"));
            // System.out.println(Color.valueOf("WHITE"));
        }
    }
    
    
    RED at index 0
    GREEN at index 1
    BLUE at index 2
    RED
    
    

    枚舉成員

    枚舉跟普通類一樣可以用自己的變量、方法和構造函數(shù)屏歹,構造函數(shù)只能使用 private 訪問修飾符票腰,所以外部無法調(diào)用。

    enum Color
    {
        RED, GREEN, BLUE;
    
        // 構造函數(shù)
        private Color()
        {
            System.out.println("Constructor called for : " + this.toString());
        }
        public void colorInfo()
        {
            System.out.println("Universal Color");
        }
    }
    
    

包(package)

為了更好地組織類恰梢,Java 提供了包機制,用于區(qū)別類名的命名空間。

包的 3 個作用如下

  1. 區(qū)分相同名稱的類统刮。

  2. 能夠較好地管理大量的類。

  3. 控制訪問范圍账千。

定義

 ```java

package 包名;

Java 包的命名規(guī)則如下:

*   包名全部由小寫字母(多個單詞也全部小寫)侥蒙。
*   如果包名包含多個層次,每個層次用“.”分割匀奏。
*   包名一般由倒置的域名開頭鞭衩,比如 com.baidu,不要有 www娃善。
*   自定義包不能 java 開頭

**包導入**

\如果使用不同包中的其它類论衍,需要使用該類的全名(包名+類名)
example.Test test = new example.Test();


```c
\\import 包名+類名;
import example.Test;\\or
import example.*;

系統(tǒng)包

說明
java.lang Java 的核心類庫,包含運行 Java 程序必不可少的系統(tǒng)類聚磺,如基本數(shù)據(jù)類型坯台、基本數(shù)學函數(shù)、 字符串處理瘫寝、異常處理和線程類等蜒蕾,系統(tǒng)默認加載這個包
java.io Java 語言的標準輸入/輸出類庫,如基本輸入/輸出流焕阿、文件輸入/輸出咪啡、過濾輸入/輸出流等
java.util 包含如處理時間的 Date 類,處理動態(tài)數(shù)組的 Vector 類捣鲸,以及 Stack 和 HashTable 類
java.awt 構建圖形用戶界面(GUI)的類庫瑟匆,低級繪圖操作 Graphics 類、圖形界面組件和布局管理 (如 Checkbox 類栽惶、Container 類愁溜、LayoutManger 接口等),以及用戶界面交互控制和事 件響應(如 Event 類)
java.awt.image 處理和操縱來自網(wǎng)上的圖片的 Java 工具類庫
java.wat.peer 很少在程序中直接用到外厂,使得同一個 Java 程序在不同的軟硬件平臺上運行
java.net 實現(xiàn)網(wǎng)絡功能的類庫有 Socket 類冕象、ServerSocket 類
java.lang.reflect 提供用于反射對象的工具
java.util.zip 實現(xiàn)文件壓縮功能
java.awt.datatransfer 處理數(shù)據(jù)傳輸?shù)墓ぞ哳悾糍N板汁蝶、字符串發(fā)送器等
java.sql 實現(xiàn) JDBC 的類庫
java.rmi 提供遠程連接與載入的支持
java. security 提供安全性方面的有關支持

9.異常處理

異常處理的概念

是編程語言或計算機硬件里的一種機制渐扮,用于處理軟件或信息系統(tǒng)中出現(xiàn)的異常狀況(即超出程序正常執(zhí)行流程的某些特殊條件)论悴。

關鍵字

Java異常機制用到的幾個關鍵字:try、catch墓律、finally膀估、throw、throws耻讽。

try -- 用于監(jiān)聽察纯。將要被監(jiān)聽的代碼(可能拋出異常的代碼)放在try語句塊之內(nèi),當try語句塊內(nèi)發(fā)生異常
時针肥,異常就被拋出饼记。
catch -- 用于捕獲異常。catch用來捕獲try語句塊中發(fā)生的異常慰枕。
finally -- finally語句塊總是會被執(zhí)行具则。它主要用于回收在try塊里打開的物力資源(如數(shù)據(jù)庫連接、網(wǎng)絡
連接和磁盤文件)具帮。只有finally塊博肋,執(zhí)行完成之后,才會回來執(zhí)行try或者catch塊中的return或者throw語
句蜂厅,如果finally中使用了return或者throw等終止方法的語句束昵,則就不會跳回執(zhí)行,直接停止葛峻。
throw -- 用于拋出異常。
throws -- 用在方法簽名中巴比,用于聲明該方法可能拋出的異常术奖。

 try{
        可能會發(fā)生的異常
    }catch(異常類型 異常名(變量)){
        針對異常進行處理的代碼
    }catch(異常類型 異常名(變量)){
        針對異常進行處理的代碼
    }...
    [finally{
        釋放資源代碼;
    }]

Error與Exception區(qū)別

Error(錯誤)是系統(tǒng)中的錯誤轻绞,程序員是不能改變的和處理的采记,是在程序編譯時出現(xiàn)的錯誤,只能通過修改程序才能修正政勃。一般是指與虛擬機相關的問題唧龄,如系統(tǒng)崩潰,虛擬機錯誤奸远,內(nèi)存空間不足既棺,方法調(diào)用棧溢等。對于這類錯誤的導致的應用程序中斷懒叛,僅靠程序本身無法恢復和和預防丸冕,遇到這樣的錯誤,建議讓程序終止薛窥。
Exception(異常)表示程序可以處理的異常胖烛,可以捕獲且可能恢復眼姐。遇到這類異常,應該盡可能處理異常佩番,使程序恢復運行众旗,而不應該隨意終止異常。

throw與throws區(qū)別

throw:指的是在方法中人為拋出一個異常對象(這個異常對象可能是自己實例化或者拋出已存在的)趟畏;
throw ThrowableInstance;
throws:在方法的聲明上使用贡歧,表示此方法在調(diào)用時必須處理異常。
throw new NullPointerException("demo");

Java異常層次結構圖(網(wǎng)上獲裙案洹)

10.集合框架

所有集合類都位于 java.util 包下艘款。Java的集合類主要由兩個接口派生而出:Collection 和 Map,Collection 和 Map 是 Java 集合框架的根接口沃琅,這兩個接口又包含了一些子接口或?qū)崿F(xiàn)類哗咆。

集合框架被設計成要滿足以下幾個目標:

  • 該框架必須是高性能的∫婷迹基本集合(動態(tài)數(shù)組晌柬,鏈表,樹郭脂,哈希表)的實現(xiàn)也必須是高效的年碘。
  • 該框架允許不同類型的集合,以類似的方式工作展鸡,具有高度的互操作性屿衅。
  • 對一個集合的擴展和適應必須是簡單的。

集合框架都包含如下內(nèi)容:

  • 接口:是代表集合的抽象數(shù)據(jù)類型莹弊。例如 Collection涤久、List、Set忍弛、Map 等响迂。之所以定義多個接口,是為了以不同的方式操作集合對象

  • 實現(xiàn)(類):是集合接口的具體實現(xiàn)细疚。從本質(zhì)上講蔗彤,它們是可重復使用的數(shù)據(jù)結構,例如:ArrayList疯兼、LinkedList然遏、HashSet、HashMap镇防。

  • 算法:是實現(xiàn)集合接口的對象里的方法執(zhí)行的一些有用的計算啦鸣,例如:搜索和排序。這些算法被稱為多態(tài)来氧,那是因為相同的方法可以在相似的接口上有著不同的實現(xiàn)诫给。

Collection是一個基本的集合接口香拉,Collection中可以容納一組集合元素(Element)

Collection 接口

Collection 是最基本的集合接口,一個 Collection 代表一組 Object中狂,即 Collection 的元素, Java不提供直接繼承自Collection的類凫碌,只提供繼承于的子接口(如List和set)。

List

List接口是一個有序, 元素可重復的 Collection胃榕,使用此接口能夠精確的控制每個元素插入的位置盛险,能夠通過索引(元素在List中位置,類似于數(shù)組的下標)來訪問List中的元素勋又,第一個元素的索引為 0苦掘,而且允許有相同的元素。

  1. ArrayList

底層數(shù)據(jù)結構是數(shù)組楔壤,查改快鹤啡,增刪慢。

非線程安全蹲嚣,效率高

方法:

排序

import java.util.Collections;  // 引入 Collections 類
Collections.sort(sites); *// 字母排序*

  1. Vector

底層數(shù)據(jù)結構是數(shù)組递瑰,查改快,增刪慢隙畜。

線程安全抖部,效率低

  1. LinkedList

底層數(shù)據(jù)結構是鏈表,查改慢议惰,增刪快慎颗。

非線程安全,效率高

以下情況使用 LinkedList :

  • 你需要通過循環(huán)迭代來訪問列表中的某些元素言询。
  • 需要頻繁的在列表開頭哗总、中間、末尾等位置進行添加和刪除元素操作倍试。

LinkedList 繼承了 AbstractSequentialList 類。

LinkedList 實現(xiàn)了 Queue 接口蛋哭,可作為隊列使用县习。

LinkedList 實現(xiàn)了 List 接口,可進行列表的相關操作谆趾。

LinkedList 實現(xiàn)了 Deque 接口躁愿,可作為隊列使用。

LinkedList 實現(xiàn)了 Cloneable 接口沪蓬,可實現(xiàn)克隆彤钟。

LinkedList 實現(xiàn)了 java.io.Serializable 接口,即可支持序列化跷叉,能通過序列化去傳輸逸雹。

方法:

Set

Set 接口存儲一組唯一营搅,無序的對象。

  1. HashSet

底層數(shù)據(jù)結構是哈希表梆砸。(無序,唯一)

依賴兩個方法:hashCode()和equals() 保證元素唯一性

// 引入 HashSet 類      
import java.util.HashSet;

public class RunoobTest {
    public static void main(String[] args) {
    HashSet<String> sites = new HashSet<String>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Zhihu");
        sites.add("Runoob");  // 重復的元素不會被添加
        System.out.println(sites);
    }
}

以上代碼只會輸出一個Runoob转质。

  1. LinkedHashSet

底層數(shù)據(jù)結構是鏈表和哈希表。(FIFO插入有序,唯一)

1.由鏈表保證元素有序

2.由哈希表保證元素唯一

  1. TreeSet

底層數(shù)據(jù)結構是紅黑樹帖世。(唯一休蟹,有序)

如何保證元素排序的呢? 自然排序,比較器排序

Set和List的區(qū)別

  • Set 接口實例存儲的是無序的日矫,不重復的數(shù)據(jù)赂弓。List 接口實例存儲的是有序的,可以重復的元素哪轿。
  • Set檢索效率低下盈魁,刪除和插入效率高,插入和刪除不會引起元素位置改變 <實現(xiàn)類有HashSet,TreeSet>缔逛。
  • List和數(shù)組類似备埃,可以動態(tài)增長,根據(jù)實際存儲的數(shù)據(jù)的長度自動增長List的長度褐奴。查找元素效率高按脚,插入刪除效率低,因為會引起其他元素位置改變 <實現(xiàn)類有ArrayList,LinkedList,Vector> 敦冬。

Map與Collection是并列關系辅搬。Map提供鍵(key)到值(value)的映射。一個Map中不能包含相同的鍵脖旱,每個鍵只能映射一個值堪遂。

  1. HashMap

無序,非線程安全萌庆,效率高溶褪。HashMap允許null值(key和value都允許)。

  1. HashTable

無序践险,線程安全猿妈,效率低。除構造函數(shù)外巍虫,HashTable的所有 public 方法聲明中都有 synchronized關鍵字彭则,而HashMap的源碼中則沒有。HashTable不允許null值(key和value都允許)占遥。

  1. TreeMap

有序俯抖,非線程安全,效率高(O(logN))瓦胎,但比不上HashMap (O(1))芬萍。

11.流(Stream)尤揣、文件(File)和IO

Java.io 包中定義了多個流類型(類或抽象類)來實現(xiàn)輸入/輸出功能;

可以從不同的角度對其進行分
類:
1.按數(shù)據(jù)流的方向不同可以分為輸入流【InputStream(字節(jié)流)担忧,Reader(字符流)】和輸出流【OutPutStream(字節(jié)流)芹缔,Writer(字符流)】
2.按照處理數(shù)據(jù)單位不同可以分為字節(jié)流【一個字節(jié)(Byte)是8位(bit))】和字符流【一個字符是2個字節(jié)】
3.按照功能不同可以分為節(jié)點流和處理流

[圖片上傳失敗...(image-da6cbd-1628583810189)]

4.按照操作對象分

InputStream 和 OutputStream

import java.io.*;

public class fileStreamTest {
    public static void main(String[] args) {
        try {
            byte bWrite[] = { 11, 21, 3, 40, 5 };
            OutputStream os = new FileOutputStream("test.txt");
            for (int x = 0; x < bWrite.length; x++) {
                os.write(bWrite[x]); // writes the bytes
            }
            os.close();

            InputStream is = new FileInputStream("test.txt");
            int size = is.available();

            for (int i = 0; i < size; i++) {
                System.out.print((char) is.read() + "  ");
            }
            is.close();
        } catch (IOException e) {
            System.out.print("Exception");
        }
    }
}

上面的程序首先創(chuàng)建文件test.txt,并把給定的數(shù)字以二進制形式寫進該文件瓶盛,同時輸出到控制臺上最欠。

以上代碼由于是二進制寫入,可能存在亂碼惩猫,你可以使用以下代碼實例來解決亂碼問題:

//文件名 :fileStreamTest2.java
import java.io.*;

public class fileStreamTest2 {
    public static void main(String[] args) throws IOException {
        File f = new File("a.txt");
        FileOutputStream fop = new FileOutputStream(f);
        // 構建FileOutputStream對象,文件不存在會自動新建
        OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
        // 構建OutputStreamWriter對象,參數(shù)可以指定編碼,默認為操作系統(tǒng)默認編碼,windows上是gbk
        writer.append("中文輸入");
        // 寫入到緩沖區(qū)
        writer.append("\r\n");
        // 換行
        writer.append("English");
        // 刷新緩存沖,寫入到文件,如果下面已經(jīng)沒有寫入的內(nèi)容了,直接close也會寫入
        writer.close();
        // 關閉寫入流,同時會把緩沖區(qū)內(nèi)容寫入文件,所以上面的注釋掉
        fop.close();
        // 關閉輸出流,釋放系統(tǒng)資源
        FileInputStream fip = new FileInputStream(f);
        // 構建FileInputStream對象
        InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
        // 構建InputStreamReader對象,編碼與寫入相同
        StringBuffer sb = new StringBuffer();
        while (reader.ready()) {
            sb.append((char) reader.read());
            // 轉(zhuǎn)成char加到StringBuffer對象中
        }
        System.out.println(sb.toString());
        reader.close();
        // 關閉讀取流
        fip.close();
        // 關閉輸入流,釋放系統(tǒng)資源

    }
}

Reader 流與Writer流

Reader ,Write與InputStream 芝硬,OutputStream: 唯一的區(qū)別就在于讀的數(shù)據(jù)單位不同分別為(16bit),(8bit)

創(chuàng)建讀取目錄:

import java.io.File;

public class CreateDir {
    public static void main(String[] args) {
        String dirname = "/tmp/user/java/bin";
        File d = new File(dirname);
        // 現(xiàn)在創(chuàng)建目錄
        d.mkdirs();
    }
}

import java.io.File;

public class DirList {
    public static void main(String args[]) {
        String dirname = "/tmp";
        File f1 = new File(dirname);
        if (f1.isDirectory()) {
            System.out.println("目錄 " + dirname);
            String s[] = f1.list();
            for (int i = 0; i < s.length; i++) {
                File f = new File(dirname + "/" + s[i]);
                if (f.isDirectory()) {
                    System.out.println(s[i] + " 是一個目錄");
                } else {
                    System.out.println(s[i] + " 是一個文件");
                }
            }
        } else {
            System.out.println(dirname + " 不是一個目錄");
        }
    }
}

刪除

import java.io.File;

public class DeleteFileDemo {
    public static void main(String[] args) {
        // 這里修改為自己的測試目錄
        File folder = new File("/tmp/java/");
        deleteFolder(folder);
    }

    // 刪除文件及目錄
    public static void deleteFolder(File folder) {
        File[] files = folder.listFiles();
        if (files != null) {
            for (File f : files) {
                if (f.isDirectory()) {
                    deleteFolder(f);
                } else {
                    f.delete();
                }
            }
        }
        folder.delete();
    }
}

緩存流

是處理流的一種轧房,它是要“套接”在相應的節(jié)點流之上拌阴,對讀寫的數(shù)據(jù)提供了緩沖的功能,避免頻繁讀寫硬盤奶镶, 提高了讀寫的效率迟赃。同時增加了一些新的方法。

BufferedReader(Reader in)
BufferedReader(Reader in,int sz) //sz 為自定義緩沖區(qū)的大小
BufferedWriter(Writer out)
BufferedWriter(Writer out,int sz)
BufferedInputStream(InputStream in)
BufferedInputStream(InputStream in,int size)
BufferedOutputStream(InputStream in)
BufferedOutputStream(InputStream in,int size)

BufferedInputStream

package com.kuang.chapter;
import java.io.*;
public class TestBufferStream {
public static void main(String args[]) {
FileInputStream fis = null;
File f = new File("a.txt");
try {
fis = new FileInputStream( f);
// 在FileInputStream節(jié)點流的外面套接一層處理流BufferedInputStream
BufferedInputStream bis = new BufferedInputStream(fis);
int c = 0;
System.out.println((char) bis.read());
System.out.println((char) bis.read());
bis.mark(100);// 在第100個字符處做一個標記
for (int i = 0; i <= 10 && (c = bis.read()) != -1; i++) {
System.out.print((char) c);
}
System.out.println();
bis.reset();// 重新回到原來標記的地方
for (int i = 0; i <= 10 && (c = bis.read()) != -1; i++) {
System.out.print((char) c);
}
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}

BufferedReader

package com.kuang.chapter;
import java.io.*;
public class TestBufferStream{
public static void main(String args[]){
try{
BufferedWriter bw = new BufferedWriter(new FileWriter("a\\Student.txt"));
//在節(jié)點流FileWriter的外面再套一層處理流BufferedWriter
String s = null;
for(int i=0;i<100;i++){
s = String.valueOf(Math.random());//“Math.random()”將會生成一系列介于0~1之間的隨機數(shù)厂镇。
// static String valueOf(double d)這個valueOf()方法的作用就是把
一個double類型的數(shù)轉(zhuǎn)換成字符串
//valueOf()是一個靜態(tài)方法纤壁,所以可以使用“類型.靜態(tài)方法名”的形式來調(diào)用
bw.write(s);//把隨機數(shù)字符串寫入到指定文件中
bw.newLine();//調(diào)用newLine()方法使得每寫入一個隨機數(shù)就換行顯示
}
bw.flush();//調(diào)用flush()方法清空緩沖區(qū)
BufferedReader br = new BufferedReader(new FileReader("a:\\Student.txt"));
//在節(jié)點流FileReader的外面再套一層處理流BufferedReader
while((s = br.readLine())!=null){
//使用BufferedReader處理流里面提供String readLine()方法讀取文件中的數(shù)據(jù)時是一行一行讀取的
//循環(huán)結束的條件就是使用readLine()方法讀取數(shù)據(jù)返回的字符串為空值后則表
示已經(jīng)讀取到文件的末尾了。
System.out.println(s);
}
bw.close();
br.close();
}catch(Exception e){
e.printStackTrace();
}
}
}

轉(zhuǎn)換流

InputStreamReader 和 OutputStreamWriter 用于字節(jié)數(shù)據(jù)到字符數(shù)據(jù)之間的轉(zhuǎn)換
InputStreamReader 需要和 InputStream “套接” 捺信。
OutputStreamWriter 需要和 OutputStream “套接” 酌媒。
轉(zhuǎn)換流在構造時可以指定其編碼集合

import java.io.*;
public class TestTransform1 {
public static void main(String args[]) {
try {
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:/char.txt"));
    osw.write("熊方園真煩人");// 把字符串寫入到指定的文件中去
    System.out.println(osw.getEncoding());// 使用getEncoding()方法取得當前系統(tǒng)的默認字符編碼
    osw.close();
    osw = new OutputStreamWriter(new FileOutputStream("D:\\java\\char.txt", true), "utf-8");// 如果在調(diào)用FileOutputStream的構造方法時沒有加入true,那么新加入的字符    串就會替換掉原來寫入的字符串迄靠,在調(diào)用構造方法時指定了字符的編碼
    osw.write("不想搭理她");// 再次向指定的文件寫入字符串秒咨,新寫入的字符串加入到原來字符串的后面
    System.out.println(osw.getEncoding());
    osw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

數(shù)據(jù)流

數(shù)據(jù)流 DataInputStream DataOutputStream 【分別繼承自InputStream 和 OutputStream】等-提供將基礎數(shù)據(jù)類型寫入到文件中,或者讀取出來.提供了可以存取與機器無關的Java原始類型數(shù)據(jù)(int掌挚,double等)的方法雨席。

public static void main(String args[]){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//在調(diào)用構造方法時,首先會在內(nèi)存里面創(chuàng)建一個ByteArray字節(jié)數(shù)組
DataOutputStream dos = new DataOutputStream(baos);
//在輸出流的外面套上一層數(shù)據(jù)流吠式,用來處理int舅世,double類型的數(shù)
try{
    dos.writeDouble(Math.random());//把產(chǎn)生的隨機數(shù)直接寫入到字節(jié)數(shù)組
    ByteArray中
    dos.writeBoolean(true);//布爾類型的數(shù)據(jù)在內(nèi)存中就只占一個字節(jié)
    ByteArrayInputStream bais = new
    ByteArrayInputStream(baos.toByteArray());
        System.out.println(bais.available());
    DataInputStream dis = new DataInputStream(bais);
    System.out.println(dis.readDouble());//先寫進去的就先讀出來,調(diào)用readDouble()方法讀取出寫入的隨機數(shù)
    System.out.println(dis.readBoolean());//后寫進去的就后讀出來奇徒,這里面的讀取順序不能更改位置,否則會打印出不正確的結果
    dos.close();
    bais.close();
}catch(Exception e){
e.printStackTrace();
}
}

打印流

打印流是輸出信息最方便的類缨硝,注意包含字節(jié)打印流PrintStream和字符打印流:PrintWriter摩钙。打印流提供了非常方便的打印功能,
可以打印任何類型的數(shù)據(jù)信息查辩,例如:小數(shù)胖笛,整數(shù)网持,字符串汪诉。

對象流

對象的輸入輸出流的作用: 用于寫入對象 的信息和讀取對象的信息隆嗅。 使得對象持久化。
ObjectInputStream : 對象輸入流
ObjectOutPutStream :對象輸出流

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

//創(chuàng)建要寫入磁盤的類毫别,這個類需要實現(xiàn)接口 Serializable(可系列化的)
class Student implements Serializable{
    // 在這里保證了serialVersionUID 的唯一性身弊,防止屬性變量的臨時改變辟汰,從而造成寫入id與讀取id不同
    private static final long serialVersionUID = 1L;
    int id ; //額外需要添加一個屬性
    String name ;
    transient String sex; //transient修飾屬性,表示暫時的阱佛,則這個屬性不會被寫入磁盤
    transient int age;
    public Student(String name,String sex,int age){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}

public class objectIO {

    /**
     * @param args
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // TODO Auto-generated method stub

        createObj();
        readObj();
    }
    //(一)先寫入對象
    public static void createObj() throws IOException {
        //1.創(chuàng)建目標路徑
        File file = new File("C:\\Users\\bg\\Desktop\\objTest.txt");
        //2.創(chuàng)建流通道
        FileOutputStream fos = new FileOutputStream(file);
        //3.創(chuàng)建對象輸出流
        ObjectOutputStream objOP = new ObjectOutputStream(fos);
        //4.創(chuàng)建類對象帖汞,并初始化
        Student stu = new Student("瑪麗蘇", "男", 18);
        //5.向目標路徑文件寫入對象
        objOP.writeObject(stu);
        //6.關閉資源
        objOP.close();
    }
    //再讀取對象
    public static void readObj() throws IOException, ClassNotFoundException {
        File file = new File("C:\\Users\\bg\\Desktop\\objTest.txt");
        FileInputStream fis = new FileInputStream(file);
        ObjectInputStream objIP = new ObjectInputStream(fis);
        //讀取對象數(shù)據(jù),需要將對象流強制轉(zhuǎn)換為 要寫入對象的類型
        Student stu = (Student)objIP.readObject();
        System.out.println("\n name:"+stu.name+"\n sex:"+stu.sex+"\n age:"+stu.age);
        objIP.close();
    }
}

流的關閉順序

  1. 一般情況下是:先打開的后關閉凑术,后打開的先關閉
  2. 另一種情況:看依賴關系翩蘸,如果流a依賴流b,應該先關閉流a淮逊,再關閉流b催首。例如,處理流a依賴節(jié)點流b泄鹏,應該先關閉處理流a郎任,再關閉節(jié)點流b
  3. 可以只關閉處理流,不用關閉節(jié)點流命满。處理流關閉的時候涝滴,會調(diào)用其處理的節(jié)點流的關閉方法。

12.多線程

進程與線程

線程的創(chuàng)建

繼承Thread類胶台,實現(xiàn)Runnable接口歼疮,實現(xiàn)Callable接口

1.繼承Thread類

public class ThreadCreateDemo1 {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); //調(diào)用start()方法啟動線程,線程不一定立即執(zhí)行,CPU安排調(diào)度
    }
}
class MyThread extends Thread {//繼承Thread類
    @Override
    public void run() {//重寫run()方法诈唬,編寫線程執(zhí)行體
        super.run();
        System.out.println("hellow_world!");
    }
}

2.實現(xiàn)Runnable接口

public class ThreadCreateDemo2 {
    //創(chuàng)建線程對象韩脏,調(diào)用start()方法啟動線程
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}
class MyRunnable implements Runnable {
    public void run() {
        System.out.println("通過Runnable創(chuàng)建的線程!");
    }
}

上述兩種創(chuàng)建方式,工作時性質(zhì)一樣。但是建議使用實現(xiàn)Runable接口方式铸磅。解決單繼承的局限性赡矢。

3.實現(xiàn)Callable接口

public class ThreadCreateDemo3 implements Callable<Integer>{
    // 實現(xiàn)call方法,作為線程執(zhí)行體
    public Integer call(){
        int i = 0;
        for ( ; i < 100 ; i++ ){
            System.out.println(Thread.currentThread().getName()+ "\t" + i);
        }
        // call()方法可以有返回值
        return i;
    }
    public static void main(String[] args) {
        // 創(chuàng)建Callable對象
        ThreadCreateDemo3 myCallableTest = new ThreadCreateDemo3();
        // 使用FutureTask來包裝Callable對象
        FutureTask<Integer> task = new FutureTask<Integer>(myCallableTest);
        for (int i = 0 ; i < 100 ; i++){
            System.out.println(Thread.currentThread().getName()+ " \t" + i);
            if (i == 20){
                // 實質(zhì)還是以Callable對象來創(chuàng)建阅仔、并啟動線程
                new Thread(task , "callable").start();
            }
        }
        try{
            // 獲取線程返回值
            System.out.println("callable返回值:" + task.get());
        }
        catch (Exception ex){
            ex.printStackTrace();
        }
    }
}

  1. 實現(xiàn)Callable接口吹散,需要返回值類型

  2. 重寫call方法,需要拋出異常

  3. 創(chuàng)建目標對象

  4. 創(chuàng)建執(zhí)行服務:ExecutorService ser = Executors.newFixedThreadPool(1);

  5. 提交執(zhí)行:Future<boolean style="margin: 0px; padding: 0px;"> result1 = ser.submit(t1);</boolean>

  6. 獲取結果:boolean r1 = result1.get()

  7. 關閉服務:ser.shutdownNow();
    總結

  8. 不過實現(xiàn)Runnable接口與實現(xiàn)Callable接口的方式基本相同八酒,只是Callable接口里定義的方法有返回值空民,可以聲明拋出異常而已。 因此可以將實現(xiàn)Runnable接口和實現(xiàn)Callable接口歸為一種方式。

  9. Runnable界轩、Callable接口的方式創(chuàng)建多線程,所以非常適合多個相同線程來處理同一份資源的情況,如果需要訪問當前線程画饥,則必須使用Thread.currentThread()方法

  10. 采用繼承Thread類的方式創(chuàng)建多線程,因為線程類已經(jīng)繼承了Thread類,所以不能再繼承其他父類

生命周期

線程被創(chuàng)建并啟動以后浊猾,它既不是一啟動就進入了執(zhí)行狀態(tài)抖甘,也不是一直處于執(zhí)行狀態(tài)新建(New)、就緒(Runnable)葫慎、運行(Running)衔彻、阻塞(Blocked)和死亡(Dead)5種狀態(tài)

下載

Thread.State:

  1. 初始(NEW):新創(chuàng)建了一個線程對象,但還沒有調(diào)用start()方法幅疼。

  2. 運行(RUNNABLE):Java線程中將就緒(ready)和運行中(running)兩種狀態(tài)籠統(tǒng)的稱為“運行”米奸。
    線程對象創(chuàng)建后,其他線程(比如main線程)調(diào)用了該對象的start()方法爽篷。該狀態(tài)的線程位于可運行線程池中悴晰,等待被線程調(diào)度選中,獲取CPU的使用權逐工,此時處于就緒狀態(tài)(ready)铡溪。就緒狀態(tài)的線程在獲得CPU時間片后變?yōu)檫\行中狀態(tài)(running)。

  3. 阻塞(BLOCKED):表示線程阻塞于鎖泪喊。

  4. 等待(WAITING):進入該狀態(tài)的線程需要等待其他線程做出一些特定動作(通知或中斷)棕硫。

  5. 超時等待(TIMED_WAITING):該狀態(tài)不同于WAITING,它可以在指定的時間后自行返回袒啼。

  6. 終止(TERMINATED):表示該線程已經(jīng)執(zhí)行完畢

線程的優(yōu)先級

Java提供一個線程調(diào)度器來監(jiān)控程序中啟動后進入就緒狀態(tài)的所有線程哈扮,線程調(diào)度
器按照優(yōu)先級決定應該調(diào)度哪個線程來執(zhí)行。
線程的優(yōu)先級用數(shù)字表示蚓再,范圍從1~10.
hread.MIN_PRIORITY = 1;
Thread.MAX_PRIORITY = 10;
Thread.NORM_PRIORITY = 5;
使用以下方式改變或獲取優(yōu)先級
getPriority() . setPriority(int xxx)

線程方法

1 public void start() 使該線程開始執(zhí)行滑肉;Java 虛擬機調(diào)用該線程的 run 方法。
2 public void run() 如果該線程是使用獨立的 Runnable 運行對象構造的摘仅,則調(diào)用該 Runnable 對象的 run 方法靶庙;否則,該方法不執(zhí)行任何操作并返回娃属。
3 public final void setName(String name) 改變線程名稱六荒,使之與參數(shù) name 相同。
4 public final void setPriority(int priority) 更改線程的優(yōu)先級矾端。
5 public final void setDaemon(boolean on) 將該線程標記為守護線程或用戶線程掏击。
6 public final void join(long millisec) 等待該線程終止的時間最長為 millis 毫秒。
7 public void interrupt() 中斷線程秩铆。
8 public final boolean isAlive() 測試線程是否處于活動狀態(tài)砚亭。
9 public static void yield() 線程禮讓: 暫停當前正在執(zhí)行的線程對象,并執(zhí)行其他線程。
10 public static void sleep(long millisec) 線程休眠: 在指定的毫秒數(shù)內(nèi)讓當前正在執(zhí)行的線程休眠(暫停執(zhí)行)钠惩,此操作受到系統(tǒng)計時器和調(diào)度程序精度和準確性的影響。
11 public static boolean holdsLock(Object x) 當且僅當當前線程在指定的對象上保持監(jiān)視器鎖時族阅,才返回 true篓跛。
12 public static Thread currentThread() 返回對當前正在執(zhí)行的線程對象的引用。
13 public static void dumpStack() 將當前線程的堆棧跟蹤打印至標準錯誤流坦刀。

停止線程:jdk提供了stop愧沟,但不建議使用可以自己去停止它

守護(daemon)線程

線程分為前臺線程與后臺線程(用戶線程與守護線程)
虛擬機必須確保用戶線程執(zhí)行完畢
虛擬機不用等待守護線程執(zhí)行完畢

并發(fā),隊列 和 鎖鲤遥,死鎖

同一個對象被多個線程同時操作就是并發(fā)沐寺。

多個線程訪問同一個對象, 并且某些線程還想修改這個對象 .這時候我們就需要線程同步 . 線程同步其實就是一種等待機制 , 多個需要同時訪問此對象的線程進入這個對象的等待池 形成隊列, 等待前面線程使用完畢 , 下一個線
程再使用。

上面的并發(fā)問題我們會加一個鎖(synchronized)來解決盖奈。我鎖上門的時候你們都別進來混坞。但是加上鎖之后會有以下為:

  1. 一個線程持有鎖會導致其他所有需要此鎖的線程掛起 ;

  2. 在多線程競爭下 , 加鎖 , 釋放鎖會導致比較多的上下文切換 和 調(diào)度延時,引起性能問題 ;

  3. 如果一個優(yōu)先級高的線程等待一個優(yōu)先級低的線程釋放鎖 會導致優(yōu)先級倒置 , 引起性能問題 .

    java 死鎖產(chǎn)生的四個必要條件:

  • 1、互斥使用钢坦,即當資源被一個線程使用(占有)時究孕,別的線程不能使用

  • 2、不可搶占爹凹,資源請求者不能強制從資源占有者手中奪取資源厨诸,資源只能由資源占有者主動釋放。

  • 3禾酱、請求和保持微酬,即當資源請求者在請求其他的資源的同時保持對原有資源的占有。

  • 4颤陶、循環(huán)等待颗管,即存在一個等待隊列:P1占有P2的資源,P2占有P3的資源指郁,P3占有P1的資源忙上。這樣就形成了一個等待環(huán)路。

    死鎖的情況下如果打破上述任何一個條件闲坎,便可讓死鎖消失疫粥。

import java.util.Date;

public class LockTest {
   public static String obj1 = "obj1";
   public static String obj2 = "obj2";
   public static void main(String[] args) {
      LockA la = new LockA();
      new Thread(la).start();
      LockB lb = new LockB();
      new Thread(lb).start();
   }
}
class LockA implements Runnable{
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockA 開始執(zhí)行");
         while(true){
            synchronized (LockTest.obj1) {
               System.out.println(new Date().toString() + " LockA 鎖住 obj1");
               Thread.sleep(3000); // 此處等待是給B能鎖住機會
               synchronized (LockTest.obj2) {
                  System.out.println(new Date().toString() + " LockA 鎖住 obj2");
                  Thread.sleep(60 * 1000); // 為測試,占用了就不放
               }
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
class LockB implements Runnable{
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockB 開始執(zhí)行");
         while(true){
            synchronized (LockTest.obj2) {
               System.out.println(new Date().toString() + " LockB 鎖住 obj2");
               Thread.sleep(3000); // 此處等待是給A能鎖住機會
               synchronized (LockTest.obj1) {
                  System.out.println(new Date().toString() + " LockB 鎖住 obj1");
                  Thread.sleep(60 * 1000); // 為測試腰懂,占用了就不放
               }
            }
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

結果

Tue May 05 10:51:06 CST 2015 LockB 開始執(zhí)行
Tue May 05 10:51:06 CST 2015 LockA 開始執(zhí)行
Tue May 05 10:51:06 CST 2015 LockB 鎖住 obj2
Tue May 05 10:51:06 CST 2015 LockA 鎖住 obj1

解決

import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class UnLockTest {
   public static String obj1 = "obj1";
   public static final Semaphore a1 = new Semaphore(1);
   public static String obj2 = "obj2";
   public static final Semaphore a2 = new Semaphore(1);

   public static void main(String[] args) {
      LockAa la = new LockAa();
      new Thread(la).start();
      LockBb lb = new LockBb();
      new Thread(lb).start();
   }
}
class LockAa implements Runnable {
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockA 開始執(zhí)行");
         while (true) {
            if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
               System.out.println(new Date().toString() + " LockA 鎖住 obj1");
               if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
                  System.out.println(new Date().toString() + " LockA 鎖住 obj2");
                  Thread.sleep(60 * 1000); // do something
               }else{
                  System.out.println(new Date().toString() + "LockA 鎖 obj2 失敗");
               }
            }else{
               System.out.println(new Date().toString() + "LockA 鎖 obj1 失敗");
            }
            UnLockTest.a1.release(); // 釋放
            UnLockTest.a2.release();
            Thread.sleep(1000); // 馬上進行嘗試梗逮,現(xiàn)實情況下do something是不確定的
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}
class LockBb implements Runnable {
   public void run() {
      try {
         System.out.println(new Date().toString() + " LockB 開始執(zhí)行");
         while (true) {
            if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) {
               System.out.println(new Date().toString() + " LockB 鎖住 obj2");
               if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) {
                  System.out.println(new Date().toString() + " LockB 鎖住 obj1");
                  Thread.sleep(60 * 1000); // do something
               }else{
                  System.out.println(new Date().toString() + "LockB 鎖 obj1 失敗");
               }
            }else{
               System.out.println(new Date().toString() + "LockB 鎖 obj2 失敗");
            }
            UnLockTest.a1.release(); // 釋放
            UnLockTest.a2.release();
            Thread.sleep(10 * 1000); // 這里只是為了演示,所以tryAcquire只用1秒绣溜,而且B要給A讓出能執(zhí)行的時間慷彤,否則兩個永遠是死鎖
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

Tue May 05 10:59:13 CST 2015 LockA 開始執(zhí)行
Tue May 05 10:59:13 CST 2015 LockB 開始執(zhí)行
Tue May 05 10:59:13 CST 2015 LockB 鎖住 obj2
Tue May 05 10:59:13 CST 2015 LockA 鎖住 obj1
Tue May 05 10:59:14 CST 2015LockB 鎖 obj1 失敗
Tue May 05 10:59:14 CST 2015LockA 鎖 obj2 失敗
Tue May 05 10:59:15 CST 2015 LockA 鎖住 obj1
Tue May 05 10:59:15 CST 2015 LockA 鎖住 obj2

  1. synchronized 與 Lock 的對比
    Lock是顯式鎖(手動開啟和關閉鎖,別忘記關閉鎖)synchronized是隱式鎖,出了作用域自動釋放
  2. Lock只有代碼塊鎖底哗,synchronized有代碼塊鎖和方法鎖使用Lock鎖岁诉,JVM將花費較少的時間來調(diào)度線程,性能更好跋选。并且具有更好的擴展性(提供更多的子類)
  3. 優(yōu)先使用順序:
    Lock > 同步代碼塊(已經(jīng)進入了方法體涕癣,分配了相應資源)> 同步方法(在方
    法體之外)

線程通訊

線程通信的目標是使線程間能夠互相發(fā)送信號。另一方面前标,線程通信使線程能夠等待其他線程的信號坠韩。

線程的通信方式

  1. volatile
  2. Wait/Notify機制
  3. join方式
  4. threadLocal
  5. CountDownLatch 并發(fā)工具
  6. CyclicBarrier 并發(fā)工具

volatile

public class Volatile implements Runnable {
  private static volatile Boolean flag = true;

  @Override
  public void run() {
    while (flag) {
      System.out.println(Thread.currentThread().getName() + " - 執(zhí)行");
    }
    System.out.println("線程結束");
  }

  public static void main(String[] args) {
    Thread t = new Thread(new Volatile());
    t.start();
    try {
      Thread.sleep(5);
      flag = false;
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

Thread-0 - 執(zhí)行
Thread-0 - 執(zhí)行
Thread-0 - 執(zhí)行
Thread-0 - 執(zhí)行
Thread-0 - 執(zhí)行
線程結束

**WaitNotify **


public class WaitNotify {
  // 狀態(tài)鎖
  private static Object lock = new Object();
  private static Integer i = 0;

  public void odd() {
    while (i < 10) {
      synchronized (lock) {
        if (i % 2 == 1) {
          System.out.println(Thread.currentThread().getName() + " - " + i);
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          i++;
          lock.notify();
        } else {
          try {
            lock.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
  }

  public void even() {
    while (i < 10) {
      synchronized (lock) {
        if (i % 2 == 0) {
          System.out.println(Thread.currentThread().getName() + " - " + i);
          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          i++;
          lock.notify();
        } else {
          try {
            lock.wait();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    }
  }

  public static void main(String[] args) {

    WaitNotify waitNotify = new WaitNotify();

    Thread t1 = new Thread(() -> waitNotify.odd(), "線程1");
    Thread t2 = new Thread(() -> waitNotify.even(), "線程2");

    t1.start();
    t2.start();
  }
}

join

package threadCommunication;

public class JoinTest extends Thread {
    @Override
    public void run() {
        try {
            int sleepTime = (int) (Math.random() * 1000);
            System.out.println(sleepTime);
            Thread.sleep(sleepTime);
            System.out.println("JoinTest end");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        JoinTest j = new JoinTest();
        j.start();
        j.join();//當前線程main等待線程對象(j)銷毀
        System.out.println("main end");
    }

threadLocal

package sync; 
public class SequenceNumber { 
 // 定義匿名子類創(chuàng)建ThreadLocal的變量 
 private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() { 
 // 覆蓋初始化方法 
 public Integer initialValue() { 
        return 0; 
    } 
 }; 
 // 下一個序列號 
 public int getNextNum() { 
     seqNum.set(seqNum.get() + 1); 
     return seqNum.get(); 
 } 
 private static class TestClient extends Thread { 
     private SequenceNumber sn; 
     public TestClient(SequenceNumber sn) { 
     this.sn = sn; 
 } 
 // 線程產(chǎn)生序列號 
 public void run() { 
     for (int i = 0; i < 3; i++) { 
         System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" +            sn.getNextNum() + "]"); 
         } 
    } 
 } 
 /** 
 * @param args 
 */ 
 public static void main(String[] args) { 
     SequenceNumber sn = new SequenceNumber(); 
     // 三個線程產(chǎn)生各自的序列號 
     TestClient t1 = new TestClient(sn); 
     TestClient t2 = new TestClient(sn); 
     TestClient t3 = new TestClient(sn); 
     t1.start(); 
     t2.start(); 
     t3.start(); 
 } 
}

thread[Thread-1] sn[1] 
thread[Thread-1] sn[2] 
thread[Thread-1] sn[3] 
thread[Thread-2] sn[1] 
thread[Thread-2] sn[2] 
thread[Thread-2] sn[3] 
thread[Thread-0] sn[1]
thread[Thread-0] sn[2] 
thread[Thread-0] sn[3]

**CountDownLatch **CountDownLatch可以代替wait/notify的使用,并去掉synchronized

import java.util.concurrent.CountDownLatch;

public class CountDown {
  private static Integer i = 0;
  final static CountDownLatch countDown = new CountDownLatch(1);

  public void odd() {
    while (i < 10) {
      if (i % 2 == 1) {
        System.out.println(Thread.currentThread().getName() + " - " + i);
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        i++;
        countDown.countDown();
      } else {
        try {
          countDown.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  public void even() {
    while (i < 10) {
      if (i % 2 == 0) {
        System.out.println(Thread.currentThread().getName() + " - " + i);
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        i++;
        countDown.countDown();
      } else {
        try {
          countDown.await();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }

  public static void main(String[] args) {

    CountDown countDown = new CountDown();

    Thread t1 = new Thread(() -> countDown.odd(), "線程1");
    Thread t2 = new Thread(() -> countDown.even(), "線程2");

    t1.start();
    t2.start();
  }
}

CyclicBarrier

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
  public static void main(String[] args) {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
    new Thread(() -> {
      System.out.println(Thread.currentThread().getName() + ": 準備...");
      try {
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
      }
      System.out.println("全部啟動完畢!");
    }, "線程1").start();

    new Thread(() -> {
      System.out.println(Thread.currentThread().getName() + ": 準備...");
      try {
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
      }
      System.out.println("全部啟動完畢!");
    }, "線程2").start();

    new Thread(() -> {
      System.out.println(Thread.currentThread().getName() + ": 準備...");
      try {
        cyclicBarrier.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (BrokenBarrierException e) {
        e.printStackTrace();
      }
      System.out.println("全部啟動完畢!");
    }, "線程3").start();
  }
}

線程3: 準備...
線程2: 準備...
線程1: 準備...
全部啟動完畢!
全部啟動完畢!
全部啟動完畢!

線程池

經(jīng)常創(chuàng)建和銷毀、使用量特別大的資源炼列,比如并發(fā)情況下的線程只搁,對性能影響很大。提前創(chuàng)建好多個線程俭尖,放入線程池中氢惋,使用時直接獲取,使用完放回池中目溉∶靼梗可以避免頻繁創(chuàng)建銷毀、實現(xiàn)重復利用缭付。

ExecutorService 和 Executors

  1. ExecutorService:真正的線程池接口柿估。常見子類ThreadPoolExecutor
    void execute(Runnable command) :執(zhí)行任務/命令,沒有返回值陷猫,一般用來執(zhí)
    行Runnable

  2. <t style="margin: 0px; padding: 0px;">Future<t style="margin: 0px; padding: 0px;"> submit(Callable<t style="margin: 0px; padding: 0px;"> task):執(zhí)行任務秫舌,有返回值,一般又來執(zhí)行
    Callable</t></t></t>

  3. void shutdown() :關閉連接池

Executors:工具類绣檬、線程池的工廠類足陨,用于創(chuàng)建并返回不同類型的線程池

13.注解

Java 注解(Annotation)又稱 Java 標注,是 JDK5.0 引入的一種注釋機制娇未。

作用

不是程序本身 , 可以對程序作出解釋.(這一點和注釋(comment)沒什么區(qū)別)

可以被其他程序(比如:編譯器等)讀取.

可以附加在package , class , method , field 等上面 , 相當于給他們添加了額外的輔助信息

我們可以通過反射機制實現(xiàn)對這些元數(shù)據(jù)的訪問

格式

注解是以"@注釋名"在代碼中存在的

還可以添加一些參數(shù)值 , 例如:@SuppressWarnings(value="unchecked")

內(nèi)置注解

Java 定義了一套注解墨缘,共有 10 個,java7之前3 個在 java.lang 中零抬, 4 個在 java.lang.annotation 中镊讼,后續(xù)增加三個

作用在代碼的注解( java.lang )是
@Override - 檢查該方法是否是重寫方法。如果發(fā)現(xiàn)其父類平夜,或者是引用的接口中并沒有該方法時蝶棋,會報編譯錯誤。
@Deprecated - 標記過時方法忽妒。如果使用該方法玩裙,會報編譯警告兼贸。
@SuppressWarnings - 指示編譯器去忽略注解中聲明的警告。
作用在其他注解的注解(或者說 元注解)是( java.lang.annotation)注解
@Retention - 標識這個注解怎么保存吃溅,是只在代碼中溶诞,還是編入class文件中,或者是在運行時可以通過反射訪問决侈。
@Documented - 標記這些注解是否包含在用戶文檔中很澄。
@Target - 標記這個注解應該是哪種 Java 成員。
@Inherited - 標記這個注解是繼承于哪個注解類(默認 注解并沒有繼承于任何子類)
java7之后增加的注解
@SafeVarargs - Java 7 開始支持颜及,忽略任何使用參數(shù)為泛型變量的方法或構造函數(shù)調(diào)用產(chǎn)生的警告。
@FunctionalInterface - Java 8 開始支持蹂楣,標識一個匿名函數(shù)或函數(shù)式接口俏站。
@Repeatable - Java 8 開始支持,標識某注解可以在同一個聲明上使用多次痊土。

package com.annotation;
//測試內(nèi)置注解
import java.util.ArrayList;
import java.util.List;
//所有類默認繼承Object類
public class Test1 extends Object {
    //@Override 表示方法重寫
    //--> 查看JDK幫助文檔
    //--> 測試名字不同產(chǎn)生的效果
    @Override
    public String toString() {
        return super.toString();
    }
     //方法過時了, 不建議使用 , 可能存在問題 , 并不是不能使用!
    //--> 查看JDK幫助文檔
    @Deprecated
    public static void stop(){
        System.out.println("測試 @Deprecated");
    }
    //@SuppressWarnings 抑制警告 , 可以傳參數(shù)
    //--> 查看JDK幫助文檔
    //查看源碼:發(fā)現(xiàn) 參數(shù)類型 和 參數(shù)名稱 , 并不是方法!
    @SuppressWarnings("all")
    public void sw(){
     List list = new ArrayList();
    }
    public static void main(String[] args) {
     stop();
    }
}   

元注解

package com.annotation;
import java.lang.annotation.*;
//測試元注解
public class Test2 {
@MyAnnotation
public void test(){
}
}
//定義一個注解
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
@interface MyAnnotation{
}

自定義注解

  1. 使用 @interface自定義注解時 , 自動繼承了java.lang.annotation.Annotation接口
    @ interface用來聲明一個注解 , 格式 : public @ interface 注解名 { 定義內(nèi)容 }

  2. 其中的每一個方法實際上是聲明了一個配置參數(shù).
    方法的名稱就是參數(shù)的名稱.

  3. 返回值類型就是參數(shù)的類型 ( 返回值只能是基本類型,Class , String , enum ).
    可以通過default來聲明參數(shù)的默認值

  4. 如果只有一個參數(shù)成員 , 一般參數(shù)名為value

  5. 注解元素必須要有值 , 我們定義注解元素時 , 經(jīng)常使用空字符串,0作為默認值 .

注解參數(shù)的可支持數(shù)據(jù)類型:
1.所有基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short)
2.String類型
3.Class類型
4.enum類型
5.Annotation類型
6.以上所有類型的數(shù)組

package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 水果名稱注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}
package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 水果顏色注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    /**
     * 顏色枚舉
     * @author peida
     *
     */
    public enum Color{ BULE,RED,GREEN};

    /**
     * 顏色屬性
     * @return
     */
    Color fruitColor() default Color.GREEN;

}
package annotation;

import annotation.FruitColor.Color;

public class Apple {

    @FruitName("Apple")
    private String appleName;

    @FruitColor(fruitColor=Color.RED)
    private String appleColor;

    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }
    public String getAppleColor() {
        return appleColor;
    }

    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }
    public String getAppleName() {
        return appleName;
    }

    public void displayName(){
        System.out.println("水果的名字是:蘋果");
    }
}

//設置默認值
package annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 水果供應者注解
 * @author peida
 *
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
    /**
     * 供應商編號
     * @return
     */
    public int id() default -1;

    /**
     * 供應商名稱
     * @return
     */
    public String name() default "";

    /**
     * 供應商地址
     * @return
     */
    public String address() default "";
}

14.反射

反射機制

Java的反射機制的實現(xiàn)要借助于4個類:class肄扎,Constructor,F(xiàn)ield赁酝,Method;
其中class代表的時類對 象犯祠,Constructor-類的構造器對象,F(xiàn)ield-類的屬性對象酌呆,Method-類的方法對象衡载。通過這四個對象我們可以粗略的看到一個類的各個組 成部分。

獲取類的方法

//調(diào)用運行時類本身的.class屬性
Class clazz = String.class;

//通過運行時類的對象獲取
Person p = new Person();

Class clazz = p.getClass();

//通過Class的靜態(tài)方法獲取:體現(xiàn)反射的動態(tài)性
String className = “java.util.commons”;

Class clazz = Class.forName(className);

//通過類的加載器
String className = “java.util.commons”;

ClassLoader classLoader = this.getClass().getClassLoader();

Class clazz = classLoader.loadClass(className);

得到構造器的方法

Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數(shù)類型的公共構造函數(shù)隙袁, 

Constructor[] getConstructors() -- 獲得類的所有公共構造函數(shù) 

Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數(shù)類型的構造函數(shù)(與接入級別無關) 

Constructor[] getDeclaredConstructors() -- 獲得類的所有構造函數(shù)(與接入級別無關)

獲取字段

Field getField(String name) -- 獲得命名的公共字段 

Field[] getFields() -- 獲得類的所有公共字段 

Field getDeclaredField(String name) -- 獲得類聲明的命名的字段 

Field[] getDeclaredFields() -- 獲得類聲明的所有字段

獲取方法的信息

Method getMethod(String name, Class[] params) -- 使用特定的參數(shù)類型痰娱,獲得命名的公共方法 

Method[] getMethods() -- 獲得類的所有公共方法 

Method getDeclaredMethod(String name, Class[] params) -- 使用特寫的參數(shù)類型,獲得類聲明的命名的方法 

Method[] getDeclaredMethods() -- 獲得類聲明的所有方法

通過 Class 類獲取成員變量菩收、成員方法梨睁、接口、超類娜饵、構造方法等

package com.ys.reflex;
public class Person {
    //私有屬性
    private String name = "Tom";
    //公有屬性
    public int age = 18;
    //構造方法
    public Person() {
    }
    //私有方法
    private void say(){
        System.out.println("private say()...");
    }
    //公有方法
    public void work(){
        System.out.println("public work()...");
    }
}

//獲得類完整的名字
String className = c2.getName();
System.out.println(className);//輸出com.ys.reflex.Person

//獲得類的public類型的屬性坡贺。
Field[] fields = c2.getFields();
for(Field field : fields){
   System.out.println(field.getName());//age
}

//獲得類的所有屬性。包括私有的
Field [] allFields = c2.getDeclaredFields();
for(Field field : allFields){
    System.out.println(field.getName());//name    age
}

//獲得類的public類型的方法箱舞。這里包括 Object 類的一些方法
Method [] methods = c2.getMethods();
for(Method method : methods){
    System.out.println(method.getName());//work waid equls toString hashCode等
}

//獲得類的所有方法遍坟。
Method [] allMethods = c2.getDeclaredMethods();
for(Method method : allMethods){
    System.out.println(method.getName());//work say
}

//獲得指定的屬性
Field f1 = c2.getField("age");
System.out.println(f1);
//獲得指定的私有屬性
Field f2 = c2.getDeclaredField("name");
//啟用和禁用訪問安全檢查的開關,值為 true褐缠,則表示反射的對象在使用時應該取消 java 語言的訪問檢查政鼠;反之不取消
f2.setAccessible(true);
System.out.println(f2);

//創(chuàng)建這個類的一個對象
Object p2 =  c2.newInstance();
//將 p2 對象的  f2 屬性賦值為 Bob,f2 屬性即為 私有屬性 name
f2.set(p2,"Bob");
//使用反射機制可以打破封裝性队魏,導致了java對象的屬性不安全公般。
System.out.println(f2.get(p2)); //Bob

//獲取構造方法
Constructor [] constructors = c2.getConstructors();
for(Constructor constructor : constructors){
    System.out.println(constructor.toString());//public com.ys.reflex.Person()
}

反射方法執(zhí)行

public class Apple {

    private int price;

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public static void main(String[] args) throws Exception{
        //正常的調(diào)用
        Apple apple = new Apple();
        apple.setPrice(5);
        System.out.println("Apple Price:" + apple.getPrice());
        //使用反射調(diào)用
        Class clz = Class.forName("com.wyl.api.Apple");
        Method setPriceMethod = clz.getMethod("setPrice", int.class);
        Constructor appleConstructor = clz.getConstructor();
        Object appleObj = appleConstructor.newInstance();
        setPriceMethod.invoke(appleObj, 14);
        Method getPriceMethod = clz.getMethod("getPrice");
        System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
    }
}
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末万搔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子官帘,更是在濱河造成了極大的恐慌瞬雹,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刽虹,死亡現(xiàn)場離奇詭異酗捌,居然都是意外死亡,警方通過查閱死者的電腦和手機涌哲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門胖缤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人阀圾,你說我怎么就攤上這事哪廓。” “怎么了初烘?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵涡真,是天一觀的道長。 經(jīng)常有香客問我肾筐,道長哆料,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任吗铐,我火速辦了婚禮东亦,結果婚禮上,老公的妹妹穿的比我還像新娘唬渗。我一直安慰自己讥此,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布谣妻。 她就那樣靜靜地躺著萄喳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蹋半。 梳的紋絲不亂的頭發(fā)上他巨,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音减江,去河邊找鬼染突。 笑死,一個胖子當著我的面吹牛辈灼,可吹牛的內(nèi)容都是我干的份企。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼巡莹,長吁一口氣:“原來是場噩夢啊……” “哼司志!你這毒婦竟也來了甜紫?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤骂远,失蹤者是張志新(化名)和其女友劉穎囚霸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體激才,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡拓型,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘸恼。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劣挫。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖东帅,靈堂內(nèi)的尸體忽然破棺而出揣云,到底是詐尸還是另有隱情,我是刑警寧澤冰啃,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站刘莹,受9級特大地震影響阎毅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜点弯,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一扇调、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抢肛,春花似錦狼钮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至福稳,卻和暖如春涎拉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背的圆。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工鼓拧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人越妈。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓季俩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親梅掠。 傳聞我的和親對象是個殘疾皇子酌住,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容