JAVA學習筆記及知識積累

 爲何說Java具備跨平臺特性?

咱們知道計算機只認識1,0兩種電平的信號,全部信息或者計算指令最終都編碼成16進制的機器碼,這些機器碼做爲程序保存於計算機的內存中,由CPU去單個取指令執行直到程序執行完畢。然而計算機能認識的這些機器碼確實不是人類善於處理的,所以人們發明了彙編語言,隨後使用匯編器(assembler)翻譯成爲機器碼;再隨後貝爾實驗室發明了C語言,這個就是人類可以理解並創造的高級程序了。一樣地,要在CPU上運行,咱們必須翻譯成機器碼,這個由編譯器來完成。咱們來看下面一句程序:javascript

printf(1+2);

 

 

在x86 intel機器上翻譯成機器碼就是 101000101010 ,intel x86處理器運行這個代碼,其中也包含了系統調用的機器碼,在這裏有兩個最關鍵的東西:1.intel處理器,2.操做系統。這二者的組合咱們就稱爲platform.顯然對應不一樣的處理器和不一樣的操做系統會有不一樣的排列組合。對於咱們應用開發者來講,咱們固然但願咱們的應用程序能夠很方便地在不一樣平臺上運行。那咱們來看看,有哪些方案:php

1. 針對不一樣的處理器彙編問題,咱們須要購買host在windows下的針對不一樣target cpu的彙編器負責轉換出可以target到不一樣cpu的機器碼;這個過程叫作交叉編譯。而且不一樣的cpu輸出不一樣的機器碼文件,不能混用css

2. 針對不一樣的操做系統,咱們printf作的系統調用也會有所不一樣html

 

可是咱們要知道的是交叉編譯而且針對不一樣OS特性作不一樣的適配,自己就是很是複雜昂貴的,不是每一個高級語言開發工程師都能勝任的。這就有了java出現的機會,咱們來看看java平臺是如何解決這個問題的。前端

java平臺中有一個很是重要的模塊: Java Virtual Machine,全部預編譯過的bytecode就在這個虛擬機上運行。詳細過程以下:java

 

1. printf(1+2)這個代碼用java就是System.out.println(1+2),該文本保存爲.java文件;python

2.使用java編譯器將這個.java文件轉換成稱爲bytecode的中間代碼,輸出爲.class文件;mysql

3.這個.class內容自己並不和任何特定平臺相關,也就是說任何平臺自己是沒法直接運行的;linux

4.這個虛擬機駐留在操做系統的內存中,當虛擬機被喂入這些bytecode時,jvm會識別到咱們正在工做的具體平臺而且將bytecode最終轉換爲native machine codeandroid

這樣你的代碼只要編譯一次,就能在全部平臺上運行!!

所以, java既是一個編程語言,更是一個平臺。

其餘的編程語言,好比C語言,編譯器產生targeted到特定平臺的機器碼,好比wintel,好比linux+intel等,而java compiler只會將源程序編譯target到Java Virtual Machine. Bytecode是host system和java source的橋樑

https://www.guru99.com/java-virtual-machine-jvm.html

 

Maven是什麼以及Maven,IDE,Mark,Ant對比

Maven是一個java的構建工具,相似於C語言的make,同時Maven也是一個依賴管理的工具。

In short, Archetype is a Maven project templating toolkit. An archetype is defined as an original pattern or model from which all other things of the same kind are made. The name fits as we are trying to provide a system that provides a consistent means of generating Maven projects. Archetype will help authors create Maven project templates for users, and provides users with the means to generate parameterized versions of those project templates.

Maven archetype

maven提供了不少工程模版,當建立一個新項目時,就可使用這些模版,自動建立配置好對應的環境

IDE對比:

Eclipse, IntelliJ Idea, myEclips等,我比較喜歡Idea,特別地,java for android新的正式工具也是基於idea設計的。寫代碼超級爽.使用Idea能夠開啓一個j2ee hello world程序來學習

JAVA SE/Java EE/ Java ME/JavaFX/Java Card/Java TV/Java DB

java主要分爲3大平臺:

java SE (J2SE)= standard edition:這是核心的java編程平臺,包含了java.lang,java.io,java.math,java.net,java.util等通用的庫和API。主要用於桌面應用開發

java ee (J2EE)= enterprise edition: 在SE基礎上,增長了用於部署高容錯,分佈式,多層級的java軟件的庫,這些基本上都以模塊化的組件模式運行在application server上。也就是說,若是你的應用會造成巨大規模,分佈式的系統,那麼你應該考慮JAVA EE。它還提供包括數據庫訪問(JDBC,JPA),遠程函數調用RMI,消息(JMI),web services, XML解析,而且定義了企業級的JavaBeans, servlets, portlets, Java Server Pages等標準API。主要用於web(網絡)應用開發

java me(J2ME) = mico edition.用於開發mobile device上的應用,嵌入於相似機頂盒的設備中。主要用於手機應用

jdk變遷歷史

JAVA程序的編譯和運行過程

JAVA運行環境(JRE)

