Java基礎總結(附帶jdk路徑配置)
一、概述
java的三中技術架構 :
EE:開發企業環境下應用程式,主要針對web
SE:完成桌面應用程式的開發,是EE、ME的基礎
ME:開發電子消費產品和嵌入式裝置,如手機程式
-------------------------------------------------------------------------------------
jdk:java的開發和執行環境(其自身帶有jre)
jre:java的執行環境,包括java api 和 JVM
-------------------------------------------------------------------------------------
配置環境
讓JDK bin目錄下的工具可以在任意資料夾下執行
(將jdk的地址告訴系統,用時讓系統幫我們去找)
具體 過程
開啟 控制面板->系統和安全->系統->更改設定->高階->環境變數
方法一:
在系統變數中找到Path(沒有就新建一個一般是有的)
直接給Path配置JDK bin目錄的絕對路徑
例如:Path=C:\Program Files\Java\jdk1.8.0_111\bin(根據你自己jdk安裝的位置而變)
例如:Path=****;C:\Program Files\Java\jdk1.8.0_111\bin;****(***表示有其他內容)
例如:Path=****;C:\Program Files\Java\jdk1.8.0_111\bin
方法二:
在系統變數中新建JAVA_HOME
給它配置上你電腦上jdk的絕對路徑
JAVA_HOME=C:\Program Files\Java\jdk1.8.0_111(根據你自己jdk安裝的位置而變)
在系統變數中找到Path(沒有就新建一個一般是有的)
例如:Path=%JAVA_HOME%\bin
例如:Path=****;%JAVA_HOME%\bin;****(***表示有其他內容)
例如:Path=****;%JAVA_HOME%\bin
基本上如上配置就行還有個classpath說下
這個配置不配置都行,那麼它是幹什麼的呢?
故名思意:位元組碼檔案路徑,也就是java命令時要去哪裡找編譯好的.class檔案路徑
那為啥配不配都行呢,那是因為(jdk5)後jdk預設.class路徑為當前路徑(javac編譯路徑)即
.java和.class是在同一資料夾下所有系統能找到他;
如果配置了那系統首先會去classpath目錄下搜尋,找到就執行它
那如果找不到還會在當前資料夾下搜尋嗎?
1:如果classpath的值結尾處有分號,在具體路徑中沒有找到執行的類,會預設在當前目錄
再找一次。
2:如果classpath的值結果出沒有分號,在具體的路徑中沒有找到執行的類,不會再
當前目錄找。
參考至:http://blog.csdn.net/u013189927/article/details/51195303
-------------------------------------------------------------------------------------
java命令和javac命令
javac命令負責編譯 將指定的.java檔案編譯成jvm可以識別的.class檔案
java命令負責啟動jvm,載入執行時所需類庫,執行.class檔案
(main函式是被執行的起始點)
-------------------------------------------------------------------------------------
二:java語法基礎(java區分大小寫)
主函式:保證所有類的獨立執行,是程式的入口,被jvm呼叫
關鍵字:java語言中已經賦予特殊含義的單詞,不能被作為變數名和過程名(包名,
類名、介面名等等)
例如:int,char,class等等
保留字:未來要定義成關鍵字的單詞,同樣不能作為變數名和過程名
識別符號:其實就是在程式中自定義的名詞。比如類名,變數名,函式名
由字母、數字、下劃線、美元符構成,不能以數字開頭
常量:由final和static一起宣告的變數定義時產生一般建議以全大寫來命名
(無論new多少個物件常量只有一個,且它在定義時就必須被賦值可以直接
賦值也可以變數賦值(變數賦值時變數如果有賦值則常量為該值,否則為改變數型別預設值)
)
static塊(一次http請求中假如有多次使用用一個有靜態塊的類,static塊只會執行一次)
變數:{
記憶體中的一個儲存空間,用於儲存資料
方便運算不確定的資料,變數空間可以重複使用
命名一般用駝峰式
作用域:變數定義的位置開始,到該變數所在的那對大括號結束
生命週期:變數從定義的位置開始就在記憶體中活了;
變數到達它所在的作用域的時候就在記憶體中消失了;
}
-------------------------------------------------------------------------------------
資料型別:
基本資料型別:byte 1位元組、short 2位元組、int 4位元組、long 8位元組、float 4位元組、double 8位元組、char 2位元組、boolean 1位元組(不同語言所佔位元組不同)
引用資料型別: 陣列、類、介面。(函式傳引用時傳的是地址)
級別從低到高為:byte,char,short(這三個平級)-->int-->float-->long-->double
自動型別轉換:從低級別到高級別,系統自動轉的;
強制型別轉換:什麼情況下使用?把一個高級別的數賦給一個別該數的級別低的變數;
(可能會溢位或丟失必須由程式設計師自己轉換)
-------------------------------------------------------------------------------------
算術運算子
+、-、*、/、%:任何整數模2不是0就是1,所以只要改變被模數就可以實現開關運算
++、--
-------------------------------------------------------------------------------------
連線符
+:連線字串
-------------------------------------------------------------------------------------
賦值運算子
=、+=、-=、*=、/=、%=
例如a+=b,a/=b等同於 a=a+b;a=a/b;
-------------------------------------------------------------------------------------
比較運算子
==、!=
-------------------------------------------------------------------------------------
邏輯運算子
& | ^ ! && ||
除了!外其他都是用於連線兩個boolean表示式
&:只有兩邊結果都為true結果才為true。否則就錯
&&:只有兩邊結果都為true結果才為true。否則就錯
&和&&的區別:&&會短路,&不會
短路:左邊為true時會去判斷右邊,左邊為false時直接返回false不去判斷右邊
|:只要兩邊都為false結果是false,否則就是true
||:只要兩邊都為false結果是false,否則就是true
|和||的區別:||會短路,|不會
短路:左邊為true時直接返回true,左邊為false時才去判斷右邊
^:異或和!=有點像
兩邊結果一樣就為false
兩邊結果不一樣就為true
位運算子:用於操作二進位制的運算子
& | ^ << >> >>>無符號右移
練習:兩個int資料進行互動,不用第3方變數
int a=3,b=5;
a=a+b;
b=a-b;
a=a-b;
a=a^b; 1111000
b=a^b; 0100110
a=a^b; 1011110
高效算出
例子 2*8=2<<3;
<<(有符號)邏輯左移 低位補0 以起點為準
>>(有符號)邏輯右移 正數高位補0 負數數高位補符號位 以起點為準
>>>(無符號)邏輯右移(注意並沒有無符號邏輯左移)高位補0 以起點為準(計算機只認補碼)
都是移到二進位制,如上例int在java中佔4個字元32個位首尾是符號(1表示負數0表示正數)
2變成2進位制******0000000010(太多0就不寫了)總32位
向左移到3位******0000010000轉成十進位制2^4也就是16
如果是負數
例如-2
1000。。。。010
1111.。。。。101
1111.。。。。110
到了這一步在去執行<< >> >>>操作
例如>>1
1111.。。。。111
1111.。。。。110
1000.。。。。001
-1
int型別的取值範圍為[-2^31,(2^31)-1](負數在java中是以補碼存在的)
&:位與
000010
110110
000010
|:位或
000010
110110
110110
-------------------------------------------------------------------------------------
三、語句
if...else switch do..while while for
(因為這些都是常見的在這裡不做過多介紹)
switch和if。。else有點相似,兩者看情況使用,(switch 只支援enum、int、string,char)
使用switch時最好將case後要執行的過程封裝成方法這樣是程式碼美觀切易於理解。
do...while和while的區別在於前者要先執行一次在判斷而後者要先判斷在執行
break:作用於switch和迴圈結構,用於跳出,或者稱為結束當前迴圈
continue:只作用於迴圈結構
結束本次迴圈,繼續下一次迴圈
函式:為了提高程式碼的複用性,可以將其定義為一個獨特的功能,該功能的體現就是
java的函式
格式:
修飾符 返回值型別 函式名(引數型別 引數,,,,){
過程
return ??;
}
當函式沒有具體的返回值時,返回的返回值型別用void關鍵字表示。
如果函式的返回值型別是void時,return語句可以省略不寫的,系統會幫你自動加上。
return的作用:結束函式。結束功能。
如何定義一個函式?
函式其實就是一個功能,定義函式就是實現功能,通過兩個明確來完成:
明確該功能的運算完的結果,其實是在明確這個函式的返回值型別。
在實現該功能的過程中是否有未知內容參與了運算,其實就是在明確這個函式的引數列表
(引數型別&引數個數)。
函式中只能呼叫函式,不能定義函式。
函式名稱最好和函式功能掛鉤(增加閱讀性),
過載的定義是:在一個類中,如果出現了兩個或者兩個以上的同名函式,
只要它們的引數的個數,或者引數的型別不同,即可稱之為該函式過載了。
如何區分過載:當函式同名時,只看引數列表。和返回值型別沒關係。
陣列:用於儲存同一種類型資料的容器;
下標從0開始
如何定義陣列:
元素型別【】 變數名=new 元素型別【n】; n可以是一個變數;
元素型別【】 變數名={元素,元素,,,,,,};
元素型別【】 變數名=new 元素型別【】{元素,元素,,,,,,};
二分查詢法。必須有前提:陣列中的元素要有序。
public static int halfSeach_2(int[] arr,int key){
int min,max,mid;
min = 0;
max = arr.length-1;
mid = (max+min)>>1; //(max+min)/2;
while(arr[mid]!=key){
if(key>arr[mid]){
min = mid + 1;
}
else if(key<arr[mid])
max = mid - 1;
if(max<min)
return -1;
mid = (max+min)>>1;
}
return mid;
}
java分了5片記憶體。
1:暫存器。2:本地方法區。3:方法區。4:棧。5:堆。
1:每一個實體都有記憶體首地址值。
2:堆記憶體中的變數都有預設初始化值。因為資料型別不同,值也不一樣。
3:垃圾回收機制
4:儲存的都是區域性變數 ( 函式中定義的變數,函式上的引數,語句中的變數 );
只要資料運算完成所在的區域結束,該資料就會被釋放。
5:用於儲存陣列和物件,也就是實體。啥是實體啊?就是用於封裝多個數據的。
-------------------------------------------------------------------------------------
四、面向物件
以前是面向過程(我理解成以前是寫一個個函式去完成專案)
而面向物件是對函式等一系列內容進行封裝;
匿名物件當物件只調用一次時可以使用 new Trees().plant();
類中的成員有兩種
1、成員變數:其實就是類的屬性
2、成員方法:其實就是成員函式
定義一個類就是定義上述的2種成員,那你首先得分析要定義的類的需求
成員的4中許可權
public private protect 包許可權(預設)
public:所有人都能訪問
private:自己本身可以訪問,別人都訪問不了
protect:被自己訪問和自己的子類訪問和同包中可以訪問
包許可權:同一個page中可以訪問和自己可以訪問
開發是屬性是用於儲存資料的,直接被訪問容易出現安全隱患,所以
通常都是私有化在提供方法去訪問它
成員變數和區域性變數的區別:
成員變數定義在類中,而區域性變數定義在方法,語句,引數中
成員變數在該類的物件(針對同一個物件)存在期間一直存在
而區域性變數在該方法完成時就會被銷燬
成員變數在堆記憶體中
區域性變數在棧記憶體中
建構函式:為物件進行初始化,它有針對性(針對呼叫他建立的物件),是函式的一種
1、改函式名和類名一樣
2、不需寫返回值型別
3、更不需要return
一個類在定義時如果自己沒定義建構函式那會預設給它一個空的建構函式
但是如果你定義了建構函式你預設便不會執行所以最好養成給它一個空的構造
也即是說類可以出現過載的建構函式
建構函式和其他函式的區別:
1、格式不同
2、建構函式是在物件建立時被呼叫,且只執行一次,以後你想用都不行
一般函式,是物件建立後才被呼叫,想調幾次就調幾次
如何寫建構函式
分析有無一開始就具備的屬性或者需要去執行的行為(呼叫方法)
如果有需求就寫在其中,沒有就鍵一個空的建構函式
構造程式碼塊和建構函式的區別
構造程式碼塊是給所有的物件建立時都會呼叫的
建構函式值針對呼叫的了它所建立的物件
順便說下何為構造程式碼塊在類中沒有前後綴的大括號區域
public Text{
{
system.out.println(“x”);
}
}
普通程式碼塊:函式,方法後面的大括號
同步程式碼塊:使用synchronize關鍵字修飾的大括號也就它後面的大括號
應用於多執行緒下的物件鎖定
靜態程式碼塊,以static關鍵字修飾的大括號也就它後面的大括號
在類被使用的第一次載入,且一直存在,直到類被使用的區域生命週期結束為止
靜態程式碼塊、構造程式碼塊、建構函式同時存在時的執行順序:靜態程式碼塊 à 構造程式碼塊 à 建構函式;
建立一個物件在記憶體中做了什麼
1將編譯好的.class檔案載入進來
2執行main方法時,在棧記憶體開闢main方法的空間,然後main方法的棧區分配一個
變數p
3在堆記憶體中開闢實體空間,分配一個記憶體首地址值
4在該實體空間中進行屬性的空間分配,並進行了預設初始化
5對空間中的屬性進行顯示初始化
6進行實體的構造程式碼塊初始化
7呼叫該實體對應的建構函式,進行初始化
8將地址賦值給p,p變數引用該實體
(2有點不懂)
封裝
隱藏物件的屬性和實現細節(函式),僅對外提供公共訪問方法
將變化隔離,便於使用,提高重用性,安全性
this
代表物件,就是所在函式所屬物件
this物件後面跟上 . 呼叫的是成員屬性和成員方法(一般方法);
this物件後面跟上 () 呼叫的是本類中的對應引數的建構函式。
用this()呼叫建構函式,必須定義在建構函式的第一行。應為如果在構造
函式的第一行沒有找到this()或super時系統會自動補上super()這樣就相當於
使用了父類的無參建構函式,那麼它在建構函式的下面又使用了this(**)那就去
呼叫本類的其他建構函式這個時候又相當於去呼叫父類的無參建構函式,造成資源的
浪費或是出現一些不意料之外的結果
static:靜態關鍵字 用於修飾成員變數或者是方法
作用在成員變數時相當於類的全域性變數只屬於類本身,任意其他物件對
它的操作都影響到其他物件
作用在函式時可以不必new一個物件,直接類名.函式名呼叫
靜態方法只能訪問靜態成員和方法,不可以訪問非靜態成員和方法
因為靜態方法載入時,優先於物件存在,所以沒有辦法訪問物件中的成員。
相反則沒有這個限制
靜態方法中不能使用this,super關鍵字。
因為this代表物件,而靜態在時,有可能沒有物件,所以this無法使用。
什麼時候定義靜態成員呢?
成員分兩種:
1,成員變數。(資料共享時靜態化)
該成員變數的資料是否是所有物件都一樣:
如果是,那麼該變數需要被靜態修飾,因為是共享的資料。
如果不是,那麼就說這是物件的特有資料,要儲存到物件中。
2,成員函式。(方法中沒有呼叫特有資料時就定義成靜態)
如果判斷成員函式是否需要被靜態修飾呢?
只要參考,該函式內是否訪問了物件中的特有資料:
如果有訪問特有資料,那方法不能被靜態修飾。
如果沒有訪問過特有資料,那麼這個方法需要被靜態修飾。
成員變數和靜態變數的區別:
1,成員變數所屬於物件,所以也稱為例項變數。
靜態變數所屬於類,所以也稱為類變數。
2,成員變數存在於堆記憶體中。
靜態變數存在於方法區中。
3,成員變數隨著物件建立而存在,隨著物件被回收而消失。
靜態變數隨著類的載入而存在,隨著類的消失而消失。
4,成員變數只能被物件所呼叫。
靜態變數可以被物件呼叫,也可以被類名呼叫。
所以,成員變數可以稱為物件的特有資料,靜態變數稱為物件的共享資料。
-------------------------------------------------------------------------------------
設計模式
單例設計模式
用處保證一個類的物件在記憶體中的唯一性
多程式讀取一個配置檔案時,建議配置檔案封裝成物件。會方便操作其中資料,又要保證多個程式讀到的是同一個配置檔案物件,就需要該配置檔案物件在記憶體中是唯一的。
如何保證物件唯一性呢?
思想:
1,不讓其他程式建立該類物件。
2,在本類中建立一個本類物件。
3,對外提供方法,讓其他程式獲取這個物件。
步驟:
1,因為建立物件都需要建構函式初始化,只要將本類中的建構函式私有化,其他程式就無法再建立該類物件;
2,就在類中建立一個本類的物件;
3,定義一個方法,返回該物件,讓其他程式可以通過方法就得到本類物件。(作用:可控)
程式碼體現:
1,私有化建構函式;
2,建立私有並靜態的本類物件;
3,定義公有並靜態的方法,返回該物件。;
例子:
public class TokenUtils {
private TokenUtils() {}
private static final TokenUtils instance = new TokenUtils();
public static TokenUtils getInstance(){
return instance;
}
public String makeToken(){
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(token.getBytes());
//base64編碼--任意二進位制編碼明文字元 adfsdfsdfsf
Base64 encoder = new Base64();
return encoder.encodeAsString(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
-------------------------------------------------------------------------------------
繼承:
1:提高了程式碼的複用性。
2:讓類與類之間產生了關係,提供了另一個特徵多型的前提。
父類的由來:其實是由多個類不斷向上抽取共性內容而來的。
java中對於繼承,java只支援單繼承。java雖然不直接支援多繼承,
但是保留了這種多繼承機制,進行改良。
單繼承:一個類只能有一個父類。
多繼承:一個類可以有多個父類。
為什麼不支援多繼承呢?
因為當一個類同時繼承兩個父類時,兩個父類中有相同的功能,那麼子類物件呼叫該功能時,執行哪一個呢?因為父類中的方法中存在方法體。
但是java支援多重繼承。A繼承B B繼承C C繼承D。
多重繼承的出現,就有了繼承體系。體系中的頂層父類是通過不斷向上抽取而來的。它裡面定義的該體系最基本最共性內容的功能。
所以,一個體系要想被使用,直接查閱該系統中的父類的功能即可知道該體系的基本用法。那麼想要使用一個體系時,需要建立物件。建議建立最子類物件,因為最子類不僅可以使用父類中的功能。還可以使用子類特有的一些功能。
簡單說:對於一個繼承體系的使用,查閱頂層父類中的內容,建立最底層子類的物件。
子父類出現後,類中的成員都有了哪些特點:
1:成員變數。
當子父類中出現一樣的屬性時,子類型別的物件,呼叫該屬性,值是子類的屬性值。
如果想要呼叫父類中的屬性值,需要使用一個關鍵字:super
This:代表是本類型別的物件引用。
Super:代表是子類所屬的父類中的記憶體空間引用。
注意:子父類中通常是不會出現同名成員變數的,因為父類中只要定義了,子類就不用在定義了,直接繼承過來用就可以了。
2:成員函式。
當子父類中出現了一模一樣的方法時,建立子類物件會執行子類中的方法。好像父類中的方法被覆蓋掉一樣。所以這種情況,是函式的另一個特性:覆蓋(複寫,重寫)
什麼時候使用覆蓋呢?當一個類的功能內容需要修改時,可以通過覆蓋來實現。
3:建構函式。
發現子類建構函式執行時,先運行了父類的建構函式。為什麼呢?
原因:子類的所有建構函式中的第一行,其實都有一條隱身的語句super();
super(): 表示父類的建構函式,並會調用於引數相對應的父類中的建構函式。而super():是在呼叫父類中空引數的建構函式。
為什麼子類物件初始化時,都需要呼叫父類中的函式?(為什麼要在子類建構函式的第一行加入這個super()?)
因為子類繼承父類,會繼承到父類中的資料,所以必須要看父類是如何對自己的資料進行初始化的。所以子類在進行物件初始化時,先呼叫父類的建構函式,這就是子類的例項化過程。
注意:子類中所有的建構函式都會預設訪問父類中的空引數的建構函式,因為每一個子類構造內第一行都有預設的語句super();
如果父類中沒有空引數的建構函式,那麼子類的建構函式內,必須通過super語句指定要訪問的父類中的建構函式。
如果子類建構函式中用this來指定呼叫子類自己的建構函式,那麼被呼叫的建構函式也一樣會訪問父類中的建構函式。
問題:super()和this()是否可以同時出現的建構函式中。
兩個語句只能有一個定義在第一行,所以只能出現其中一個。
super()或者this():為什麼一定要定義在第一行?
上面已經有詳細訴過
繼承的細節:
什麼時候使用繼承呢?
當類與類之間存在著所屬關係時,才具備了繼承的前提。a是b中的一種。a繼承b。狼是犬科中的一種。
英文書中,所屬關係:" is a "
在方法覆蓋時,注意兩點:
1:子類覆蓋父類時,必須要保證,子類方法的許可權必須大於等於父類方法許可權可以實現繼承。否則,編譯失敗。
2:覆蓋時,要麼都靜態,要麼都不靜態。 (靜態只能覆蓋靜態,或者被靜態覆蓋)
繼承的一個弊端:打破了封裝性。對於一些類,或者類中功能,是不需要被繼承,或者複寫的。
這時如何解決問題呢?介紹一個關鍵字,final:最終。
final特點:
1:這個關鍵字是一個修飾符,可以修飾類,方法,變數。
2:被final修飾的類是一個最終類,不可以被繼承。
3:被final修飾的方法是一個最終方法,不可以被覆蓋。
4:被final修飾的變數是一個常量,只能賦值一次,一般會和static組合定義常量
常量名稱定義時,有規範,所有字母都大寫,如果由多個單片語成,中間用 _ 連線
抽象類: abstract
抽象:不具體,看不明白。抽象類表象體現。
在不斷抽取過程中,將共性內容中的方法宣告抽取,但是方法不一樣,沒有抽取,這時抽取到的方法,並不具體,需要被指定關鍵字abstract所標示,宣告為抽象方法。
例如:public abstract void ppx();
抽象方法所在類一定要標示為抽象類,也就是說該類需要被abstract關鍵字所修飾。
抽象類的特點:
1:抽象方法只能定義在抽象類中,抽象類和抽象方法必須由abstract關鍵字修飾(可以描述類和方法,不可以描述變數)。
2:抽象方法只定義方法宣告,並不定義方法實現。
3:抽象類不可以被建立物件(例項化)。
4:只有通過子類繼承抽象類並覆蓋了抽象類中的所有抽象方法後,該子類才可以例項化。否則,該子類還是一個抽象類。
抽象類的細節:
1:抽象類中是否有建構函式?有,用於給子類物件進行初始化。
2:抽象類中是否可以定義非抽象方法?
可以。其實,抽象類和一般類沒有太大的區別,都是在描述事物,只不過抽象類在描述事物時,有些功能不具體。所以抽象類和一般類在定義上,都是需要定義屬性和行為的。只不過,比一般類多了一個抽象函式。而且比一般類少了一個建立物件的部分。
3:抽象關鍵字abstract和哪些不可以共存?final , private , static
(抽象關鍵字本來就沒有具體實現需要通過繼承來實現,凡是阻礙其被繼承的存在都不可和其搭配)
4:抽象類中可不可以不定義抽象方法?可以。抽象方法目的僅僅為了不讓該類建立物件。
模板方法設計模式:
解決的問題:當功能內部一部分實現時確定,一部分實現是不確定的。這時可以把不確定的部分暴露出去,讓子類去實現。
abstract class GetTime{
public final void getTime(){ //此功能如果不需要複寫,可加final限定
long start = System.currentTimeMillis();
code(); //不確定的功能部分,提取出來,通過抽象方法實現
long end = System.currentTimeMillis();
System.out.println("毫秒是:"+(end-start));
}
public abstract void code(); //抽象不確定的功能,讓子類複寫實現
}
class SubDemo extends GetTime{
public void code(){ //子類複寫功能方法
for(int y=0; y<1000; y++){
System.out.println("y");
}
}
}