1. 程式人生 > >沈澱,再出發:Java基礎知識匯總

沈澱,再出發:Java基礎知識匯總

overflow 解析錯誤 his store mls 修飾 sed 自己 getc

沈澱,再出發:Java基礎知識匯總

一、前言

不管走得多遠,基礎知識是最重要的,這些知識就是建造一座座高樓大廈的基石和鋼筋水泥。對於Java這門包含了編程方方面面的語言,有著太多的基礎知識了,從最初的語法,對象的定義,類、接口、繼承、靜態、動態、重載、覆蓋這些基本的概念和使用方法,到稍微高級一點的多線程,文件讀寫,網絡編程,GUI使用,再到之後的反射機制、序列化、與數據庫的結合等高級一點的用法,最後將設計模式應用其中,產生了一個個新的概念,比如Spring、Spring MVC、Hibernate等產品以及AOP(面向切面編程)、IOC(控制反轉)、ID(依賴註入)、容器等概念,最後再加上強大的Tomcat等服務器充分將這些概念應用其中,產生了多種多樣的編程方式以及用法,因為Android系統編程的興起,最初就是使用Java來完成的(現在也可以使用kotlin了),從而又產生了新的編程概念,就這樣java語言像滾雪球一樣的不斷地擴展,深入到生活的方方面面,比如大數據的hadoop,可以說我們在不知不覺之中已經過分的充分的依靠java這門語言了,同時也在不斷地改善著java的能力和功能,比如後來的lambda表達式等等。再回過來仔細看看java這門語言,確實是有著很多的優點,比如GC垃圾回收機制,比如對多種平臺的適應性,比如java虛擬機的概念,可以說正是因為設計思想的獨到和通用性才使得java這麽快的風靡世界,今天我們就來稍微整理一下Java的基礎知識,將一些自己不確定的東西變得更加真實和堅實一點。

二、Java基礎知識

2.1、J2EE是什麽?

J2EE本身是一個標準,一個為企業分布式應用的開發提供的標準平臺。J2EE也是一個框架,包括JDBC、JNDI、RMI、JMS、EJB、JTA等技術。J2EE是一套全然不同於傳統應用開發的技術架構,包含許多組件,主要可簡化且規範應用系統的開發與部署,進而提高可移植性、安全與再用價值。J2EE核心是一組技術規範與指南,其中所包含的各類組件、服務架構及技術層次,均有共同的標準及規格,讓各種依循J2EE架構的不同平臺之間,存在良好的兼容性,解決過去企業後端使用的信息產品彼此之間無法兼容,企業內部或外部難以互通的窘境。J2EE組件和“標準的” Java類的不同點在於:它被裝配在一個J2EE應用中,具有固定的格式並遵守J2EE規範,由J2EE服務器對其進行管理。J2EE規範是這樣定義J2EE組件的:客戶端應用程序和applet是運行在客戶端的組件;Java Servlet和Java Server Pages (JSP) 是運行在服務器端的Web組件;Enterprise Java Bean (EJB )組件是運行在服務器端的業務組件。

技術分享圖片

Enterprise Java Bean 相當於DCOM,即分布式組件。它是基於Java的遠程方法調用(RMI)技術的,所以EJB可以被遠程訪問 (跨進程、跨計算機) 。但EJB必須被布署在諸如Webspere、WebLogic這樣的容器中,EJB客戶從不直接訪問真正的EJB組件,而是通過其容器訪問。EJB容器是EJB組件的代理,EJB組件由容器所創建和管理。客戶通過容器來訪問真正的EJB組件。Enterprise java bean 容器。更具有行業領域特色。他提供給運行在其中的組件EJB各種管理功能。只要滿足J2EE規範的EJB放入該容器,馬上就會被容器進行高效率的管理。並且可以通過現成的接口來獲得系統級別的服務。例如郵件服務、事務管理。

EJB與JAVA BEAN是SUN的不同組件規範,EJB是在容器中運行的,分步式的,而JAVA BEAN主要是一種可利用的組件,主要在客戶端UI表現上。Java Bean 是可復用的組件,對Java Bean並沒有嚴格的規範,理論上講,任何一個Java類都可以是一個Bean。但通常情況下,由於Java Bean是被容器所創建(如Tomcat)的,所以Java Bean應具有一個無參的構造器,另外,通常Java Bean還要實現Serializable接口用於實現Bean的持久性。Java Bean實際上相當於微軟COM模型中的本地進程內COM組件,它是不能被跨進程訪問的。Enterprise Java Bean 相當於DCOM,即分布式組件。它是基於Java的遠程方法調用(RMI)技術的,所以EJB可以被遠程訪問(跨進程、跨計算機)。但EJB必須被布署在諸如Webspere、WebLogic這樣的容器中,EJB客戶從不直接訪問真正的EJB組件,而是通過其容器訪問。EJB容器是EJB組件的代理,EJB組件由容器所創建和管理。客戶通過容器來訪問真正的EJB組件。