JRE = Java Runtime Environment = JVM + API(Lib)

JRE運行程序時的三項主要功能:由class loader來加載代碼,由bytecode verifier來校驗代碼,由runtime interpreter來執行代碼

一句話:由虛擬機來裝載編譯好的應用程序而且調用相應的指令具體地執行。虛擬機能夠理解爲在實際的wintel, linux/intel平臺上虛擬出一個新的機器,有他本身的指令系統,操做系統API接口,對下會匹配到不一樣的平臺,對上展現的接口是相同的,所以具備跨平臺的特徵

JAVA開發工具包(JDK)

JDK = JRE+ Tools = JVM + API + Tools 

JDK提供如下主要的開發工具:

  • java編譯器: javac.exe
  • java執行器: java.exe
  • 文檔生成器: javadoc.exe
  • java打包器: jar.exe
  • java調試器:jdb.exe
  • javaw:運行圖形界面程序,而且不啓控制檯
  • javap:查看類信息及反彙編

javap反彙編後造成的jvm字節碼指令和源程序的對應關係:

public class Main {

    public static void main(String[] args) {
        System.out.println("hello, world");
    }
}

J:\eclipse-workspace\TType>javap -c out\production\TType\Main.class
Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String hello, world
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

 

面向對象設計的要點:

  • 將客觀世界中的各類對象映射爲程序中的一個對象
  • 程序的分析和設計都圍繞着:
    • 分析有哪些對象類
    • 每一個類都有哪些屬性,哪些方法
    • 類之間的關係:繼承關係和關聯關係(好比人有一個手錶,老師屬於一個學校,屬於一個院系)
    • 對象之間互相調用

JAVA Application .VS. Applet

二者的運行環境不一樣,application是獨立的程序,須要執行器(調用虛擬機)來運行;而applet則是嵌在HTML頁面中的非獨立程序,由專門的appletViewer來運行,或者由web瀏覽器調用JAVA虛擬機來運行.applet是java最先提出的,是對網頁web技術發展的重大改進,今後網頁變得豐富,可交互了。要在網頁中運行applet必須在系統中有JRE安裝,而且要在瀏覽器中使能java,咱們須要將.class以及.html文件放到www服務器上,而後用瀏覽器訪問。從java8開始, applet的運行就收到更加嚴格的限制。

applet替代方案有flash, silverlight等。甚至如今隨着javascript富體驗方案以及HTML5提供的豐富功能引入,applet已經慢慢退出歷史舞臺.

.jar包

.jar是一系列java的類字節文件打包生成的壓縮文件,jar包伴隨一個很是重要的是清單文件(mainifest),指出這個jar包的入口類是哪個

要使用jar包通常通過:編譯->打包->運行三個階段

javac A.java
jar cvfm A.jar manifest.mf A.class
java -jar A.jar

 輸入與輸出

application輸入輸出能夠是文本界面,也能夠圖形界面,而applet則只能是圖形界面

文本界面的輸入輸出: java.util.Scanner類

圖形界面輸入輸出:初始化一個frame,在這個frame中add一些控件,控件中添加事件處理

Java數據類型劃分

基本數據類型:byte,short,int,long,float,double,char,boolean存在棧裏面

引用數據類型:class,interface,數組:數據自己存在堆裏面,可是指針存在棧裏面

內存區間之常量池StringBuffer

看下面的代碼, 因爲常量是存在方法區中的常量池中,值相等的常量就是同一個常量,而字符串"aaa"本質上就是一個「常量」.可是若是經過new String方式建立的字符串則存在於系統堆中,局部變量僅僅是指向了堆中分配的內存而已。因爲字符串本質上是一個常量,而咱們常常須要作字符串拼接賦值,每一次這類操做都會產生一個字符串副本,效率低下。爲解決這個問題,須要使用StringBuffer,也就是能夠變動的string。

public static void main(String[] args) {
        String s1= "aaa";
        String s2="aaa";
        System.out.println(s1==s2); // true
        String s3 = new String("aaa");
        String s4 = new String("aaa");
        System.out.println(s3==s4); // false
        System.out.println(s3.equals(s4)); // true
        System.out.println(s3==s2);// false

        String s5 = "aaa";
        String s6 = s5;
        s6 = s6 + "bbb";
        // 字符串是不可變的,每次修改本質上都是建立了一個副本
        System.out.println(s5==s6); // false
        StringBuffer s7 = new StringBuffer("aaa");
        StringBuffer s8 = s7;
        s7.append("bbb");
        System.out.println(s7==s8); // true
    }

package

package實際上爲了解決名字空間,名字衝突,相似php的命名空間,須要和對應存儲路徑相對應

 

package pkg1[.pkg2]

 

根目錄由classpath環境變量來肯定,若是沒有package語句,則是default package.

java jdk實際上提供了不少包,好比: java.applet,java.awt,java.awt.image,java.net,java.util等

import語句

爲了使用java中提供的類,須要用import語句來導入所須要的類。

import java.util.Date

導入類後就能夠直接使用Date而不用加package的前綴了。

package和物理目錄之間的關係

