日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Java中難理解的四個概念

瀏覽:162日期:2022-08-13 16:16:35
前言

Java 是很多人一直在用的編程語言,但是有些 Java 概念是非常難以理解的,哪怕是一些多年的老手,對某些 Java 概念也存在一些混淆和困惑。

所以,在這篇文章里,會介紹四個 Java 中最難理解的四個概念,去幫助開發者更清晰的理解這些概念:

匿名內部類的用法 多線程 如何實現同步 序列化匿名內部類

匿名內部類又叫匿名類,它有點像局部類(Local Class)或者內部類(Inner Class),只是匿名內部類沒有名字,我們可以同時聲明并實例化一個匿名內部類。

一個匿名內部類僅適用在想使用一個局部類并且只會使用這個局部類一次的場景。

匿名內部類是沒有需要明確聲明的構造函數的,但是會有一個隱藏的自動聲明的構造函數。

創建匿名內部類有兩種辦法 通過繼承一個類(具體或者抽象都可以)去創建出匿名內部類 通過實現一個接口創建出匿名內部類

咱們看看下面的例子:

// 接口:程序員interface Programmer { void develop();}public class TestAnonymousClass { public static Programmer programmer = new Programmer() {@Overridepublic void develop() { System.out.println('我是在類中實現了接口的匿名內部類');} }; public static void main(String[] args) {Programmer anotherProgrammer = new Programmer() { @Override public void develop() {System.out.println('我是在方法中實現了接口的匿名內部類'); }};TestAnonymousClass.programmer.develop();anotherProgrammer.develop(); }}

從上面的例子可以看出,匿名類既可以在類中也可以在方法中被創建。

之前我們也提及匿名類既可以繼承一個具體類或者抽象類,也可以實現一個接口。所以在上面的代碼里,我創建了一個叫做 Programmer 的接口,并在 TestAnonymousClass 這個類中和 main() 方法中分別實現了接口。

Programmer除了接口以外既可以是一個抽象類也可以是一個具體類。

抽象類,像下面的代碼一樣:

public abstract class Programmer { public abstract void develop();}

具體類代碼如下:

public class Programmer { public void develop() {System.out.println('我是一個具體類'); }}

OK,繼續深入,那么如果 Programmer 這個類沒有無參構造函數怎么辦?我們可以在匿名類中訪問類變量嗎?我們如果繼承一個類,需要在匿名類中實現所有方法嗎?

public class Programmer { protected int age; public Programmer(int age) {this.age = age; } public void showAge() {System.out.println('年齡:' + age); } public void develop() {System.out.println('開發中……除了異性,他人勿擾'); } public static void main(String[] args) {Programmer programmer = new Programmer(38) { @Override public void showAge() {System.out.println('在匿名類中的showAge方法:' + age); }};programmer.showAge(); }} 構造匿名類時,我們可以使用任何構造函數。上面的代碼可以看到我們使用了帶參數的構造函數。 匿名類可以繼承具體類或者抽象類,也能實現接口。所以訪問修飾符規則同普通類是一樣的。子類可以訪問父類中的 protected 限制的屬性,但是無法訪問 private 限制的屬性。 如果匿名類繼承了具體類,比如上面代碼中的 Programmer 類,那么就不必重寫所有方法。但是如果匿名類繼承了一個抽象類或者實現了一個接口,那么這個匿名類就必須實現所有沒有實現的抽象方法。 在一個匿名內部類中你不能使用靜態初始化,也沒辦法添加靜態變量。 匿名內部類中可以有被 final 修飾的靜態常量。匿名類的典型使用場景

臨時使用:我們有時候需要添加一些類的臨時實現去修復一些問題或者添加一些功能。為了避免在項目里添加java文件,尤其是僅使用一次這個類的時候,我們就會使用匿名類。UI Event Listeners:在java的圖形界面編程中,匿名類最常使用的場景就是去創建一個事件監聽器。比如:

button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { }});

上面的代碼中,我們通過匿名類實現了 setOnClickListener 接口,當用戶點擊按鈕的時候,就會觸發我們實現的 onClick 方法。

多線程