EJB容器提供的服務:主要提供聲明周期管理、代碼產生、持續性管理、安全、事務管理、鎖和並發行管理等服務。
EJB的角色和三個對象:EJB角色主要包括Bean開發者、應用組裝者、部署者、系統管理員、EJB容器提供者、EJB服務器提供者;三個對象是Remote(Local)接口、Home(LocalHome)接口,Bean類。
EJB的幾種類型:會話(Session)Bean、實體(Entity)Bean、消息驅動(Message Driven)Bean;會話Bean又可分為有狀態(Stateful)和無狀態(Stateless)兩種;實體Bean可分為Bean管理的持續性(BMP)和容器管理的持續性(CMP)兩種。

EJB(包括SessionBean,EntityBean)的生命周期和管理事務的方法:
SessionBean:Stateless Session Bean 的生命周期是由容器決定的,當客戶機發出請求要建立一個Bean的實例時,EJB容器不一定要創建一個新的Bean的實例供客戶機調用,而是隨便找一個現有的實例提供給客戶機。當客戶機第一次調用一個Stateful Session Bean 時,容器必須立即在服務器中創建一個新的Bean實例,並關聯到客戶機上,以後此客戶機調用Stateful Session Bean 的方法時容器會把調用分派到與此客戶機相關聯的Bean實例。
EntityBean:Entity Beans能存活相對較長的時間,並且狀態是持續的。只要數據庫中的數據存在,Entity beans就一直存活。而不是按照應用程序或者服務進程來說的。即使EJB容器崩潰了,Entity beans也是存活的。Entity Beans生命周期能夠被容器或者 Beans自己管理。
EJB通過以下技術管理實務:對象管理組織(OMG)的對象實務服務(OTS),Sun Microsystems的Transaction Service(JTS)、Java Transaction API(JTA),開發組(X/Open)的XA接口。
Bean 實例的生命周期:對於Stateless Session Bean、Entity Bean、Message Driven Bean一般存在緩沖池管理,而對於Entity Bean和Statefull Session Bean存在Cache管理,通常包含創建實例,設置上下文、創建EJB Object(create)、業務方法調用、remove等過程;對於存在緩沖池管理的Bean,在create之後實例並不從內存清除,而是采用緩沖 池調度機制不斷重用實例,而對於存在Cache管理的Bean則通過激活和去激活機制保持Bean的狀態並限制內存中實例數量。
激活機制:以Statefull Session Bean 為例,其Cache大小決定了內存中可以同時存在的Bean實例的數量,根據MRU或NRU算法,實例在激活和去激活狀態之間遷移,激活機制是當客戶端調用某個EJB實例業務方法時,如果對應EJB Object發現自己沒有綁定對應的Bean實例則從其去激活Bean存儲中(通過序列化機制存儲實例)回復(激活)此實例。狀態變遷前會調用對應的ejbActive和ejbPassivate方法。
remote接口和home接口主要作用:remote接口定義了業務方法,用於EJB客戶端調用業務方法;home接口是EJB工廠用於創建和移除查找EJB實例。
客服端調用EJB對象的幾個基本步驟:設置JNDI服務工廠以及JNDI服務地址系統屬性;查找Home接口;從Home接口調用Create方法創建Remote接口;通過Remote接口調用其業務方法。

有狀態session bean與無狀態session bean的區別:stateful session bean維護客戶端會話狀態.它們必須屬於一個且只屬於一個客戶端.激活/鈍化,開銷大.stateless session不維護一個客戶端的會話狀態它們被放入實例池中,因此可被多個用戶共用,開銷小,效率高。
本地視圖與遠程視圖的區別:遠程視圖中遠程調用將在兩臺不同JVM之間執行,遠程調用這些操作使得相關網絡開銷會更高與對象的位置無關,也不會在乎是否在一個JVM。
本地視圖是本地調用將在相同的JVM中執行,沒有網絡開銷,操作效率更高,因為客戶端使用本地對象調用bean上的服務,限制在本地實現中,而且不需要做到與位置無關。

實體Bean的三個狀態:no-state,Bean實例還沒有創建;pooled,Bean實例被創建,但還沒有和一個EJB Object關聯;ready,與EJB Object相關聯,若斷開關聯則回到pooled。