http://www.cnblogs.com/moveofgod/p/3809653.html

package和jar包

第三方的Package通常都以jar包形式來發布。咱們知道jar包其實是包含了一堆類字節碼的壓縮包。咱們要在項目中使用,首先得引入jar包,並將對應jar包加到對應的build path,其本質是classpath加入jar包,這樣在java代碼中import 第三方jar包中的類時,jvm就能找到對應的類字節碼並加載運行。

https://blog.csdn.net/zhenyusoso/article/details/6174834

 

編譯和運行包中的類

javac -d . pk\*.java
java pk.TestPkg  /*pk是package, TestPkg是包含main的class*/

java訪問權限控制修飾符: public/protected/private/默認

須要注意的是,默認若是沒有任何修飾符,則成員在同一個包中能夠訪問.首先要看是否類爲public,也就是說是否能夠在其餘package中可以訪問該類,只有有權訪問類,再談可否訪問該類的方法。

public class PubClass{
defaultFunction(){} // 默承認以被包內訪問
privateFunction(){} // 只能在本類中訪問
protectedFunction(){} // 在子類中也可以訪問
publicFunction(){} // 任何地方都可以訪問
}

private成員的setter/getter(setAttribute/getAttribute)

對於私有的成員,咱們通常經過提供setter/getter函數提供讀和/或寫,好處是可以作合法檢查,作量剛的變換等。。若是不提供setAttribute方法則該屬性就是隻讀的

static/final/abstract修飾符

很是常見的,好比System.in和System.out其中in和out就是在System這個類中定義的static變量,所以任什麼時候候均可以訪問。

static如修飾方法,則該方法屬於類,不被任何類所專有,在調用該static方法時,無須事先實例化一個對象

一樣,若是沒有static關鍵字則方法會屬於特定的對象。因爲static方法屬於類,而不屬於對象,所以static方法不能操做屬於類實例的成員變量!static方法不能使用this或super

final類表示不可被繼承,final方法表示不可被子類覆蓋overwrite的方法,final字段表示一旦初始化就不可改變!

static final修飾某個字段時,該字段爲常量,好比Math.PI, integer.MAX_VALUE都是static final類型的成員變量

abstract方法必須在子類中實現, abstract類不能被初始化

接口(interface)

接口就是某種特殊的約定,接口能夠被多個類來實現,軟件工程趨勢於:面向接口的編程,而不是面向實現。

經過接口能夠實現不相關的類的相同的行爲,而無需考慮這些類之間的層次關係。某種意義上實現了多重繼承

接口和類的繼承層次無關,同一個接口能夠被不一樣的類來實現。

好比上面這個圖中: Flyable這個接口定義了takeoff,fly,land三個接口方法,該接口被Airplane, Bird, Superman三個類來implement了,可是這三個類分別繼承於Vehicle, Animal這兩個抽象類(abstract class)

JAVA 8中實現了接口函數的默認實現,這樣有點像似繼承了,不用每一個申明implements這個接口的類中都要實現每個函數。

類成員字段變量和局部變量

字段變量爲對象的一部分,所以存在於對象中,也就是堆中;

局部變量爲成員函數內聲明的變量,存在於棧中

生命週期不一樣:字段變量隨對象建立後一直存在直到對象銷燬,而局部變量只有在函數被調用時存在,調用結束則釋放內存;

字段變量自動賦初值爲0, 局部變量則不會自動初始化,必須顯式地初始化。

函數調用時變量的傳遞(值傳遞和引用傳遞)

總的來講,調用對象方法時,java是值傳遞,即:將表達式的值複製給形式參數。對於引用型變量,傳遞的值是引用值,不會複製對象實體自己

多態(polymorphism)

多態是指一個程序中相同的名字表示不一樣的含義。java的多態有兩種情形:

  • 編譯時多態:重載(overload)是多個同名可是不一樣簽名(參數不一樣)的不一樣方法,如:p.sayHello(),p.sayHello("zhang");
  • 運行時多態
    • 覆蓋override:子類對父類方法進行覆蓋,經過動態綁定(dynamic binding),也稱之爲虛方法調用(virtual method invoking),由於程序調用的是虛的,只有在運行時系統根據調用該方法的實例的類型來決定調用哪一個方法
    • 在調用方法時,程序會正確地調用子類對象的方法
public class Main {
    static void  callDraw(Shape s){
        s.draw();
    }
    public static void main(String[] args) {
        Circle c = new Circle();
        Triangle t = new Triangle();
        Line l = new Line();
        callDraw(c);
        callDraw(t);
        callDraw(l);
    }
}
class Shape{
    void draw(){        System.out.println("shape drawing");}
}
class Circle extends Shape{
    void draw(){        System.out.println("Circle drawing");}
}
class Triangle extends  Shape{
    void draw(){       System.out.println("triangle drawing");}
}
class Line extends Shape{
    void draw(){       System.out.println("line drawing");}
}

上面這個例子中到底調用的是哪一個draw則在運行時決定。

虛方法調用和非虛調用

