java 网络编程connection timed out是什么意思_什么?听说这四个概念,很多 Java 老手都说不清...
Java 是很多人一直在用的編程語言,但是有些 Java 概念是非常難以理解的,哪怕是一些多年的老手,對某些 Java 概念也存在一些混淆和困惑。
所以,在這篇文章里,會介紹四個 Java 中最難理解的四個概念,去幫助開發者更清晰的理解這些概念:
匿名內部類
匿名內部類又叫匿名類,它有點像局部類(Local Class)或者內部類(Inner Class),只是匿名內部類沒有名字,我們可以同時聲明并實例化一個匿名內部類。
一個匿名內部類僅適用在想使用一個局部類并且只會使用這個局部類一次的場景。
匿名內部類是沒有需要明確聲明的構造函數的,但是會有一個隱藏的自動聲明的構造函數。
創建匿名內部類有兩種辦法:
咱們看看下面的例子:
interface Programmer { void develop();} public class TestAnonymousClass { public static Programmer programmer = new Programmer() { @Override public 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(); }}匿名類的典型使用場景
上面的代碼中,我們通過匿名類實現了 setOnClickListener 接口,當用戶點擊按鈕的時候,就會觸發我們實現的 onClick 方法。
多線程
Java 中的多線程就是利用多個線程共同完成一個大任務的運行過程,使用多線程可以最大程度的利用CPU。
使用多線程的使用線程而不是進程來做任務處理,是因為線程比進程更加輕量,線程是一個輕量級的進程,是程序執行的最小單元,并且線程和線程之間是共享主內存的,而進程不是。
線程生命周期
正如上圖所示,線程生命周期一共有六種狀態。我們現在依次對這些狀態進行介紹。
為什么要使用多線程
大白話講就是通過多線程同時做多件事情讓 Java 應用程序跑的更快,使用線程來實行并行和并發。如今的 CPU 都是多核并且頻率很高,如果單獨一個線程,并沒有充分利用多核 CPU 的優勢。
重要的優勢
- 可以更好地利用 CPU
- 可以更好地提升和響應性相關的用戶體驗
- 可以減少響應時間
- 可以同時服務多個客戶端
創建線程有兩種方式
這個繼承類會重寫 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(); } }}我們創建一個實現了 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 提供了序列化機制。這樣,我們就能把對象的狀態做臨時儲存或者進行持久化,以供后續當我們需要這個對象時,可以通過反序列化把對象還原回來。
下面給出一些代碼看看我們是怎么來做序列化的。
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名字為 : niubiplayer位置為 : null關鍵特性
總結
首先,我們介紹了匿名類的定義,使用場景和使用方式。
其次,我們討論了多線程和其生命周期以及多線程的使用場景。
再次,我們了解了同步,知道同步后,僅同時允許一個線程執行被同步的方法或者代碼塊。當一個線程在執行被同步的代碼時,別的線程只能在隊列中等待直到執行同步代碼的線程釋放資源。
最后,我們知道了序列化就是把對象狀態儲存起來以供后續使用。
總結
以上是生活随笔為你收集整理的java 网络编程connection timed out是什么意思_什么?听说这四个概念,很多 Java 老手都说不清...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 环绕布局,Android
- 下一篇: java美元兑换,(Java实现) 美元