Jar、War、EAR、在文件結構上,三者並沒有什麽不同,它們都采用zip或jar檔案文件壓縮格式。但是它們的使用目的有所區別:
  Jar文件(擴展名為.jar,Java Application Archive)包含Java類的普通庫、資源(resources)、輔助文件(auxiliary files)等
War文件(擴展名為.war,Web Application Archive)包含全部Web應用程序。在這種情形下,一個Web應用程序被定義為單獨的一組文件、類和資源,用戶可以對jar文件進行封裝,並把它作為小型服務程序(servlet)來訪問。
Ear文件(擴展名為.ear,Enterprise Application Archive)包含全部企業應用程序。在這種情形下,一個企業應用程序被定義為多個jar文件、資源、類和Web應用程序的集合。
每一種文件(.jar, .war, .ear)只能由應用服務器(application servers)、小型服務程序容器(servlet containers)、EJB容器(EJB containers)等進行處理。
EAR文件包括整個項目,內含多個ejb module(jar文件)和web module(war文件);EAR文件的生成可以使用winrar zip壓縮方式或者jar命令。

2.2、JAVA解析xml的五種方式比較:

(1)DOM解析

DOM是html和xml的應用程序接口(API),以層次結構(類似於樹型)來組織節點和信息片段,映射XML文檔的結構,允許獲取和操作文檔的任意部分,是W3C的官方標準。
優點:允許應用程序對數據和結構做出更改;訪問是雙向的,可以在任何時候在樹中上下導航,獲取和操作任意部分的數據。
缺點:通常需要加載整個XML文檔來構造層次結構,消耗資源大。
①構建Document對象:

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = bdf.newDocumentBuilder();
    InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(xml文件);
    Document doc = bd.parse(is);

②遍歷DOM對象
Document: XML文檔對象,由解析器獲取
NodeList: 節點數組
Node: 節點(包括element、#text)
Element: 元素,可用於獲取屬性參數


(2)SAX(Simple API for XML)解析
流模型中的"推"模型分析方式。通過事件驅動,每發現一個節點就引發一個事件,事件推給事件處理器,通過回調方法完成解析工作,解析XML文檔的邏輯需要應用程序完成。
優點:不需要等待所有數據都被處理,分析就能立即開始;只在讀取數據時檢查數據,不需要保存在內存中;可以在某個條件得到滿足時停止解析,不必解析整個文檔;效率和性能較高,能解析大於系統內存的文檔。
缺點:需要應用程序自己負責TAG的處理邏輯(例如維護父/子關系等),文檔越復雜程序就越復雜;單向導航,無法定位文檔層次,很難同時訪問同一文檔的不同部分數據,不支持XPath。
原理:簡單的說就是對文檔進行順序掃描,當掃描到文檔(document)開始與結束、元素(element)開始與結束時通知事件處理函數(回調函數),進行相應處理,直到文檔結束。
事件處理器類型:①訪問XML DTD:DTDHandler ②低級訪問解析錯誤:ErrorHandler ③訪問文檔內容:ContextHandler
DefaultHandler類:SAX事件處理程序的默認基類,實現了DTDHandler、ErrorHandler、ContextHandler和EntityResolver接口,通常做法是,繼承該基類,重寫需要的方法,如startDocument()
創建SAX解析器:

    SAXParserFactory saxf = SAXParserFactory.newInstance();
    SAXParser sax = saxf.newSAXParser();

註:關於遍歷:深度優先遍歷、廣度優先遍歷


(3)JDOM(Java-based Document Object Model)
Java特定的文檔對象模型。自身不包含解析器,使用SAX。
優點:使用具體類而不是接口,簡化了DOM的API;大量使用了Java集合類,方便Java開發人員。
缺點:沒有較好的靈活性;性能較差。

(4)DOM4J(Document Object Model for Java)
簡單易用,采用Java集合框架,並完全支持DOM、SAX和JAXP
優點:大量使用了Java集合類,方便Java開發人員,同時提供一些提高性能的替代方法;支持XPath;有很好的性能。
缺點:大量使用了接口,API較為復雜。

(5)StAX(Streaming API for XML)
StAX API的實現是使用了Java Web服務開發(JWSDP)1.6,並結合了Sun Java流式XML分析器(SJSXP)-它位於javax.xml.stream包中。XMLStreamReader接口用於分析一個XML文檔,而XMLStreamWriter接口用於生成一個XML文檔。XMLEventReader負責使用一個對象事件叠代子分析XML事件-這與XMLStreamReader所使用的光標機制形成對照。流模型中的拉模型分析方式提供基於指針和基於叠代器兩種方式的支持,JDK1.6新特性。

和推式解析相比的優點:在拉式解析中,事件是由解析應用產生的,因此拉式解析中向客戶端提供的是解析規則,而不是解析器;同推式解析相比,拉式解析的代碼更簡單,而且不用那麽多庫;拉式解析客戶端能夠一次讀取多個XML文件;拉式解析允許你過濾XML文件和跳過解析事件。

2.3、介紹JAVA中的Collection FrameWork?

Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)
Map提供key到value的映射
Collection FrameWork如下:
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set