Java 中的多線程就是利用多個線程共同完成一個大任務的運行過程,使用多線程可以最大程度的利用CPU。

使用多線程的使用線程而不是進程來做任務處理,是因為線程比進程更加輕量,線程是一個輕量級的進程,是程序執行的最小單元,并且線程和線程之間是共享主內存的,而進程不是。

線程生命周期

Java中難理解的四個概念

正如上圖所示,線程生命周期一共有六種狀態。我們現在依次對這些狀態進行介紹。

New:當我們構造出一個線程實例的時候, 這個線程就擁有了 New 狀態。這個狀態是線程的第一個狀態。此時,線程并沒有準備運行。 Runnable:當調用了線程類的 start() 方法, 那么這個線程就會從 New 狀態轉換到 Runnable 狀態。這就意味著這個線程要準備運行了。但是,如果線程真的要運行起來,就需要線程調度器來調度執行這個線程。但是線程調度器可能忙于在執行其他的線程,從而不能及時去調度執行這個線程。線程調度器是基于 FIFO 策略去從線程池中挑出一個線程來執行的。 Blocked:線程可能會因為不同的情況自動的轉為 Blocked 狀態。比如,等候 I/O 操作,等候網絡連接等等。除此之外,任意的優先級比當前正在運行的線程高的線程都可能會使得正在運行的線程轉為 Blocked 狀態。 Waiting:在同步塊中調用被同步對象的 wait 方法,當前線程就會進入 Waiting 狀態。如果在另一個線程中的同一個對象被同步的同步塊中調用 notify()/notifyAll(),就可能使得在 Waiting 的線程轉入 Runnable 狀態。 Timed_Waiting:同 Waiting 狀態,只是會有個時間限制,當超時了,線程會自動進入 Runnable 狀態。 Terminated:線程在線程的 run() 方法執行完畢后或者異常退出run()方法后,就會進入 Terminated 狀態。為什么要使用多線程

大白話講就是通過多線程同時做多件事情讓 Java 應用程序跑的更快,使用線程來實行并行和并發。如今的 CPU 都是多核并且頻率很高,如果單獨一個線程,并沒有充分利用多核 CPU 的優勢。

重要的優勢

可以更好地利用 CPU 可以更好地提升和響應性相關的用戶體驗 可以減少響應時間 可以同時服務多個客戶端創建線程有兩種方式

1.通過繼承Thread類創建線程

這個繼承類會重寫 Thread 類的 run() 方法。一個線程的真正運行是從 run() 方法內部開始的,通過 start() 方法會去調用這個線程的 run() 方法。

public class MultithreadDemo extends Thread { @Override public void run() {try { System.out.println('線程 ' + Thread.currentThread().getName() + ' 現在正在運行');} catch (Exception e) { e.printStackTrace();} } public static void main(String[] args) {for (int i = 0; i < 10; i++) { MultithreadDemo multithreadDemo = new MultithreadDemo(); multithreadDemo.start();} }}

2.通過實現Runnable接口創建線程

我們創建一個實現了 java.lang.Runnable 接口的新類,并實現其 run() 方法。然后我們會實例化一個 Thread 對象,并調用這個對象的 start() 方法。

public class MultithreadDemo implements Runnable { @Override public void run() {try { System.out.println('線程 ' + Thread.currentThread().getName() + ' 現在正在運行');} catch (Exception e) { e.printStackTrace();} } public static void main(String[] args) {for (int i = 0; i < 10; i++) { Thread thread = new Thread(new MultithreadDemo()); thread.start();} }}兩種創建方式對比 如果一個類繼承了 Thread 類,那么這個類就沒辦法繼承別的任何類了。因為 Java 是單繼承,不允許同時繼承多個類。多繼承只能采用接口的方式,一個類可以實現多個接口。所以,使用實現 Runnable 接口在實踐中比繼承 Thread 類更好一些。 第一種創建方式,可以重寫 yield()、interrupt() 等一些可能不太常用的方法。但是如果我們使用第二種方式去創建線程,則 yield() 等方法就無法重寫了。同步

