Java工程師的工資待遇怎么樣?
Java工程師的工資待遇怎么樣?
Java軟件工程師一般月薪范圍在4000-10000元,遠遠超過了應屆畢業(yè)生月薪 2500元的平均水平。通常來說,有一年工作經驗的Java高級軟件工程師的薪酬大致在年薪10—13萬左右。
從Java的應用領域來分,Java語言的應用方向主要表現(xiàn)在以下三個方面:首 先是大中型的商業(yè)應用;其次是桌面應用,就是常說的C/S應用;再次是移動領域應用。
綜上而言JAVA就業(yè)方向為:可以從事JSP網站開發(fā)、Java編程、Java游戲開 發(fā)、Java桌面程序設計,以及其他與Java語言編程相關的工作。可進入電信、銀行、保險專業(yè)軟件開發(fā)公司等從事軟件設計和開發(fā)工作。
JavaWeb開發(fā)
JavaWeb開發(fā)
-
01HTML5與CSS3
-
1.B/S架構
-
2.HTML基本使用
-
3.HTML DOM
-
4.CSS選擇器
-
5.常用樣式
-
6.盒子模型與布局
-
7.HTML5新特性
-
8.CSS3新特性
-
02JavaScript
-
1.JavaScript基本語法
-
2.JavaScript流程控制
-
3.數(shù)組、函數(shù)、對象的使用
-
4.JavaScript事件綁定/觸發(fā)
-
5.JavaScript事件冒泡
-
6.JavaScript嵌入方式
-
7.JavaScript DOM操作
-
8.DOM API
-
03jQuery
-
1.jQuery快速入門
-
2.jQuery語法詳解
-
3.jQuery核心函數(shù)
-
4.jQuery對象/JavaScript對象
-
5.jQuery選擇器
-
6.jQuery 文檔處理
-
7.jQuery事件
-
8.jQuery動畫效果
-
04AJAX&JSON
-
1.AJAX技術衍生
-
2.XMLHttpRequest使用
-
3.同步請求&異步請求
-
4.JSON語法
-
5.Java JSON轉換
-
6.JavaScript JSON轉換
-
7.jQuery 基本AJAX方法
-
8.底層$.ajax使用
-
05XML
-
1.XML用途
-
2.XML文檔結構
-
3.XML基本語法
-
4.DOM&SAX解析體系
-
5.DOM4j節(jié)點查詢
-
6.DOM4j文檔操作
-
7.xPath語法
-
8.xPath快速查詢
-
06bootstrap
-
1.bootstrap快速使用
-
2.柵格系統(tǒng)
-
3.表單、表格、按鈕、圖片
-
4.下拉菜單
-
5.按鈕組使用
-
6.導航條
-
7.分頁、進度條
-
07Web服務器基礎
-
1.HTTP協(xié)議
-
2.HttpWatch
-
3.Tomcat服務器搭建
-
4.Tomcat目錄結構解析
-
5.Tomcat端口配置
-
6.Tomcat啟動&停止
-
7.Tomcat&Eclipse整合
-
8.Eclipse配置優(yōu)化
-
08Servlet
-
1.Servlet體系
-
2.Servlet生命周期
-
3.ServletConfig&ServletContext
-
4.請求&響應
-
5.重定向&轉發(fā)
-
6.中文亂碼解決方案
-
7.項目路徑問題
-
09JSP
-
1.JSP語法
-
2.JSP原理
-
3.JSP腳本片段&表達式
-
4.JSP聲明&指令
-
5.JSP九大隱含對象
-
6.域對象使用
-
10JSTL
-
1.JSTL簡介
-
2.JSTL-核心標簽庫
-
3.JSTL-函數(shù)標簽庫
-
4.JSTL-fmt標簽庫
-
5.自定義標簽庫使用
-
6.自定義標簽庫原理
-
11EL
-
1.EL表達式簡介
-
2.EL使用
-
3.EL取值原理
-
4.EL的11大隱含對象
-
5.EL2.2與3.0規(guī)范
-
6.EL邏輯運算
-
7.函數(shù)庫深入
-
12Cookie&Session
-
1.Cookie機制
-
2.Cookie創(chuàng)建&使用
-
3.Session原理
-
4.Session失效
-
5.Url重寫
-
6.Session活化&鈍化
-
7.Token令牌應用
-
13Filter&Listener
-
1.Filter原理
-
2.Filter聲明周期
-
3.Filter鏈
-
4.Filter登錄驗證
-
5.Filter事務控制
-
6.Listener原理
-
7.八大監(jiān)聽器使用
-
8.Listener監(jiān)聽在線用戶
-
14國際化
-
1.國際化原理
-
2.ResourceBundle&Locale
-
3.國際化資源文件
-
4.日期/數(shù)字/貨幣國際化
-
5.頁面動態(tài)中英文切換
-
6.頁面點擊鏈接中英文切換
-
7.fmt標簽庫的使用
-
15文件上傳
-
1.文件上傳原理
-
2.commons-io&commons-fileupload
-
3.文件上傳參數(shù)控制
-
4.文件上傳路徑瀏覽器兼容性解決
-
5.文件**原理
-
6.文件**響應頭
-
7.文件**中文亂碼&瀏覽器兼容性
創(chuàng)建者模式之-單例模式
>
應用場景
由于單例模式只生成一個實例, 減少了系統(tǒng)性能開銷(如: 當一個對象的產生需要比較多的資源時, 如讀取配置, 產生其他依賴對象, 則可以**在應用啟動時直接產生一個單例對象, 然后永久駐留內存的方式來解決)
Windows中的任務管理器; 文件系統(tǒng), 一個操作系統(tǒng)只能有一個文件系統(tǒng); 數(shù)據(jù)庫連接池的設計與實現(xiàn); SPRing中, 一個Component就只有一個實例java-Web中, 一個Servlet類只有一個實例;實現(xiàn)要點
聲明為private來隱藏構造器 private static Singleton實例 聲明為public來暴露實例獲取方法單例模式主要追求三個方面性能
線程安全 調用效率高 延遲加載實現(xiàn)方式
主要有五種實現(xiàn)方式,懶漢式(延遲加載,使用時初始化),餓漢式(JVM加載資源時初始化),雙重檢查,靜態(tài)內部類,枚舉。
懶漢式,線程不安全的實現(xiàn)由于沒有同步,多個線程可能同時檢測到實例沒有初始化而分別初始化,從而破壞單例約束。
缺點:線程不安全,產生多個實例
public class Singleton { private static Singleton instance; private Singleton() { }; public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 懶漢式,線程安全但效率低下的實現(xiàn) 優(yōu)點:線程安全,延遲加載 缺點:低效, public class Singleton { private static Singleton instance; private Singleton() { }; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }由于對象只需要在初次初始化時需要同步,多數(shù)情況下不需要互斥的獲得對象,加鎖會造成巨大無意義的資源消耗
雙重檢查 優(yōu)點:線程安全,延遲加載,高效;
這種方法對比于上面的方法確保了只有在初始化的時候需要同步,當初始化完成后,再次調用getInstance不會再進入synchronized塊。
public class Singleton { private static volatile Singleton instance; private Singleton() { }; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }說明: 內部檢查是必要的
由于在同步塊外的if語句中可能有多個線程同時檢測到instance為null同時進入同步塊區(qū)外部(synchronized (Singleton.class)之外),所以在進入同步塊后還需要再判斷是否為null,避免后續(xù)獲得鎖的線程再次對instance進行初始化。
instance聲明為volatile類型是必要的。指示JVM不用優(yōu)化。
指令重排
由于初始化操作 instance=new Singleton()是非原子操作的,主要包含三個過程
1、給instance分配內存 2、調用構造函數(shù)初始化instance 3、將instance指向分配的空間(instance指向分配空間后,instance就不為空了)
雖然synchronized塊保證了只有一個線程進入同步塊,但是在同步塊內部JVM出于優(yōu)化需要可能進行指令重排,例如(1->3->2),instance還沒有初始化之前其他線程就會在外部檢查到instance不為null,而返回還沒有初始化的instance,從而造成邏輯錯誤。
volatile保證變量的可見性
volatile類型變量可以保證寫入對于讀取的可見性,JVM不會將volatile變量上的操作與其他內存操作一起重新排序,volatile變量不會被緩存在寄存器,因此保證了檢測instance狀態(tài)時總是檢測到instance的**新狀態(tài)。
注意:volatile并不保證操作的原子性,例如即使count聲明為volatile類型,count 操作被分解為讀取->寫入兩個操作,雖然讀取到的是count的**新值,但并不能保證讀取與寫入之間不會有其他線程再次寫入,從而造成邏輯錯誤
餓漢式 優(yōu)點:線程安全 缺點:沒有延遲加載 這種方式基于單ClassLoder機制,instance在類加載時進行初始化,避免了同步問題。餓漢式的優(yōu)勢在于實現(xiàn)簡單,劣勢在于不是延遲加載模式(lazy initialization)
在需要實例之前就完成了初始化,在單例較多的情況下,會造成內存占用,加載速度慢問題 由于在調用getInstance()之前就完成了初始化,如果需要給getInstance()函數(shù)傳入?yún)?shù),將會無法實現(xiàn)
public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() { }; public static Singleton getInstance() { return instance; } }私有靜態(tài)內部類 優(yōu)點:延遲加載,線程安全
由于私有內部類不會在類的外部被使用,所以只有在調用getInstance()方法時才會被加載。同時依賴JVM的ClassLoader類加載機制保證了不會出現(xiàn)同步問題。 私有靜態(tài)內部類保證了外部訪問不到,內部類的靜態(tài)屬性,保證了當多線程調用getInstance時候,jvm加載Holder字節(jié)碼文件時候對靜態(tài)成員變量初始化保證線程安全。加載成功后instance實例已經創(chuàng)建,已經不存在線程安全的問題,同時保證了延遲加載(只要不調用getInstance方法就不會實例化Holder 類)。
public class Singleton { private Singleton() { }; public static Singleton getInstance() { return Holder.instance; } private static class Holder{ private static Singleton instance = new Singleton(); } }枚舉方法
參見枚舉類解析
線程安全由于枚舉類的會在編譯期編譯為繼承自java.lang.Enum的類,其構造函數(shù)為私有,不能再創(chuàng)建枚舉對象,枚舉對象的聲明和初始化都是在static塊中,所以由JVM的ClassLoader機制保證了線程的安全性。但是不能實現(xiàn)延遲加載
序列化由于枚舉類型采用了特殊的序列化方法,從而保證了在一個JVM中只能有一個實例。
枚舉類的實例都是static的,且存在于一個數(shù)組中,可以用values()方法獲取該數(shù)組 在序列化時,只輸出代表枚舉類型的名字屬性 name 反序列化時,根據(jù)名字在靜態(tài)的數(shù)組中查找對應的枚舉對象,由于沒有創(chuàng)建新的對象,因而保證了一個JVM中只有一個對象
public enum Singleton { INSTANCE; public String error(){ return "error"; } }單例模式的破壞與防御
反射
對于枚舉類,該破解方法不適用。
import java.lang.reflect.Constructor; public class TestCase { public void testBreak() throws Exception { Class<Singleton> clazz = (Class<Singleton>) Class.forName("Singleton"); Constructor<Singleton> constructor = clazz.getDeclaredConstructor(); constructor.setaccessible(true); Singleton instance1 = constructor.newInstance(); Singleton instance2 = constructor.newInstance(); System.out.println("singleton? " (instance1 == instance2)); } public static void main(String[] args) throws Exception{ new TestCase().testBreak(); } }序列化
對于枚舉類,該破解方法不適用。
該測試首先需要聲明Singleton為實現(xiàn)了可序列化接口
public class Singleton implements Serializable public class TestCase { private static final String SYSTEM_FILE = "save.txt"; public void testBreak() throws Exception { Singleton instance1 = Singleton.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(SYSTEM_FILE)); oos.writeObject(instance1); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(SYSTEM_FILE)); Singleton instance2 = (Singleton) ois.readObject(); System.out.println("singleton? " (instance1 == instance2)); } public static void main(String[] args) throws Exception{ new TestCase().testBreak(); } }ClassLoader
JVM中存在兩種ClassLoader,啟動內裝載器(bootstrap)和用戶自定義裝載器(user-defined class loader),在一個JVM中可能存在多個ClassLoader,每個ClassLoader擁有自己的NameSpace。一個ClassLoader只能擁有一個class對象類型的實例,但是不同的ClassLoader可能擁有相同的class對象實例,這時可能產生致命的問題。
防御
對于序列化與反序列化,我們需要添加一個自定義的反序列化方法,使其不再創(chuàng)建對象而是直接返回已有實例,就可以保證單例模式。
我們再次用下面的類進行測試,就發(fā)現(xiàn)結果為true。
public final class Singleton { private Singleton() { } private static final Singleton INSTANCE = new Singleton(); public static Singleton getInstance() { return INSTANCE; } private Object readResolve() throws ObjectStreamException { // instead of the object we re on, // return the class variable INSTANCE return INSTANCE; } public class TestCase { private static final String SYSTEM_FILE = "save.txt"; public void testBreak() throws Exception { Singleton instance1 = Singleton.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(SYSTEM_FILE)); oos.writeObject(instance1); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(SYSTEM_FILE)); Singleton instance2 = (Singleton) ois.readObject(); System.out.println("singleton? " (instance1 == instance2)); } public static void main(String[] args) throws Exception { new TestCase().testBreak(); } } }單例模式性能總結
方式 | 優(yōu)點 | 缺點 |
---|---|---|
餓漢式 | 線程安全, 調用效率高 | 不能延遲加載 |
懶漢式 | 線程安全, 可以延遲加載 | 調用效率不高 |
雙重檢測鎖式 | 線程安全, 調用效率高, 可以延遲加載 | - |
靜態(tài)內部類式 | 線程安全, 調用效率高, 可以延遲加載 | - |
枚舉單例 | 線程安全, 調用效率高 | 不能延遲加載 |
單例性能測試
測試結果:
HungerSingleton 共耗時: 30 毫秒 LazySingleton 共耗時: 48 毫秒 DoubleCheckSingleton 共耗時: 25 毫秒 StaticInnerSingleton 共耗時: 16 毫秒 EnumSingleton 共耗時: 6 毫秒在不考慮延遲加載的情況下,枚舉類型獲得了**好的效率,懶漢模式由于每次方法都需要獲取鎖,所以效率**低,靜態(tài)內部類與雙重檢查的效果類似。考慮到枚舉可以 有效的避免序列化與反射,所以枚舉是較好實現(xiàn)單例模式的方法。
public class TestCase { private static final String SYSTEM_FILE = "save.txt"; private static final int THREAD_COUNT = 10; private static final int CIRCLE_COUNT = 100000; public void testSingletonPerformance() throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(THREAD_COUNT); FileWriter writer = new FileWriter(new File(SYSTEM_FILE), true); long start = System.currentTimeMillis(); for (int i = 0; i < THREAD_COUNT; i) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < CIRCLE_COUNT; i) { Object instance = Singleton.getInstance(); } latch.countDown(); } }).start(); } latch.await(); long end = System.currentTimeMillis(); writer.append("Singleton 共耗時: " (end - start) " 毫秒\n"); writer.close(); } public static void main(String[] args) throws Exception{ new TestCase().testSingletonPerformance(); } }補充知識
類加載機制
static關鍵字的作用是把類的成員變成類相關,而不是實例相關,static塊會在類首次被用到的時候進行加載,不是對象創(chuàng)建時,所以static塊具有線程安全性
普通初始化塊當Java創(chuàng)建一個對象時, 系統(tǒng)先為對象的所有實例變量分配內存(前提是該類已經被加載過了), 然后開始對這些實例變量進行初始化, 順序是: 先執(zhí)行初始化塊或聲明實例變量時指定的初始值(這兩處執(zhí)行的順序與他們在源代碼中排列順序相同), 再執(zhí)行構造器里指定的初始值.
靜態(tài)初始化塊
又名類初始化塊(普通初始化塊負責對象初始化, 類初始化塊負責對類進行初始化). 靜態(tài)初始化塊是類相關的, 系統(tǒng)將在類初始化階段靜態(tài)初始化, 而不是在創(chuàng)建對象時才執(zhí)行. 因此靜態(tài)初始化塊總是先于普通初始化塊執(zhí)行.
執(zhí)行順序
系統(tǒng)在類初始化以及對象初始化時, 不僅會執(zhí)行本類的初始化塊[static/non-static], 而且還會一直上溯到java.lang.Object類, 先執(zhí)行Object類中的初始化塊[static/non-static], 然后執(zhí)行其父類的, **后是自己.
頂層類(初始化塊, 構造器) -> … -> 父類(初始化塊, 構造器) -> 本類(初始化塊, 構造器)
小結
static{} 靜態(tài)初始化塊會在類加載過程中執(zhí)行;
{} 則只是在對象初始化過程中執(zhí)行, 但先于構造器;
內部類
內部類訪問權限
Java 外部類只有兩種訪問權限:public/default, 而內部類則有四種訪問權限:private/default/protected/public. 而且內部類還可以使用static修飾;內部類可以擁有private訪問權限、protected訪問權限、public訪問權限及包訪問權限。如果成員內部類Inner用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是默認訪問權限,則只能在同一個包下訪問。這一點和外部類有一點不一樣,外部類只能被public和包訪問兩種權限修飾。成員內部類可以看做是外部類的一個成員,所以可以像類的成員一樣擁有多種權限修飾。 內部類分為成員內部類與局部內部類, 相對來說成員內部類用途更廣泛, 局部內部類用的較少(匿名內部類除外), 成員內部類又分為靜態(tài)(static)內部類與非靜態(tài)內部類, 這兩種成員內部類同樣要遵守static與非static的約束(如static內部類不能訪問外部類的非靜態(tài)成員等) 非靜態(tài)內部類
非靜態(tài)內部類在外部類內使用時, 與平時使用的普通類沒有太大區(qū)別; Java不允許在非static內部類中定義static成員,除非是static final的常量類型 如果外部類成員變量, 內部類成員變量與內部類中的方法里面的局部變量有重名, 則可**this, 外部類名.this加以區(qū)分. 非靜態(tài)內部類的成員可以訪問外部類的private成員, 但反之不成立, 內部類的成員不被外部類所感知. 如果外部類需要訪問內部類中的private成員, 必須顯示創(chuàng)建內部類實例, 而且內部類的private權限對外部類也是不起作用的: 靜態(tài)內部類
使用static修飾內部類, 則該內部類隸屬于該外部類本身, 而不屬于外部類的某個對象. 由于static的作用, 靜態(tài)內部類不能訪問外部類的實例成員, 而反之不然; 匿名內部類
如果(方法)局部變量需要被匿名內部類訪問, 那么該局部變量需要使用final修飾.
枚舉
枚舉類繼承了java.lang.Enum, 而不是Object, 因此枚舉不能顯示繼承其他類; 其中Enum實現(xiàn)了Serializable和Comparable接口(implements Comparable, Serializable); 非抽象的枚舉類默認使用final修飾,因此枚舉類不能派生子類; 枚舉類的所有實例必須在枚舉類的**行顯示列出(枚舉類不能**new來創(chuàng)建對象); 并且這些實例默認/且只能是public static final的; 枚舉類的構造器默認/且只能是private; 枚舉類通常應該設計成不可變類, 因此建議成員變量都用private final修飾; 枚舉類不能使用abstract關鍵字將枚舉類聲明成抽象類(因為枚舉類不允許有子類), 但如果枚舉類里面有抽象方法, 或者枚舉類實現(xiàn)了某個接口, 則定義每個枚舉值時必須為抽象方法提供實現(xiàn),
$(function () { $( pre.prettyprint code ).each(function () { var lines = $(this).text().split( \n ).length; var $numbering = $( ).addClass( pre-numbering ).hide(); $(this).addClass( has-numbering ).parent().append($numbering); for (i = 1; i <= lines; i ) { $numbering.append($( ).text(i)); }; $numbering.fadeIn(1700); }); });
相關推薦:
體驗課預約試聽
倒計時
課程熱線:
客服在線時間:早上9點~下午6點,其他時間請在線預約報名或留言,謝謝!