Map
├Hashtable
├HashMap
└WeakHashMap
ArrayList和Vector都是使用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,它們都允許直接按序號索引元素,但是插入元素要涉及數組元素移動等內存操作,所以索引數據快而插入數據慢,Vector由於使用了synchronized方法(線程安全),通常性能上較ArrayList差,而LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行前向或後向遍歷,但是插入數據時只需要記錄本項的前後項即可,所以插入速度較快。

HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在於HashMap允許空(null)鍵值(key),由於非線程安全,效率上可能高於Hashtable.
ArrayList與Vector主要從二方面來說:同步性,Vector是線程安全的,也就是說是同步的,而ArrayList是線程序不安全的,不是同步的;數據增長,當需要增長時,Vector默認增長為原來一培,而ArrayList卻是原來的一半。
HashMap與HashTable主要從三方面來說:歷史原因,Hashtable是基於陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現;同步性,Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的;值,只有HashMap可以將空值作為一個表的條目的key或value。

對List進行排序:使用java.util.Collections的sort靜態方法。一種方法是傳入一個Comparator對象,另一種方法是List中的對象實現Comparable。

2.4、運行時異常與一般異常有何異同?

異常表示程序運行過程中可能出現的非正常狀態,運行時異常表示虛擬機的通常操作中可能遇到的異常,是一種常見運行錯誤。java編譯器要求方法必須聲明拋出可能發生的非運行時異常,但是並不要求必須聲明拋出未被捕獲的運行時異常

error表示恢復不是不可能但很困難的情況下的一種嚴重問題。比如說內存溢出。不可能指望程序能處理這樣的情況。
exception表示一種設計或實現問題,也就是說,它表示如果程序運行正常,從不會發生的情況。

2.5、基礎常識

String與StringBuffer的區別:String的長度是不可變的,StringBuffer的長度是可變的。如果你對字符串中的內容經常進行操作,特別是內容要修改時,那麽使用StringBuffer,如果最後需要String,那麽使用StringBuffer的toString()方法。

char型變量中能夠定義成為一個中文,因為java中以unicode編碼,一個char占16個字節,所以放一個中文是沒問題的。

Anonymous Inner Class (匿名內部類) 可以繼承其他類或完成其他接口,在swing編程中常用此方式。

Static Nested Class 和 Inner Class的不同:Static Nested Class是被聲明為靜態(static)的內部類,它可以不依賴於外部類實例被實例化;而通常的內部類需要在外部類實例化後才能實例化。

靜態內部類可以有靜態成員,而非靜態內部類則不能有靜態成員;靜態內部類的非靜態成員方法可以訪問外部類的靜態變量,而不可訪問外部類的非靜態變量;非靜態內部類的非靜態成員可以訪問外部類的非靜態變量。

Collection 和 Collections的區別:Collection是集合類的上級接口,繼承與他的接口主要有Set 和List。Collections是針對集合類的一個幫助類,他提供一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作。

什麽時候用assert:用於測試boolean表達式狀態,可用於調試程序。使用方法 assert <boolean表達式>,表示如果表達式為真(true),則下面的語句執行,否則拋出AssertionError。另外的使用方式assert < boolean表達式>:<other表達式>,表示如果表達式為真,後面的表達式忽略,否則後面表達式的值用於AssertionError的構建參數。

基礎中的基礎:

String類是final類故不可以繼承。

String s = new String(“xyz”);創建了兩個String Object;
round方法返回與參數最接近的長整數,參數加1/2後求其floor:Math.round(11.5)==12;Math.round(-11.5)==-11
short s1 = 1; s1 = s1 + 1; (錯誤,s1+1運算結果是int型,需要強制轉換類型)
short s1 = 1; s1 += 1;(可以正確編譯)

float型 float f=3.4 不正確,因為精度不準確,應該用強制類型轉換,float f=(float)3.4 或float f = 3.4f。在java裏面,沒小數點的默認是int,有小數點的默認是 double; int轉成long系統自動作沒有問題,因為後者精度更高;double轉成float就不能自動做了,所以後面的加上個f;

一個".java"源文件中可以包括多個類(不是內部類)但是必須只有一個類名文件名相同。