同步只有在多線程條件下才有意義,一次只能有一個線程執行同步塊。

在 Java 中,同步這個概念非常重要,因為 Java 本身就是一門多線程語言,在多線程環境中,做合適的同步是極度重要的。

為什么要使用同步

在多線程環境中執行代碼,如果一個對象可以被多個線程訪問,為了避免對象狀態或者程序執行出現錯誤,對這個對象使用同步是非常必要的。

在深入講解同步概念之前,我們先來看看同步相關的問題。

class Production { //沒有做方法同步 void printProduction(int n) {for (int i = 1; i <= 5; i++) { System.out.print(n * i+' '); try {Thread.sleep(400); } catch (Exception e) {System.out.println(e); }} }}class MyThread1 extends Thread { Production p; MyThread1(Production p) {this.p = p; } public void run() {p.printProduction(5); }}class MyThread2 extends Thread { Production p; MyThread2(Production p) {this.p = p; } public void run() {p.printProduction(100); }}public class SynchronizationTest { public static void main(String args[]) {Production obj = new Production(); //多線程共享同一個對象MyThread1 t1 = new MyThread1(obj);MyThread2 t2 = new MyThread2(obj);t1.start();t2.start(); }}

運行上面的代碼后,由于我們沒有加同步,可以看到運行結果非常混亂。Output:

100 5 10 200 15 300 20 400 25 500

接下來,我們給 printProduction 方法加上同步:

class Production { //做了方法同步 synchronized void printProduction(int n) {for (int i = 1; i <= 5; i++) { System.out.print(n * i+' '); try {Thread.sleep(400); } catch (Exception e) {System.out.println(e); }} }}

當我們對 printProduction() 加上了同步(synchronized)后, 已有一個線程執行的情況下,是不會有任何一個線程可以再次執行這個方法。這次加了同步后的輸出結果是有次序的。

Output:

5 10 15 20 25 100 200 300 400 500

類似于對方法做同步,你也可以去同步 Java 類和對象。

注意:其實有時候我們可以不必去同步整個方法。出于性能原因,我們其實可以僅同步方法中我們需要同步的部分代碼。被同步的這部分代碼就是方法中的同步塊。

序列化

Java 的序列化就是將一個 Java 對象轉化為一個字節流的一種機制。從字節流再轉回 Java 對象叫做反序列化,是序列化的反向操作。

序列化和反序列化是和平臺無關的,也就是說你可以在 Linux 系統序列化,然后在 Windows 操作系統做反序列化。

如果要序列化對象,需要使用 ObjectOutputStream 類的 writeObject() 方法。如果要做反序列化,則要使用 ObjectOutputStream 類的 readObject() 方法。

如下圖所示,對象被轉化為字節流后,被儲存在了不同的介質中。這個流程就是序列化。在圖的右邊,也可以看到從不同的介質中,比如內存,獲得字節流并轉化為對象,這叫做反序列化。

Java中難理解的四個概念

為什么使用序列化

如果我們創建了一個 Java 對象,這個對象的狀態在程序執行完畢或者退出后就消失了,不會得到保存。

所以,為了能解決這類問題,Java 提供了序列化機制。這樣,我們就能把對象的狀態做臨時儲存或者進行持久化,以供后續當我們需要這個對象時,可以通過反序列化把對象還原回來。

下面給出一些代碼看看我們是怎么來做序列化的。

import java.io.Serializable;public class Player implements Serializable { private static final long serialVersionUID = 1L; private String serializeValueName; private transient String nonSerializeValuePos; public String getSerializeValueName() {return serializeValueName; } public void setSerializeValueName(String serializeValueName) {this.serializeValueName = serializeValueName; } public String getNonSerializeValueSalary() {return nonSerializeValuePos; } public void setNonSerializeValuePos(String nonSerializeValuePos) {this.nonSerializeValuePos = nonSerializeValuePos; } @Override public String toString() {return 'Player [serializeValueName=' + serializeValueName + ']'; }}

import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;public class SerializingObject { public static void main(String[] args) {Player playerOutput = null;FileOutputStream fos = null;ObjectOutputStream oos = null;playerOutput = new Player();playerOutput.setSerializeValueName('niubi');playerOutput.setNonSerializeValuePos('x:1000,y:1000');try { fos = new FileOutputStream('Player.ser'); oos = new ObjectOutputStream(fos); oos.writeObject(playerOutput); System.out.println('序列化數據被存放至Player.ser文件'); oos.close(); fos.close();} catch (IOException e) { e.printStackTrace();} }}

Output:

序列化數據被存放至Player.ser文件

import java.io.FileInputStream;import java.io.IOException;import java.io.ObjectInputStream;public class DeSerializingObject { public static void main(String[] args) {Player playerInput = null;FileInputStream fis = null;ObjectInputStream ois = null;try { fis = new FileInputStream('Player.ser'); ois = new ObjectInputStream(fis); playerInput = (Player) ois.readObject(); System.out.println('從Player.ser文件中恢復'); ois.close(); fis.close();} catch (IOException | ClassNotFoundException e) { e.printStackTrace();}System.out.println('player名字為 : ' + playerInput.getSerializeValueName());System.out.println('player位置為 : ' + playerInput.getNonSerializeValuePos()); }}

Output:

從Player.ser文件中恢復

player名字為 : niubi

player位置為:null

關鍵特性 如果父類實現了 Serializable 接口那么子類就不必再實現 Serializable 接口了。但是反過來不行。 序列化只支持非 static 的成員變量 static 修飾的變量和常量以及被 transient 修飾的變量是不會被序列化的。所以,如果我們不想要序列化某些非 static 的成員變量,直接用 transient 修飾它們就好了。 當反序列化對象的時候,是不會調用對象的構造函數的。 如果一個對象被一個要序列化的對象引用了,這個對象也會被序列化,并且這個對象也必須要實現 Serializable 接口。總結

首先,我們介紹了匿名類的定義,使用場景和使用方式。

其次,我們討論了多線程和其生命周期以及多線程的使用場景。

再次,我們了解了同步,知道同步后,僅同時允許一個線程執行被同步的方法或者代碼塊。當一個線程在執行被同步的代碼時,別的線程只能在隊列中等待直到執行同步代碼的線程釋放資源。

最后,我們知道了序列化就是把對象狀態儲存起來以供后續使用。

以上就是Java中難理解的四個概念的詳細內容,更多關于Java的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久亚洲视频| 成午夜精品一区二区三区软件| 999精品在线| 国产一区观看| 欧美在线综合| 亚洲精品系列| 国产欧美69| 女生影院久久| 极品日韩av| 伊人国产精品| 嫩草伊人久久精品少妇av杨幂| 麻豆精品蜜桃视频网站| 中文字幕在线看片| 亚洲精品888| 日韩精品三级| 电影91久久久| 国产精品美女久久久| 日韩亚洲精品在线观看| 精品99在线| 亚洲一区二区免费看| 国产欧美日韩精品高清二区综合区| 国产一区二区精品福利地址| 国内精品福利| 青青草国产精品亚洲专区无| 91视频一区| 亚洲另类视频| 日韩成人精品一区二区| 夜夜精品视频| 欧美国产极品| 国产视频亚洲| 免费亚洲婷婷| 91九色精品| 国产亚洲精品美女久久| 99国产精品久久久久久久| 亚洲综合丁香| 日本成人在线不卡视频| 精品女同一区二区三区在线观看| 亚洲精华国产欧美| 国产精品xxxav免费视频| 亚洲女同中文字幕| 国产午夜一区| 久久精品青草| 日韩av午夜在线观看| 成人影视亚洲图片在线| 日韩中文字幕91| 97视频热人人精品免费| 亚洲精品动态| 99精品电影| 国产精品九九| 一区二区高清| 久久久久久美女精品| 国产精品资源| 免费成人av在线播放| 韩国三级一区| 免费在线欧美黄色| 日韩在线一二三区| 日本蜜桃在线观看视频| 日韩1区2区3区| 黑丝一区二区三区| 国产一区二区三区四区大秀 | 九九久久国产| 日韩一区二区三免费高清在线观看| 久久久久国产精品一区三寸| 麻豆成人av在线| 日本免费新一区视频| 久久国产99| 欧美亚洲国产激情| 福利一区二区三区视频在线观看| 久久激五月天综合精品| 首页国产欧美久久| 日韩一区二区三区免费| 免费一级欧美在线观看视频| 97久久超碰| 亚洲毛片视频| 男女男精品网站| 亚洲欧美日韩在线观看a三区| 亚洲爱爱视频| 国产美女高潮在线| 精品亚洲免a| 麻豆精品视频在线观看| 日韩精品一区二区三区中文| 在线观看亚洲精品福利片| 欧美在线亚洲| 欧美a级片一区| 欧美日韩精品免费观看视频完整| 日韩在线第七页| 欧美日韩视频免费观看| 丝袜美腿诱惑一区二区三区| 日韩大片在线播放| 群体交乱之放荡娇妻一区二区| 中文一区一区三区高中清不卡免费| 麻豆精品在线观看| 久久中文字幕一区二区| 国产精品一区高清| 国产精品黄色| 欧美黄色精品| 欧美xxxx中国| 日韩在线观看| 免费av一区二区三区四区| 亚洲精品一二三区区别| 欧美日韩国产高清电影| 天堂资源在线亚洲| 欧美日韩免费观看一区=区三区 | 欧美日韩日本国产亚洲在线| 激情综合网站| 中文字幕一区二区三区在线视频| 亚州av一区| 国产精品啊啊啊| 毛片在线网站| 亚洲激精日韩激精欧美精品| 日韩精品一二三四| 日韩不卡一二三区| 国产精品二区影院| 国产一区二区三区不卡av| 激情国产在线| 日韩一级网站| 欧美日韩一区自拍| 国产精品99久久精品| 亚洲一级特黄| 亚洲最新av| 久久精品资源| 91九色精品| 欧美日韩一区二区三区在线电影| 国精品产品一区| 欧美日韩国产亚洲一区| 日韩一二三区在线观看| 九九久久国产| 夜久久久久久| 欧美激情一区| 亚洲午夜黄色| 亚洲精品大片| 98精品久久久久久久| 性一交一乱一区二区洋洋av| 日韩精品免费视频人成| 国产自产自拍视频在线观看| 鲁大师影院一区二区三区| 国产精品美女午夜爽爽| 香蕉国产精品| 老司机精品视频网| 亚洲精品91| 欧美国产专区| 欧美专区18| 成人在线超碰| 亚洲欧洲av| 国产不卡人人| 色婷婷成人网| 久久激情中文| 国产精品香蕉| 国产亚洲在线观看| 欧美丰满日韩| 91成人精品在线| 国产综合婷婷| 久久精品国产成人一区二区三区| 91成人精品| 麻豆精品久久久| 久久最新视频| 日韩欧美一区二区三区在线观看 | 播放一区二区| 日韩精彩视频在线观看| 国精品一区二区| 国产福利91精品一区二区| 中文一区一区三区免费在线观 | 国产三级一区| 亚洲天堂黄色| 狠狠久久伊人中文字幕| 天海翼精品一区二区三区| 久久国产小视频| 精品视频在线你懂得| 日韩一区二区三区精品| 一区在线视频观看| 丝袜诱惑一区二区| 国产日韩免费| 亚洲精品在线a| av一区二区高清| 日韩深夜视频| 久久精品国产一区二区| 日韩av三区| 蜜臀久久久久久久| 欧美日韩激情| 日韩精品一区二区三区免费观影| 久久99精品久久久久久园产越南| 亚洲日本在线观看视频| 亚洲激情中文| 99久久亚洲精品蜜臀| 日本不卡免费高清视频在线| 另类欧美日韩国产在线| 日韩三级久久| 蜜臀a∨国产成人精品| 国产中文一区| 久久高清精品| 国产在线成人| 99国产精品视频免费观看一公开 | 国产情侣一区| 日韩精品久久久久久久软件91| 99国产精品| 伊人久久亚洲影院| 亚洲电影在线一区二区三区| 国产精品97| 亚洲福利免费| 欧美亚洲国产激情|