java中,普通的方法就是虛方法,可是如下幾種情形不是虛方法調用:

static/private/final

請注意下面的例子中,因爲Shape中的draw爲static也就是說屬於類的,就不會觸發虛方法調用,而輸出3個相同的shape drawing。這時的調用依賴於申明的類,這裏就是Shape類,和傳入的是circle,triangle等無關了

public class Main {

    static void  callDraw(Shape s){
        s.draw();
    }
    public static void main(String[] args) {
        Circle c = new Circle();
        Triangle t = new Triangle();
        Line l = new Line();
        callDraw(c);
        callDraw(t);
        callDraw(l);
    }
}
class Shape{
    static void draw(){ System.out.println("shape drawing");}
}
class Circle extends Shape{
    static void draw(){System.out.println("Circle drawing");}
}
class Triangle extends  Shape{
    static void draw(){System.out.println("triangle drawing");}
}
class Line extends Shape{
    static void draw(){System.out.println("line drawing");}
}
// shape drawing
// shape drawing
// shape drawing

構造函數的層級調用

在建立一個對象時,若是類中沒有構造函數,則系統會自動調用super,這時必定要注意父類中的構造函數必須是無參數的函數,不然就會出錯。java編譯器的原則是必須令全部父類的構造方法都能獲得調用

所以,若是不顯式地調用super,則必須保證其父類中的構造函數爲無參數,不然編譯出錯 

實例初始化與靜態初始化