Java沒有goto機制,java確實提供了goto語句,並且它是保留的關鍵字,但是JVM並沒有給它提供任何的實現,或許是java並沒打算放開使用這種機制。
技術分享圖片

數組沒有length()這個方法,有length的屬性;String有length()這個方法。

switch可作用於char byte short int;
switch可作用於char byte short int對應的包裝類;
switch不可作用於long double float boolean,包括他們的包裝類;
switch中可以是字符串類型,String(jdk1.7之後才可以作用在string上);
switch中可以是枚舉類型;

final, finally, finalize的區別:
final用於聲明屬性,方法和類,分別表示屬性不可變,方法不可覆蓋,類不可繼承
finally是異常處理語句結構的一部分,無論是否異常該部分代碼總是執行
finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法。

Overload和Override的區別:方法的重寫Overriding和重載Overloading是Java多態性的不同表現。重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。如果在子類中定義某方法與其父類有相同的名稱和參數,我們說該方法被重寫 (Overriding),子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被“屏蔽”了。如果在一個類中定義了多個同名的方法,它們或有不同的參數個數或有不同的參數類型,則稱為方法的重載(Overloading)。Overloaded的方法是可以改變返回值的類型

接口可以繼承接口抽象類可以實現(implements)接口抽象類可以繼承實體類,因為抽象類中不僅可以有抽象方法,也可以有非抽象方法,抽象類繼承了實體類則即包括自己的抽象方法也包括了繼承來的非抽象方法,但是和實體類的繼承一樣,也要求父類擁有子類可訪問到的構造器,這個構造器必須是公共的 ,可以供抽象類調用 。

try{}裏有一個return語句,那麽緊跟在這個try後的finally{}裏的code會被執行在return前執行

最常見到的runtime exception:

ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, 
CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException,
IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException,
ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException,
NullPointerException, ProfileDataException, ProviderException, RasterFormatException, SecurityException, SystemException,
UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException

sleep() 和 wait() 的區別:sleep是線程類(Thread)的方法,導致此線程暫停執行指定時間,給執行機會給其他線程,但是監控狀態依然保持,到時後會自動恢復,調用sleep不會釋放對象鎖。wait是Object類的方法,對此對象調用wait方法導致本線程放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象發出notify方法(或notifyAll)後本線程才進入對象鎖定池準備獲得對象鎖進入運行狀態。

synchronized和java.util.concurrent.locks.Lock的異同:兩者功能類似,都是用來控制線程同步。Lock能完成synchronized所實現的所有功能。Lock需要在finally代碼中釋放鎖,synchronized會自動釋放鎖。

啟動一個線程是調用start()方法,使線程所代表的虛擬處理機處於就緒狀態,以後可以由JVM調度並執行,但是並不意味著線程就會立即運行,一個線程必須關聯一些具體的執行代碼,run()方法是該線程所關聯的執行代碼,run()方法也可以產生必須退出的標誌來停止一個線程。

多線程有兩種實現方法,分別是繼承Thread類與實現Runnable接口;
同步的實現方面有兩種,分別是synchronized,wait與notify;

當一個線程進入一個對象的一個synchronized方法後,其它線程是否可進入此對象的其它方法?
當一個線程進入一個對象的synchronized()方法後,其他線程是否可以進入此對象的其他方法取決於方法本身,如果該方法是非synchronized()方法,那麽是可以訪問的;如果是synchronized()方法,那麽不能訪問,因為上一個方法使用了對象鎖;如果其他方法是靜態的方法,它用的同步鎖是當前類的字節碼,因此靜態方法可以被調用
當一個對象被當作參數傳遞到一個方法後,此方法可改變這個對象的屬性,並可返回變化後的結果,這裏是值傳遞Java 編程語言只由值傳遞參數,當一個對象實例作為一個參數被傳遞到方法中時,參數的值就是對該對象的引用,對象的內容可以在被調用的方法中改變,但對象的引用是永遠不會改變的

Class.forName()返回一個以字符串指定類名的類的對象;

什麽是java序列化,如何實現java序列化?
序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化。可以對流化後的對象進行讀寫操作,也可將流化後的對象傳輸於網絡之間。序列化是為了解決在對對象流進行讀寫操作時所引發的問題。
序列化的實現:將需要被序列化的類實現Serializable接口,該接口沒有需要實現的方法,implements Serializable只是為了標註該對象是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造一個ObjectOutputStream(對象流)對象,接著,使用ObjectOutputStream對象的writeObject(Object obj)方法就可以將參數為obj的對象寫出(即保存其狀態),要恢復的話則用輸入流。

2.6、abstract的method是否可同時是static、native或synchronized的

  • abstract修飾的方法是抽象的方法,只有聲明而沒有實現,他的實現要放入聲明該類的子類中實現。
  • static是靜態的,是一種屬於類而不屬於對象的方法或者屬性。
  • synchronized 是同步,是一種相對線程的鎖。
  • native 本地方法,這種方法和抽象方法及其類似,它也只有方法聲明,沒有方法實現,但是與抽象方法不同的是,它把具體實現移交給了本地系統的函數庫,而沒有通過虛擬機,可以說是Java與其它語言通訊的一種機制。

首先abstract與static,聲明static說明可以直接用類名調用該方法,聲明abstract說明需要子類重寫該方法,如果同時聲明static和abstract,用類名調用一個抽象方法是不行的。因為抽象方法是不能被調用的,原因就是抽象方法沒有方法體。但是,在一個類中定義了一個抽象方法,在這個類或其子類中是可以調用的。因為,具有抽象方法的類,一定是一個抽象類,而抽象類在被繼承的時候,必須重寫這個抽象類的抽象方法,而且,抽象類不能實例化,在使用這個抽象類的時候,使用的一定是這個抽象類的子類。因此在抽象類或其子類中可以使用這個抽象方法,是因為當真正實例化去使用的時候,使用的是子類重寫後的實例方法。
synchronized 是同步,然而同步是需要有具體操作才能同步的,如果像abstract只有方法聲明,那麽就不知道同步什麽代碼了,當然抽象方法在被子類繼承以後,可以添加同步。
native 這個東西本身就和abstract沖突,他們都是方法的聲明,只是一個把方法實現移交給子類,另一個是移交給本地操作系統。如果同時出現,就相當於即把實現移交給子類,又把實現移交給本地操作系統,那到底誰來實現具體方法呢
另附:不能放在一起的修飾符:final和abstract,private和abstract,static和abstract因為abstract修飾的方法是必須在其子類中實現,才能以多態方式調用,以上修飾符在修飾方法時期子類都覆蓋不了這個方法,final是不可以覆蓋,private是不能夠繼承到子類,所以也就不能覆蓋,static是可以覆蓋的,但是在調用時會調用編譯時類型的方法,因為調用的是父類的方法,而父類的方法又是抽象的方法,又不能夠調用,所以上的修飾符不能放在一起。

2.7、靜態變量、靜態方法、靜態代碼塊

類的生命周期分為裝載、連接、初始化、使用和卸載的五個過程。其中靜態代碼在類的初始化階段被初始化,而非靜態代碼則在類的使用階段(也就是實例化一個類的時候)才會被初始化。
靜態變量:可以將靜態變量理解為類變量(與對象無關),而實例變量則屬於一個特定的對象。
靜態變量有兩種情況:
靜態變量是基本數據類型,這種情況下在類的外部不必創建該類的實例就可以直接使用;
靜態變量是一個引用。這種情況比較特殊,主要問題是由於靜態變量是一個對象的引用,那麽必須初始化這個對象之後才能將引用指向它。因此如果要把一個引用定義成static的,就必須在定義的時候就對其對象進行初始化。
靜態方法:與類變量不同,方法(靜態方法與實例方法)在內存中只有一份,無論該類有多少個實例,都共用一個方法。
靜態方法與實例方法的不同主要有:
靜態方法可以直接使用,而實例方法必須在類實例化之後通過對象來調用。
在外部調用靜態方法時,可以使用“類名.方法名”或者“對象名.方法名”的形式,實例方法只能使用後面這種方式。
靜態方法只允許訪問靜態成員。而實例方法中可以訪問靜態成員和實例成員。
靜態方法中不能使用this(因為this是與實例相關的)。
靜態代碼塊:在java類中,可以將某一塊代碼聲明為靜態的。靜態代碼塊主要用於類的初始化,它只執行一次。
靜態代碼塊的特點主要有:
靜態代碼塊會在類被加載時自動執行。
靜態代碼塊只能定義在類裏面,不能定義在方法裏面。
靜態代碼塊裏的變量都是局部變量,只在塊內有效。
一個類中可以定義多個靜態代碼塊,按順序執行。
靜態代碼塊只能訪問類的靜態成員,而不允許訪問實例成員。