public class Main {
    public static void main(String[] args) {
        InitialTest2 init2 = new InitialTest2(2);
    }
}
class InitialTest{
    static int x=0;
    static {
        x++;
        System.out.println("static..."+x);
    }
}
class InitialTest2 extends  InitialTest{
    InitialTest2(int a){
        this.a = a;
        System.out.println("consturction2 : this.a="+a);
    }
    int a;
    {
        System.out.println("IntialTest2 before instance created..."+this.a);
    }
    static {
        x++;
        System.out.println("static2 init..."+x);
    }
}
/* 輸出結果:
static...1
static2 init...2
IntialTest2 before instance created...0
consturction2 : this.a=2
*

因爲經過super調用在construct中可能會在調用虛方法時繞回到子類中訪問未初始化的數據,所以儘可能不要在構造函數中調用方法,若是必須調用的話就調用final方法

對象清除(garbage collection)

System.gc()調用僅僅建議啓動系統的垃圾回收,可是並不能真正作到垃圾的回收。

也能夠在子類的finalize()重載實現中去釋放資源,相似c++的析構函數。

對於實現了java.lang.AutoCloseable的對象,咱們可使用try範式在代碼執行完畢後自動關閉資源:

 

        try(Scanner scanner = new Scanner(...)) {
            ...
        }

 

 

類的類、匿名類

匿名類沒有類名,在定義類的同時就生成該對象的一個實例,一次性使用

lambda表達式

至關於匿名函數

(參數)->結果

的形式,相似於javascript的匿名函數

@override是幹嗎的

@override是java的僞代碼,表示在這裏要重寫下面的方法,固然也能夠沒有。寫了這個僞代碼的好處:

一、能夠當註釋用,方便閱讀;
二、編譯器能夠給你驗證@Override下面的方法名是不是你父類中全部的,若是沒有則報錯。例如,你若是沒寫@Override,而你下面的方法名又寫錯了,這時你的編譯器是能夠編譯經過的,由於編譯器覺得這個方法是你的子類中本身增長的方法。

注意重載和重寫的區別,重載是方法的參數個數或者參數類型不一樣,致使是不一樣的方法。而重寫是子類對父類相同方法的覆蓋重寫

POJO(Plain Old Java Object)

POJO = Plain Old Java Object字面意思是普通java對象。其內在含義爲沒有繼承任何類的普通類實例對象

JavaBean

一個pojo類(plain old java object)對象中,若是其字段都有對應的getter和setter,而且有一個無參的構造函數,這類對象咱們稱之爲JavaBean,JavaBean每每由容器來建立,好比tomcat建立javabean,所以須要保證有一個無參構造函數。更多用於數據的臨時中轉

war文件

war文件是一個適用於tomcat webapp目錄下部署的web項目包文件。一般使用一下命令打包和查看,一般包含一堆的jar包文件

jar -cvf blog.war * // 打包
jar -tf blog.war //查看

範型Point<T>

有的時候,具體使用什麼class的參數,只有在使用時才能肯定,那麼比較好的方案就是使用範型。好比要設計一個Point類,其成員變量可能可使用整形,也可使用浮點數,那麼就可使用:

 

public class Main {

    public static void main(String[] args) {
        Point<String> p1 = new Point<String>(); // 在調用處指定對應類型
        p1.x = "20";
        p1.y = "24";
        System.out.println(p1.x);
    }
}
class Point<T>{
    T x;
    T y;
}

JVM exception處理

java程序運行時出錯的話要麼本身try{}catch主動處理,要麼經過throws調用交由jvm自行處理。java程序也能夠主動拋出異常,層層向上。

throw vs throws

throw在方法體內,由java本身主動拋出異常,而throws則在方法後面緊跟本方法可能拋出的異常,而在別人調用這個異常時,就必須實現catch相應的異常,或者再次主動拋出異常。

反射

類加載器

類加載器負責將.class字節碼文件加載到內存中,併爲之生成對應的class對象。以便後續使用。

  • 類加載器分如下幾類:根類加載器,也稱爲引導類加載器,負責java核心類的加載,好比system, string等,在JRE的lib目錄下rt.jar文件中;
  • 擴展類加載器,負責JRE擴展目錄中jar包的加載,在jre lib目錄下的ext目錄
  • 系統類加載器,負責在JVM啓動時加載來自java命令的class文件以及在classpath環境變量中所指定的jar包和類路徑

什麼是反射

java反射機制是在運行狀態中,對於任何一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取對象的信息以及動態調用對象方法的功能稱爲java語言的反射機制。

要使用反射,就必須得到字節碼文件

Class.forName/obj.getClass獲取字節碼

public class Main {

    public static void main(String[] args) throws ClassNotFoundException {
        Class pclass1 = Class.forName("Point");
        Class pclass2 = Point.class;
        Point pobj = new Point();
        Class pclass3 = pobj.getClass();
        System.out.println(pclass1==pclass2); // true
        System.out.println(pclass2 == pclass3); // true
    }
}

以上說明幾種方式獲取class字節碼都是相同的拷貝,其中若是使用idea則隨時可能要使用alt+enter快捷鍵增長一個local變量來引用返回值,及快捷增長exception處理。

 使用反射暴力修改private成員

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        Class pClass = Class.forName("Point");
        Point pObj = (Point)pClass.newInstance();
        Field privateVarField = pClass.getDeclaredField("privateVar");
        privateVarField.setAccessible(true);
        privateVarField.set(pObj,205);
        System.out.println(pObj.getPrivateVar()); // 私有變量已被修改成205 
    }
}

使用反射暴力修改private方法訪問權限

class Point{
    private int privateVar = 1;
    int x;
    int y = 2;

    private int privateGetX(){
        return  x;
    }
    public int setX(int a){
        x = a;
        return 0;
    }
    public int publicGetY() {
        return y;
    }
}
public class Main {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        Class pClass = Class.forName("Point");
        Point pObj = (Point)pClass.newInstance();
        pObj.setX(5);
        Method publicGetY = pClass.getMethod("publicGetY");
        System.out.println(publicGetY.invoke(pObj)); // 2
        Method privateGetX = pClass.getDeclaredMethod("privateGetX");
        // 暴力破解private Method,使得能夠經過反射來調用
        privateGetX.setAccessible(true);
        System.out.println(privateGetX.invoke(pObj)); // 5
    }
}

JAVA內部類

在java中,一個類內部又能夠定義內部類,內部類有如下幾種存在形式

1.成員內部類

class OutClass{
    private int num = 3;
    class Inner { // 成員內部類
        int num = 4;
        void show(){
            int num = 5;
            System.out.println("num" + num); // num:5
            System.out.println("num" + this.num); // num:4 本內部類的成員
            System.out.println("num" + OutClass.this.num); // num:3 外部類的成員訪問
        }
    }
    public static void main(String[] args){
        OutClass.Inner inner = new OutClass().new Inner(); // 因爲有內部成員類,所以有了new方法,須先new一個外部類實例,再new內部類
        inner.show();
    }
}

2.靜態內部類

class OutClass{
    private static int num = 3;
    static class Inner { // 成員內部類
        int num = 4;
        void show(){
            int num = 5;
            System.out.println("num" + num); // num:5
            System.out.println("num" + this.num); // num:4 本內部類的成員
            System.out.println("num" + OutClass.num); // num:3只能訪問外部類靜態成員
        }
        static void showstatic(){
            int num = 5;
            System.out.println("num" + num); // num:5
            System.out.println("num" + OutClass.num); // num:3 外部類的成員訪問
        }
    }
    public static void main(String[] args){
        OutClass.Inner inner = new OutClass.Inner();
        inner.show();
        OutClass.Inner.showstatic();
    }
}

 

3.匿名內部類

匿名內部類每每用於從接口定義一個類,僅僅一次使用,沒有必要給他一個命名的情形

4.局部內部類

Tomcat體系結構

tomcat做爲server run time environment,以web容器的方式提供服務,包括connector(http,https,ajp及其餘請求方式)的接入引擎,服務引擎,Host主機服務及host下面的context project等部分組成。

JAVAWeb分層結構

web層負責http請求的接收和響應;web層適用於MVC設計模式,controller實際上就是servlet,view則是JSP,model對於C操做,由input參數建立對應的model並經由service調用DAO持久化,對於R操做,則反過來由DAO層獲取到數據呈現到response中.

service層負責核心的業務邏輯;

Dao層則惟一負責和數據庫CRUD操做並以model方式返回數據

J2EE web項目運行包體系

JAVA多線程

java線程在調用start方法後將進入就緒狀態隊列,該隊列爲一個先入先出的FIFO隊列,CPU會根據必定的調度算法從該隊列中取出一個線程分配時間片進入運行狀態。

在運行過程當中,若是時間片到時則會被搶佔進入就緒態,等待下一次調度;若是運行中須要等待某一資源,則阻塞本身進入等待態。線程運行完畢則銷燬態。

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("當前線程名稱爲:"+ Thread.currentThread().getName());
    }
}
public class ThreadDemo{
    public static void main(String[] args){
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        myThread1.start(); // 分別打印   當前線程名稱爲:Thread-0,注意順序多是隨機的哦
        myThread2.start();  // 分別打印   當前線程名稱爲:Thread-1
    }
}

  

tomcat http請求處理及響應

Servlet

servlet是運行在服務端的java程序段,遵循sun公司提供的一套規範接口。該接口中最重要的是service方法,還有init,destroy等接口。主要用來負責處理客戶端的請求並響應給瀏覽器以動態資源。servlet的實質就是java代碼,經過java提供的API來動態向客戶端輸出內容。

須要注意的是,在java web以及junit開發中,咱們不須要再寫main函數,由於該main函數在javaweb開發時是由tomcat的bootstrap類來提供的,是一個無限循環,永遠不會撤銷。而在junit中則在junit的框架代碼中。咱們的servlet程序由tomcat的main函數在接收到http請求時經過反射機制來具體調用servlet的字節代碼,並最終返回響應。servlet是鏈接web前端和後端邏輯的橋樑。servlet是singleton,所以在servlet中不能保存用戶相關的數據(至關因而全局互斥數據,會致使線程衝突),不然會致使混亂,注意線程安全

servlet的建立和映射:

能夠經過手工在web.xml中定義,或者經過註解@WebServlet("/myservnet")的方式來指示編譯器完成映射。

單實例,多線程servlet調用模型

 

servlet配置過程,相似於PHP Laravel的路由配置過程,主要要指定對應的url-pattern,以及對應的servlet類。配置時也存在優先級及覆蓋的問題。咱們能夠在站點級全局web.xml中配置公共路由,也能夠在項目級別建立web.xml實現項目級別的路由。

tomcat中靜態資源加載過程

當path後面寫的是靜態資源名稱,好比index.html,tomcat也會去找url-pattern有沒有能夠匹配的內容,若是有,就加載對應servnet,若是沒有就找到配置中的缺省url-pattern.

若是當前project沒有缺省url-pattern,則找到站點級別的web.xml的默認匹配的url-pattern,通常在default servlet name項中

<servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

JSP的本質

JSP自己實質上是一段未來被編譯爲字節碼的java程序,也是一個servlet,相似於PHP的模版引擎(xxx.blade.php),最終編譯出來的字節碼(php native源碼)完成的工做實際上就是拼接java數據到對應前端html中.

 

servlet的forward和redirect

當tomcat收到一個http請求時,路由到servlet,對應的servlet根據業務邏輯可能須要forward到其餘servlet(這是內部轉移)或者直接返回一個重定向讓瀏覽器作redirect操做,最終才能完成業務。

若是須要servlet共享數據給jsp,則須要使用forward轉發,轉發只能轉到內部的資源。

每每經過request對象setAttribute增長一個數據,而後forward給jsp來顯示數據

request.setAttribute('productList',proList);
RequestDispatcher requestDispatcher = request.getRequestDispatcher('/product/query.jsp');
requestDispatcher.forward(request,response);

JSTL/EL/OGNL(Struts2)

JSTL/EL是用於簡化jsp編寫而定義的java規範,JSTL(tld)定義了一些描述性的標籤,EL則定義了一種以${ java代碼 }的方式便於在jsp中執行java代碼獲取數據,而且使用相似php的blade模版來表達展現數據

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
  <head>
    <title>查詢商品</title>
  </head>
  <body>
  <c:forEach items="${requestScope.prodList}" var="prod">
    <tr>
      <td>${prod.id}</td>
      <td>${prod.name}</td>
      <td>${prod.price}</td>
    </tr>
  </c:forEach>
  </body>
</html>

須要注意的是jstl標籤裏面訪問的都是pojo的get方法,由於相似於name, price等字段都是私有的,因此不可能經過obj.propery來訪問到,只能經過getXXX的方式來獲取,這也是爲何咱們須要JavaBean的緣由。咱們儘可能不要在jsp中使用<%= pageContext.request.contextPath %>,這樣的方式來寫java代碼,而儘量要使用EL表達式方式

struts2值域valueStack

雖然在上面的演示中,咱們經過request,session,application等域對象能夠在頁面處理過程當中交換數據,可是這類方法更多限定於在jsp頁面中訪問相關數據,對於若是想在action中訪問相關數據,則可使用struts2框架的值域。action一旦建立,就會生成一個valueStack,他就是一個存放數據的容器。struts2中會將全部的域對象(request,response,application,session)也都存放在了valueStack中,所以最好的方式,我們都統一稱爲valueStack方式來處理數據。

 

jspf文件簡化前端資源引用

在web頁面中,有一些css,js等前端資源的引用其實是公共的,幾乎全部的頁面都須要。而且有的時候咱們也須要在全部jsp文件中均可能須要引用相似工程基地址的變量,這時一個比較好的辦法就是使用相似php的partial.blade.php文件,將這些東西抽取出來,在全部jsp文件中經過@include來引用。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="projectbaseuri" value ="${pageContext.request.contextPath}"/>

 

 

JVM內存分佈

所謂本地方法區是指非Java語言編寫的C或者C++程序須要的棧,而程序計數器則屬於線程專有,保存着每一個線程運行時場景的堆棧,PC計數器等,能夠用於線程的切換

數據庫JDBC

jdbc是java定義的一套java訪問數據庫的接口,數據庫的vendor能夠根據該接口規範來實現數據庫訪問驅動,好比mysql的驅動爲Mysql-JDBC-impl.jar,Oracle-JDBC-impl.jar, SQL servier-JDBC-impl.jar. 

java程序遵循JDBC規範經過對應的驅動來對實際數據庫的訪問。

DAO組件

經過上面的JDBC接口,雖然JAVA程序能夠直接訪問到數據庫,可是每次數據庫的訪問仍是比較複雜的過程,好比創建鏈接,構建SQL,執行SQL,關閉sql statement,關閉jdbc鏈接。爲了責任單一,通常須要抽象出來一層DAO組件,上層程序調用該組件的方法實現數據庫操做。

數據庫鏈接池

如上面所描述,每次數據庫的操做都須要創建數據庫的鏈接,數據庫操做完畢後將鏈接關閉,而socket創建和關閉是很消耗資源而且緩慢的過程,咱們有必要事先建立好這些connection,而數據庫訪問時,臨時從這些connection中取出一個,數據操做完畢後並不真正釋放鏈接,而是將鏈接對象返回到鏈接池,供後續應用使用。

過濾器filter

相似於PHP laravel的middleware,咱們可使用filter來對某些servlet進行保護和受權。

 

 

監聽器listener

咱們能夠監聽servletContext, HttpSession, ServletRequest對象的建立屬性更改等事件。

須要注意的是針對監聽的對象不一樣,監聽器的做用範圍也是不一樣的,好比針對監聽servletContext,則是全局性質的,監聽Session的,則只針對單個訪問過程週期有效(只要瀏覽器沒有關閉,session就存在),而監聽ServletRequest的,則只針對單次請求有效

java web開發xml中三大組件

servlet < filter < listener優先級排序

因爲listener優先級最高,最早執行,所以每每把整個項目的初始化數據加載工做放在這裏執行

https://blog.csdn.net/sunxianghuang/article/details/52107376

https://blog.csdn.net/xiaojie119120/article/details/73274759

java web中四大做用域及數據對象request/response(PageContext),ServletRequest(整個請求鏈有效,包括forward和redirect),HttpSession,application(ServletContext)

application:tomcat全局惟一

session:單用戶惟一

request/response:單個pv惟一

JavaWeb的四大做用域爲:PageContext,ServletRequest,HttpSession,ServletContext;

PageContext域:做用範圍是整個JSP頁面,是四大做用域中最小的一個;生命週期是當對JSP的請求時開始,當響應結束時銷燬。

ServletRequest域:做用範圍是整個請求鏈(請求轉發也存在);生命週期是在service方法調用前由服務器建立,傳入service方法。整個請求結束,request生命結束. 

HttpSession域:做用範圍是一次會話。生命週期是在第一次調用request.getSession()方法時,服務器會檢查是否已經有對應的session,若是沒有就在內存中建立一個session並返回。當一段時間內session沒有被使用(默認爲30分鐘),則服務器會銷燬該session。若是服務器非正常關閉(強行關閉),沒有到期的session也會跟着銷燬。若是調用session提供的invalidate() ,能夠當即銷燬session。

注意:服務器正常關閉,再啓動,Session對象會進行鈍化和活化操做。同時若是服務器鈍化的時間在session 默認銷燬時間以內,則活化後session仍是存在的。不然Session不存在。  若是JavaBean 數據在session鈍化時,沒有實現Serializable 則當Session活化時,會消失。

ServletContext域:做用範圍是整個Web應用。當Web應用被加載進容器時建立表明整個web應用的ServletContext對象,當服務器關閉或Web應用被移除時,ServletContext對象跟着銷燬。 

做用域從小到大爲:PageContext(jsp頁面),ServletRequest(一次請求),HttpSession(一次會話),ServletContext(整個web應用)

JAVA ObjectOutputStream(序列化和反序列化)實現Serializable接口

相似於python,c, java中也存在對對象持久化的需求.比較典型的例子是tomcat在關閉前會將session內存數據序列化存放到硬盤,而從新啓動tomcat則反序列化讀取恢復到內存。

Tomcat調試中的詳細log使能

在tomcat的conf/loggings.properties文件或者該應用的WEB-INF/classes目錄中新建一個loggings.properties文件,再加上如下兩句:

org.apache.catalina.core.ContainerBase.[Catalina].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].handlers = java.util.logging.ConsoleHandler

https://blog.csdn.net/Q_AN1314/article/details/52832460

微服務/SOA

https://blog.csdn.net/zhengzhaoyang122/article/details/80142955

面向服務架構,和傳統的單機單進程搞定一切業務需求不同,他更強調模塊化,層次化,更加容錯,系統容易維護,可是也會帶來沒必要要的複雜性。模塊之間經過RPC或者REST API調用來通訊

JRebel實現j2ee熱加載開發

在正常的開發過程當中,咱們寫代碼,build,從新部署,使用瀏覽器檢查結果。每每build和從新部署是很是耗時也是頻繁發生的,JRebel就是解決這個痛點的,相似於Nodejs、webpack中的HRM模塊,在編寫前端組件代碼時,無需刷新瀏覽器,代碼直接編譯並灌入瀏覽器,這樣的開發體驗是很是高效完美的。

https://zeroturnaround.com/software/jrebel/pricing/

Struts2

struts實際上就是web層的MVC框架,經過一個前端過濾控制器,截取全部的request,分發到對應的action,在action中能夠經過result結果頁返回對應的web頁面(result實際上就是至關於laravel中的view)

Spring

spring是一個開放源碼的設計層面框架,他將面向接口編程思想貫穿始終,是一個分層的JavaSE/JavaEE full-stack一站式輕量級開源框架,他主要爲了解決業務邏輯層和其餘各層的鬆耦合關係。這個更加相似於laravel

IOC模式下的Bean配置

經過工廠實現接口與實現的分離。當需求變化時,好比一個mysql須要變動爲oracle的數據庫系統,則只須要配置bean對應的class類名,因爲對象建立都是由spring提供的工廠來提供的,而工廠根據新的配置就能經過反射機制建立新的類對象了。

IOC本質上就是控制反轉,由spring來給咱們建立類實例,而對應的類由咱們在xml中配置指定,方便解耦。

1. xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 這裏bean id就是你要實例化類的alias,而其實現則由class來決定,屆時由IOC自動調用這裏定義的實現類 -->
    <bean id="userDao" class="cn.kidsit.project1.UserDaoOracleImpl">
<property name="userName" value="zzh"></property>

</
bean> </beans>

2. 接口類及實現類:

package cn.kidsit.project1;

public interface UserDao {
    public void save();

    public void delete();
}

public class UserDapMysqImpl implements UserDao {

    @Override
    public void save() {
        System.out.println("mysql save");
    }

    @Override
    public void delete() {
        System.out.println("mysql delete");
    }
}

public class UserDaoOracleImpl implements UserDao {

public String userName;
public void setUserName(String userName) {
this.userName = userName;
}
@Override public void save() { System.out.println("oracle save"); } @Override public void delete() { System.out.println("oracle delete"); } }

3.單元測試代碼:

package cn.kidsit.project1;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {
    @Test
    public void test(){
//    1.加載配置文件
        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//    2.根據id建立獲取對象
        UserDao userDao = (UserDao) appContext.getBean("userDao");
        userDao.save(); // 這時將建立的是oracle的實現類
        userDao.delete();
UserDaoOracleImpl userDIDao = (UserDaoOracleImpl) appContext.getBean("userDao");
System.out.println(userDIDao.userName); // 這裏就有了初始化的值,因爲依賴注入的功勞
} }

DI依賴注入

將spring管理的類中依賴的屬性賦值時,經過配置文件來指定spring建立對象的過程就是依賴注入

Bean的scope:單例仍是多例(singleton .vs. prototype)

在上面的xml配置代碼中,默認建立的對象都是單例模式,也就是隻建立了一個,之後都是使用相同的對象。可是不少時候咱們必須指定多例模式,好比action對於每次訪問都是不一樣的。

singleton:默認的scope配置,單例模式;

prototype:多例模式

request:應用在web項目中,Spring建立這個類以後,將這個類對象存入到request範圍中;

session:應用在web項目中,Spring建立這個類以後,將這個類對象存入到session範圍內;

globalsession:應用在web項目中,必須在porlet(基於java的web組件)環境。

經過註解方式聲明Bean

@Component("user") // 至關於在applicationContext.xml中配置對應的bean
public class UserDaoOracleImpl implements UserDao {

    public String userName;

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Override
    public void save() {
        System.out.println("oracle save");
    }

    @Override
    public void delete() {
        System.out.println("oracle delete");
    }
}

注意:須要在IDE的compiler配置選項中使能註解

AOP面向切面編程(相似於python的proxy功能)

後面也能夠直接使用AOP自定義的類,並經過配置文件來指定在哪一個切入點添加切面(就是加強函數)。。。

// 定義加強的功能切片類
public class AspectClass {
    public void checkPrevilidge(){
        System.out.println("權限校驗");
    }
    public void log(){
        System.out.println("日誌記錄");
    }
}

 

前置通知,後置通知每每用於日誌的加強功能,咱們來看對應的配置文件

 

2018年IEEE Spectrum language Ranking

相關文章
相關標籤/搜索