下面看一段代碼:

 1 package com.zyr.world;
 2 
 3 class Value {
 4     static int c = 0;
 5 
 6     Value() {
 7         c = 100;
 8     }
 9 
10     Value(int i) {
11         c = i;
12         System.out.println("value構造函數,c="+i);
13     }
14 
15     static void inc() {
16         c++;
17     }
18 }
19 
20 class Count {
21     
22     public Count(){
23         prt("count類構造函數開始執行...");
24     }
25     
26     public static void prt(String s) {
27         System.out.println(s);
28     }
29 
30     //在構造函數之前執行
31     Value v = new Value(10);
32     
33     //在靜態代碼塊執行完之後執行
34     static Value v1, v2;
35     
36     //類加載的時候執行
37     static {
38         prt("靜態代碼塊開始執行...");
39         prt("v1.c=" + v1.c + "  v2.c=" + v2.c);
40         v1 = new Value(27);
41         prt("v1.c=" + v1.c + "  v2.c=" + v2.c);
42         v2 = new Value(15);
43         prt("v1.c=" + v1.c + "  v2.c=" + v2.c);
44     }
45 
46     public static void main(String[] args) {
47         Count ct = new Count();
48         prt("主函數執行到打印...");
49         prt("ct.c=" + ct.v.c);
50         prt("v1.c=" + v1.c + "  v2.c=" + v2.c);
51         v1.inc();
52         prt("加一之後...");
53         prt("v1.c=" + v1.c + "  v2.c=" + v2.c);
54         prt("ct.c=" + ct.v.c);
55     }
56 }

從上面的代碼中我們可以理解靜態代碼塊、靜態變量、構造函數的初始化順序,如果再加上繼承關系我們更能深刻理解這些組成之間的關系了,另一方面我們在類中只定義了一個變量,並且是靜態的,因此在所有的操作之中,其實只有這一個變量(靜態變量)來作為對象的組成部分,也就是只有一個對象的內存再使用,我們可以理解為這些引用其實都是指向同一塊內存的,根據不同的執行順序進行修改,從而得到不同的結果。

技術分享圖片

2.8、JSP基礎知識

JSP共有以下9種基本內置組件:
request:用戶端請求,此請求會包含來自GET/POST請求的參數
response:網頁傳回用戶端的回應
pageContext:網頁的屬性是在這裏管理
session:與請求有關的會話期
application:servlet正在執行的內容
out:用來傳送回應的輸出
config:servlet的構架部件
page:JSP網頁本身
exception:針對錯誤網頁,未捕捉的例外

JSP共有以下6種基本動作:
jsp:include:在頁面被請求的時候引入一個文件。
jsp:useBean:尋找或者實例化一個JavaBean。
jsp:setProperty:設置JavaBean的屬性。
jsp:getProperty:輸出某個JavaBean的屬性。
jsp:forward:把請求轉到一個新的頁面。
jsp:plugin:根據瀏覽器類型為Java插件生成OBJECT或EMBED標記。
JSP中動態include用jsp:include動作實現,它總是會檢查所含文件中的變化,適合用於包含動態頁面,並且可以帶參數;靜態include用include偽碼實現,不會檢查所含文件的變化,適用於包含靜態頁面。

JSP四大屬性範圍:
pageContext:作用域是當前頁面。
request:作用域是一次請求。
session:作用域是一個客戶端會話。
application:作用域是整個應用,所有用戶共享。

JSP兩種include有什麽區別?
include指令:<%@include file=”MyJsp.jsp” %>
可以引用各種文本文件,包括jsp文件,只是單純的將文件合並,生成Servlet。file是只文件路徑,必須是實實在在的文件。
jsp:include標簽:<jsp:include page=”MyJsp.jsp” flush=”true”></jsp:include>
不是簡單的文本合並,而是兩個獨立的頁面。可以理解為將這個頁面的運行結果引用進來。page是頁面地址,例如可以是Servlet,所以不一定是一個存在的文件,而是一個可以訪問的地址。它當然還能帶參數,但是include指令不能。

redirect和forward的區別:
redirect是服務器發給客戶端一個狀態碼為3XX的響應,由客戶端負責跳轉,所以瀏覽器地址欄顯示的是跳轉後的地址。
forward又叫轉發,是服務器內部的跳轉,客戶端是不知道的,所以瀏覽器地址欄顯示的是跳轉前的地址。

2.9、HTTP、Servlet

GET和POST有什麽區別:GET請求參數會在地址欄顯示,POST不會。POST提交的數據可以比GET更大,類型更多,例如上傳文件需要用POST。POST更安全。本質的區別是,GET請求一般沒有請求body,參數直接寫在URL中,POST請求參數在請求body中。
Session和Cookie區別:Cookie保存在客戶端,而Session保存在服務器上;Session一般是通過Cookie中添加一項sessionid來實現功能,但是如果客戶端禁用Cookie的話,也可以將sessionid寫在url中;Session一般關閉瀏覽器後再打開就無效了,實際上是因為Cookie中的Sessionid失效而不是服務器保存的Session失效;Session可以用來做登陸後保持登陸狀態,Cookie可以做例如一個月自動登陸這樣的功能。
Servlet生命周期:
init初始化,整個生命周期只調用一次。
service處理請求,每次請求調用一次。
destroy銷毀, 整個生命周期只調用一次。
JSP和Servlet的相同和不同:
相同:JSP本質上是Servlet,最後會轉換成servlet執行。
不同:用法不同,在MVC模式中,Servlet用來做控制器,用於處理用戶請求和業務邏輯,再跳轉到相應的JSP,JSP一般用來做頁面顯示。

2.10、java中的堆和棧

技術分享圖片

Java中對象都是分配在heap(堆)中,從heap中分配內存所消耗的時間遠遠大於從stack產生存儲空間所需的時間。
(1)每個應用程序運行時,都有屬於自己的一段內存空間,用於存放臨時變量、參數傳遞、函數調用時的PC值的保存。這叫stack。
(2)所有的應用可以從一個系統共用的空間中申請供自己使用的內存,這個共用的空間叫heap。
(3)stack中的對象或變量只要定義好就可使用了,應用程序結束時會自動釋放。
(4)而要使用heap中申請的變量或對象只能定義變量指針,並要求在運行過程中通過new來動態分配內存空間,而且必須顯式地free申請過的內存,不過Java的垃圾回收機解決了這個問題,它會釋放這部分內存。
(5)stack中變量的大小和個數會影響exe的文件大小,但速度快。堆中的變量大小與exe大小關系不大,但分配和釋放需要耗費的時間遠大於stack中分配內存所需的時間。
棧(stack)與堆(heap)都是Java用來在Ram中存放數據的地方。
  棧的優勢是,存取速度比堆要快,僅次於直接位於CPU中的寄存器。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性,棧數據可以共享。堆的優勢是可以動態地分配內存大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的數據,但缺點是,由於要在運行時動態分配內存,存取速度較慢。

    int a = 3; //放在棧中
   int b = 3;//棧中已有,直接指向
   a = 4;//棧中沒有,再次創建並指向

  對於基本類型是存放在棧中的,對於a,b在棧中其實是共享內存的,特別註意的是,這種字面值的引用與類對象的引用不同。假定兩個類對象的引用同時指向一個對象,如果一個對象引用變量修改了這個對象的內部狀態,那麽另一個對象引用變量也即刻反映出這個變化。相反,通過字面值的引用來修改其值,不會導致另一個指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與 b的值後,再令a=4;那麽,b不會等於4,還是等於3。在編譯器內部,遇到a=4;時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。
  包裝類數據,如Integer, String, Double等將相應的基本數據類型包裝起來的類。這些類數據全部存在於堆中,Java用new()語句來顯示地告訴編譯器,在運行時才根據需要動態創建,因此比較靈活,但缺點是要占用更多的時間。
每個JVM的線程都有自己的私有的棧空間,隨線程創建而創建,java的stack存放的是frames ,java的stack和c的不同,只是存放本地變量,返回值和調用方法,不允許直接push和pop frames ,因為frames 可能是有heap分配的,所以java的stack分配的內存不需要是連續的。java的heap是所有線程共享的,堆存放所有 runtime data ,裏面是所有的對象實例和數組,heap是JVM啟動時創建。

    String str1 = "abc";//放在棧中
  String str2 = "abc";//棧中已有,直接指向
  System.out.println(str1==str2);   //true

  String str1 = new String("abc");//放入堆中
  String str2 = "abc";                 //放入棧中
  System.out.println(str1==str2);   //false

  只要是用new()來新建對象的,都會在堆中創建,即使與棧中的數據相同,也不會與棧中的數據共享。
當比較包裝類裏面的數值是否相等時,用equals()方法;當測試兩個包裝類的引用是否指向同一個對象時,用==

兩個對象值相同(x.equals(y) == true),但卻可有不同的hashcode,這句話也對,也不對。
如果此對象重寫了equals方法,那麽可能出現這兩個對象的equals相同,而hashcode不同。
如果此對象繼承Object,沒有重寫equals方法,那麽就使用Object的equals方法,Object對象的equals方法默認是用==實現的,那麽如果equals相同,hashcode一定相同。String重寫了equals方法,只要兩個引用所指向的對象是兩塊含有一樣字樣的字符串的話,那麽就返回true。

三、總結

寫了這麽多基礎的知識,有很多都是我們容易混淆的,也是面試的時候喜歡問到的,當然除了這些之外還有編寫代碼的能力,這些代碼一般涉及到了數據庫、設計模式、多線程、文件讀寫、數據結構等知識,需要我們多練習,多思考,多記憶。

沈澱,再出發:Java基礎知識匯總