JAVA笔记(十四)
線程狀態轉換圖(它有好幾條路徑)
線程組?Java中使用ThreadGroup來表示線程組,它可以對一批線程進行分類管理,Java允許程序直接對線程組進行控制。
默認情況下,所有的線程都屬于主線程組。【main】
public final ThreadGroup getThreadGroup()
我們也可以給線程設置分組
Thread(ThreadGroup?group, Runnable?target, String?name)
??可能產生死鎖的代碼
??
package cn.itcast_02;public class MyLock {// 創建兩把鎖對象public static final Object objA = new Object();public static final Object objB = new Object();}ackage cn.itcast_02;public class DieLock extends Thread {private boolean flag;public DieLock(boolean flag) {this.flag = flag;}@Overridepublic void run() {if (flag) {synchronized (MyLock.objA) {System.out.println("if objA");synchronized (MyLock.objB) {System.out.println("if objB");}}} else {synchronized (MyLock.objB) {System.out.println("else objB");synchronized (MyLock.objA) {System.out.println("else objA");}}}}}package cn.itcast_02;/** 同步的弊端:* A:效率低* B:容易產生死鎖* 死鎖:* 兩個或兩個以上的線程在爭奪資源的過程中,發生的一種相互等待的現象。** 舉例:* 中國人,美國人吃飯案例。* 正常情況:* 中國人:筷子兩支* 美國人:刀和叉* 現在:* 中國人:筷子1支,刀一把* 美國人:筷子1支,叉一把*/public class DieLockDemo {public static void main(String[] args) {DieLock dl1 = new DieLock(true);DieLock dl2 = new DieLock(false);dl1.start();dl2.start();}} 等待喚醒機制代碼package cn.itcast_05;public class Student {String name;int age;boolean flag; // 默認情況是沒有數據,如果是true,說明有數據}package cn.itcast_05;public class SetThread implements Runnable {private Student s;private int x = 0;public SetThread(Student s) {this.s = s;}@Overridepublic void run() {while (true) {synchronized (s) {//判斷有沒有if(s.flag){try {s.wait(); //t1等著,釋放鎖} catch (InterruptedException e) {e.printStackTrace();}}if (x % 2 == 0) {s.name = "林青霞";s.age = 27;} else {s.name = "劉意";s.age = 30;}x++; //x=1//修改標記s.flag = true;//喚醒線程s.notify(); //喚醒t2,喚醒并不表示你立馬可以執行,必須還得搶CPU的執行權。}//t1有,或者t2有}}}package cn.itcast_05;public class GetThread implements Runnable {private Student s;public GetThread(Student s) {this.s = s;}@Overridepublic void run() {while (true) {synchronized (s) {if(!s.flag){try {s.wait(); //t2就等待了。立即釋放鎖。將來醒過來的時候,是從這里醒過來的時候} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(s.name + "---" + s.age);//林青霞---27//劉意---30//修改標記s.flag = false;//喚醒線程s.notify(); //喚醒t1}}}}package cn.itcast_05;/** 分析:* 資源類:Student* 設置學生數據:SetThread(生產者)* 獲取學生數據:GetThread(消費者)* 測試類:StudentDemo* 問題1:按照思路寫代碼,發現數據每次都是:null---0* 原因:我們在每個線程中都創建了新的資源,而我們要求的時候設置和獲取線程的資源應該是同一個* 如何實現呢?* 在外界把這個數據創建出來,通過構造方法傳遞給其他的類。* 問題2:為了數據的效果好一些,我加入了循環和判斷,給出不同的值,這個時候產生了新的問題* A:同一個數據出現多次* B:姓名和年齡不匹配* 原因:* A:同一個數據出現多次* CPU的一點點時間片的執行權,就足夠你執行很多次。* B:姓名和年齡不匹配* 線程運行的隨機性* 線程安全問題:* A:是否是多線程環境 是* B:是否有共享數據 是* C:是否有多條語句操作共享數據 是* 解決方案:* 加鎖。* 注意:* A:不同種類的線程都要加鎖。* B:不同種類的線程加的鎖必須是同一把。* 問題3:雖然數據安全了,但是呢,一次一大片不好看,我就想依次的一次一個輸出。* 如何實現呢?* 通過Java提供的等待喚醒機制解決。* 等待喚醒:* Object類中提供了三個方法:* wait():等待* notify():喚醒單個線程* notifyAll():喚醒所有線程* 為什么這些方法不定義在Thread類中呢?* 這些方法的調用必須通過鎖對象調用,而我們剛才使用的鎖對象是任意鎖對象。* 所以,這些方法必須定義在Object類中。*/public class StudentDemo {public static void main(String[] args) {//創建資源Student s = new Student();//設置和獲取的類SetThread st = new SetThread(s);GetThread gt = new GetThread(s);//線程類Thread t1 = new Thread(st);Thread t2 = new Thread(gt);//啟動線程t1.start();t2.start();}} 等待喚醒機制代碼金典版 package cn.itcast_07;public class Student {private String name;private int age;private boolean flag; // 默認情況是沒有數據,如果是true,說明有數據public synchronized void set(String name, int age) {// 如果有數據,就等待if (this.flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 設置數據this.name = name;this.age = age;// 修改標記this.flag = true;this.notify();}public synchronized void get() {// 如果沒有數據,就等待if (!this.flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}// 獲取數據System.out.println(this.name + "---" + this.age);// 修改標記this.flag = false;this.notify();}}package cn.itcast_07;public class SetThread implements Runnable {private Student s;private int x = 0;public SetThread(Student s) {this.s = s;}@Overridepublic void run() {while (true) {if (x % 2 == 0) {s.set("林青霞", 27);} else {s.set("劉意", 30);}x++;}}}ackage cn.itcast_07;public class GetThread implements Runnable {private Student s;public GetThread(Student s) {this.s = s;}@Overridepublic void run() {while (true) {s.get();}}}package cn.itcast_07;/** 分析:* 資源類:Student* 設置學生數據:SetThread(生產者)* 獲取學生數據:GetThread(消費者)* 測試類:StudentDemo問題1:按照思路寫代碼,發現數據每次都是:null---0* 原因:我們在每個線程中都創建了新的資源,而我們要求的時候設置和獲取線程的資源應該是同一個* 如何實現呢?* 在外界把這個數據創建出來,通過構造方法傳遞給其他的類。* 問題2:為了數據的效果好一些,我加入了循環和判斷,給出不同的值,這個時候產生了新的問題* A:同一個數據出現多次* B:姓名和年齡不匹配* 原因:* A:同一個數據出現多次* CPU的一點點時間片的執行權,就足夠你執行很多次。* B:姓名和年齡不匹配* 線程運行的隨機性* 線程安全問題:* A:是否是多線程環境 是* B:是否有共享數據 是* C:是否有多條語句操作共享數據 是* 解決方案:* 加鎖。* 注意:* A:不同種類的線程都要加鎖。* B:不同種類的線程加的鎖必須是同一把。** 問題3:雖然數據安全了,但是呢,一次一大片不好看,我就想依次的一次一個輸出。* 如何實現呢?* 通過Java提供的等待喚醒機制解決。* 等待喚醒:* Object類中提供了三個方法:* wait():等待* notify():喚醒單個線程* notifyAll():喚醒所有線程* 為什么這些方法不定義在Thread類中呢?* 這些方法的調用必須通過鎖對象調用,而我們剛才使用的鎖對象是任意鎖對象。* 所以,這些方法必須定義在Object類中。* 最終版代碼中:* 把Student的成員變量給私有的了。* 把設置和獲取的操作給封裝成了功能,并加了同步。* 設置或者獲取的線程里面只需要調用方法即可。*/public class StudentDemo {public static void main(String[] args) {//創建資源Student s = new Student();//設置和獲取的類SetThread st = new SetThread(s);GetThread gt = new GetThread(s);//線程類Thread t1 = new Thread(st);Thread t2 = new Thread(gt);//啟動線程t1.start();t2.start();}}
???? 程序啟動一個新線程成本是比較高的,因為它涉及到要與操作系統進行交互。而使用線程池可以很好的提高性能,尤其是當程序中要創建大量生存期很短的線程時,更應該考慮使用線程池。
線程池里的每一個線程代碼結束后,并不會死亡,而是再次回到線程池中成為空閑狀態,等待下一個對象來使用。
在JDK5之前,我們必須手動實現自己的線程池,從JDK5開始,Java內置支持線程池
JDK5新增了一個Executors工廠類來產生線程池,有如下幾個方法
public static ExecutorService newCachedThreadPool()public static ExecutorService newFixedThreadPool(int nThreads)public static ExecutorService newSingleThreadExecutor()
這些方法的返回值是ExecutorService對象,該對象表示一個線程池,可以執行Runnable對象或者Callable對象代表的線程。它提供了如下方法
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
案例演示
創建線程池對象
創建Runnable實例
提交Runnable實例
關閉線程池
(shutdown()方法)????
???? 實現Callable接口
步驟和剛才演示線程池執行Runnable對象的差不多。
但是還可以更好玩一些,求和案例演示
好處:
可以有返回值
可以拋出異常
弊端:
代碼比較復雜,所以一般不用
多線程求和代碼
package cn.itcast_10;import java.util.concurrent.Callable;/** 線程求和案例*/public class MyCallable implements Callable<Integer> {private int number;public MyCallable(int number) {this.number = number;}@Overridepublic Integer call() throws Exception {int sum = 0;for (int x = 1; x <= number; x++) {sum += x;}return sum;}}package cn.itcast_10;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** 多線程實現的方式3:* A:創建一個線程池對象,控制要創建幾個線程對象。* public static ExecutorService newFixedThreadPool(int nThreads)* B:這種線程池的線程可以執行:* 可以執行Runnable對象或者Callable對象代表的線程* 做一個類實現Runnable接口。* C:調用如下方法即可* Future<?> submit(Runnable task)* <T> Future<T> submit(Callable<T> task)* D:我就要結束,可以嗎?* 可以。*/public class CallableDemo {public static void main(String[] args) throws InterruptedException, ExecutionException {// 創建線程池對象ExecutorService pool = Executors.newFixedThreadPool(2);// 可以執行Runnable對象或者Callable對象代表的線程Future<Integer> f1 = pool.submit(new MyCallable(100));Future<Integer> f2 = pool.submit(new MyCallable(200));// V get()Integer i1 = f1.get();Integer i2 = f2.get();System.out.println(i1);System.out.println(i2);// 結束pool.shutdown();}}定時器定時器是一個應用十分廣泛的線程工具,可用于調度多個定時任務以后臺線程的方式執行。在Java中,可以通過Timer和TimerTask類來實現定義調度的功能Timer定時public Timer()public void schedule(TimerTask task, long delay)public void schedule(TimerTask task,long delay,long period)TimerTask任務【該類是一個抽象類】public abstract void run()public boolean cancel()開發中Quartz是一個完全由java編寫的開源調度框架。 匿名內部類使用多線程 匿名內部類方式使用多線程new Thread(){代碼…}.start();New Thread(new Runnable(){代碼…}).start();package cn.itcast_11;/** 匿名內部類的格式:* new 類名或者接口名() {* 重寫方法;* };* 本質:是該類或者接口的子類對象。*/public class ThreadDemo {public static void main(String[] args) {// 繼承Thread類來實現多線程new Thread() {public void run() {for (int x = 0; x < 100; x++) {System.out.println(Thread.currentThread().getName() + ":"+ x);}}}.start();// 實現Runnable接口來實現多線程new Thread(new Runnable() {@Overridepublic void run() {for (int x = 0; x < 100; x++) {System.out.println(Thread.currentThread().getName() + ":"+ x);}}}) {}.start();// 更有難度的(兩個同時有的時候調用的是子類對象的,并不是Runnable的)new Thread(new Runnable() {@Overridepublic void run() {for (int x = 0; x < 100; x++) {System.out.println("hello" + ":" + x);}}}) {public void run() {for (int x = 0; x < 100; x++) {System.out.println("world" + ":" + x);}}}.start();}}
?? 多線程有幾種實現方案,分別是哪幾種?
?????? 兩種。
?????? 繼承Thread類
?????? 實現Runnable接口
擴展一種:實現Callable接口。這個得和線程池結合。
2:同步有幾種方式,分別是什么?
?????? 兩種。
??????
?????? 同步代碼塊
?????? 同步方法
3:啟動一個線程是run()還是start()?它們的區別?
?????? start();
run():封裝了被線程執行的代碼,直接調用僅僅是普通方法的調用
?????? start():啟動線程,并由JVM自動調用run()方法
4:sleep()和wait()方法的區別
?????? sleep():必須指時間;不釋放鎖。
?????? wait():可以不指定時間,也可以指定時間;等待的時候釋放鎖。
5:為什么wait(),notify(),notifyAll()等方法都定義在Object類中
?????? 因為這些方法的調用是依賴于鎖對象的,而同步代碼塊的鎖對象是任意鎖。
?????? 而Object代表任意的對象,所以,定義在這里面。
6:線程的生命周期圖
?????? 新建 -- 就緒 -- 運行 -- 死亡
?????? 新建 -- 就緒 -- 運行 -- 阻塞 -- 就緒 -- 運行 -- 死亡
?????? 建議:畫圖解釋。
??
package cn.itcast_12;import java.io.File;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;/** 需求:在指定的時間刪除我們的指定目錄(我使用項目路徑下的demo)*/class DeleteFolder extends TimerTask {@Overridepublic void run() {File srcFolder = new File("demo");deleteFolder(srcFolder);}// 遞歸刪除目錄public void deleteFolder(File srcFolder) {File[] fileArray = srcFolder.listFiles();if (fileArray != null) {for (File file : fileArray) {if (file.isDirectory()) {deleteFolder(file);} else {System.out.println(file.getName() + ":" + file.delete());}}System.out.println(srcFolder.getName() + ":" + srcFolder.delete());}}}public class TimerTest {public static void main(String[] args) throws ParseException {Timer t = new Timer();String s = "2014-11-27 15:45:00";SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d = sdf.parse(s);t.schedule(new DeleteFolder(), d);}} 定時器經典代碼2 package cn.itcast_12;import java.util.Timer;import java.util.TimerTask;/** 定時器:可以讓我們在指定的時間做某件事情,還可以重復的做某件事情。* 依賴Timer和TimerTask這兩個類:* Timer:定時* public Timer()* public void schedule(TimerTask task,long delay)* public void schedule(TimerTask task,long delay,long period)* public void cancel()* TimerTask:任務*/public class TimerDemo {public static void main(String[] args) {// 創建定時器對象Timer t = new Timer();// 3秒后執行爆炸任務// t.schedule(new MyTask(), 3000);//結束任務t.schedule(new MyTask(t), 3000);}}// 做一個任務class MyTask extends TimerTask {private Timer t;public MyTask(){}public MyTask(Timer t){this.t = t;}@Overridepublic void run() {System.out.println("beng,爆炸了");t.cancel();}}
?設計模式的分類
創建型模式 對象的創建
結構型模式 對象的組成(結構)
行為型模式 對象的行為
?創建型模式:簡單工廠模式,工廠方法模式,抽象工廠模式,建造者模式,原型模式,單例模式。(6個)
結構型模式:外觀模式、適配器模式、代理模式、裝飾模式、橋接模式、組合模式、享元模式。(7個)
行為型模式:模版方法模式、觀察者模式、狀態模式、職責鏈模式、命令模式、訪問者模式、策略模式、備忘錄模式、迭代器模式、解釋器模式。(10個)
簡單工廠模式簡單工廠模式概述
又叫靜態工廠方法模式,它定義一個具體的工廠類負責創建一些類的實例
優點
客戶端不需要在負責對象的創建,從而明確了各個類的職責
缺點
這個靜態工廠類負責所有對象的創建,如果有新的對象增加,或者某些對象的創建方式不同,就需要不斷的修改工廠類,不利于后期的維護
動物抽象類:public abstract Animal { public abstract void eat(); }
具體狗類:public class Dog extends Animal {}
具體貓類:public class Cat extends Animal {}
開始,在測試類中每個具體的內容自己創建對象,但是,創建對象的工作如果比較麻煩,就需要有人專門做這個事情,所以就知道了一個專門的類來創建對象。
public class AnimalFactory {private AnimalFactory(){}//public static Dog createDog() {return new Dog();}//public static Cat createCat() {return new Cat();}//改進public static Animal createAnimal(String animalName) {if(“dog”.equals(animalName)) {}else if(“cat”.equals(animaleName)) {}else {return null;}}}
?? 工廠方法模式概述
工廠方法模式中抽象工廠類負責定義創建對象的接口,具體對象的創建工作由繼承抽象工廠的具體類實現。
優點
客戶端不需要在負責對象的創建,從而明確了各個類的職責,如果有新的對象增加,只需要增加一個具體的類和具體的工廠類即可,不影響已有的代碼,后期維護容易,增強了系統的擴展性
缺點
需要額外的編寫代碼,增加了工作量
動物抽象類:public abstract Animal { public abstract void eat(); }
工廠接口:public interface Factory {public abstract Animal createAnimal();}
具體狗類:public class Dog extends Animal {}
具體貓類:public class Cat extends Animal {}
開始,在測試類中每個具體的內容自己創建對象,但是,創建對象的工作如果比較麻煩,就需要有人專門做這個事情,所以就知道了一個專門的類來創建對象。發現每次修改代碼太麻煩,用工廠方法改進,針對每一個具體的實現提供一個具體工廠。
狗工廠:public class DogFactory implements Factory {
?????? public Animal createAnimal() {…}
??????? }
貓工廠:public class CatFactory implements Factory {
?????? public Animal createAnimal() {…}
??????? }
?????
? 單例設計模式概述
單例模式就是要確保類在內存中只有一個對象,該實例必須自動創建,并且對外提供。
優點
在系統內存中只存在一個對象,因此可以節約系統資源,對于一些需要頻繁創建和銷毀的對象單例模式無疑可以提高系統的性能。
缺點
沒有抽象層,因此擴展很難。
職責過重,在一定程序上違背了單一職責????????
???? package cn.itcast_03;
?
public class Student {
?????? // 構造私有
?????? private Student() {
?????? }
?
?????? // 自己造一個
?????? // 靜態方法只能訪問靜態成員變量,加靜態
?????? // 為了不讓外界直接訪問修改這個值,加private
?????? private static Student s = new Student();
?
?????? // 提供公共的訪問方式
?????? // 為了保證外界能夠直接使用該方法,加靜態
?????? public static Student getStudent() {
????????????? return s;
?????? }
}
package cn.itcast_03;
?
/*
?* 單例模式:保證類在內存中只有一個對象。
?*
?* 如何保證類在內存中只有一個對象呢?
?* ????????????? A:把構造方法私有
?* ????????????? B:在成員位置自己創建一個對象
?* ????????????? C:通過一個公共的方法提供訪問
?*/
public class StudentDemo {public static void main(String[] args) {// Student s1 = new Student();// Student s2 = new Student();// System.out.println(s1 == s2); // false// 通過單例如何得到對象呢?// Student.s = null;Student s1 = Student.getStudent();Student s2 = Student.getStudent();System.out.println(s1 == s2);System.out.println(s1); // null,cn.itcast_03.Student@175078bSystem.out.println(s2);// null,cn.itcast_03.Student@175078b}} 單例設計模式懶漢式 package cn.itcast_03;/** 單例模式:* 餓漢式:類一加載就創建對象* 懶漢式:用的時候,才去創建對象*/public class Teacher {private Teacher() {}private static Teacher t = null;public synchronized static Teacher getTeacher() {// t1,t2,t3if (t == null) {//t1,t2,t3t = new Teacher();}return t;}}package cn.itcast_03;public class TeacherDemo {public static void main(String[] args) {Teacher t1 = Teacher.getTeacher();Teacher t2 = Teacher.getTeacher();System.out.println(t1 == t2);System.out.println(t1); // cn.itcast_03.Teacher@175078bSystem.out.println(t2);// cn.itcast_03.Teacher@175078b}}
??????? ????
???? 面試題:單例模式的思想是什么?請寫一個代碼體現。
?*
?* ??????????? 開發:餓漢式(是不會出問題的單例模式)
?* ??????????? 面試:懶漢式(可能會出問題的單例模式)
?* ?????????????????? A:懶加載(延遲加載)?
?* ?????????????????? B:線程安全問題
?* ????????????????????????? a:是否多線程環境(可能沒有)???? 是
?* ????????????????????????? b:是否有共享數據???? 是
?* ????????????????????????? c:是否有多條語句操作共享數據 ?? 是
?
24.javax.swing:在AWT的基礎上,建立的一套圖形界面系統,其中提供了更多的組件,而且完全由Java實現。增強了移植性,屬輕量級控件。(這里的輕重是指依賴當前系統的程度,越重依賴性越高,這樣就不方便移植)?????????
?
package cn.itcast_02;import java.awt.Frame;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.awt.event.WindowListener;public class FrameDemo {public static void main(String[] args) {// 創建窗體對象Frame f = new Frame("窗體關閉案例");// 設置窗體屬性f.setBounds(400, 200, 400, 300);// 讓窗體關閉//事件源//事件:對窗體的處理//事件處理:關閉窗口(System.exit(0));//事件監聽// f.addWindowListener(new WindowListener() {// @Override// public void windowOpened(WindowEvent e) {// }// @Override// public void windowIconified(WindowEvent e) {// }// @Override// public void windowDeiconified(WindowEvent e) {// }// @Override// public void windowDeactivated(WindowEvent e) {// }// @Override// public void windowClosing(WindowEvent e) {// System.exit(0);// }// @Override// public void windowClosed(WindowEvent e) {// }// @Override// public void windowActivated(WindowEvent e) {// }// });//用適配器類改進f.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});// 設置窗體可見f.setVisible(true);}}
?
package cn.itcast_05;import java.awt.Button;import java.awt.FlowLayout;import java.awt.Frame;import java.awt.TextArea;import java.awt.TextField;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;public class FrameDemo {public static void main(String[] args) {// 創建窗體對象Frame f = new Frame("數據轉移");// 設置窗體屬性和布局f.setBounds(400, 200, 400, 300);f.setLayout(new FlowLayout());// 創建文本框final TextField tf = new TextField(20);// 創建按鈕Button bu = new Button("數據轉移");// 創建文本域final TextArea ta = new TextArea(10, 40);// 把組件添加到窗體f.add(tf);f.add(bu);f.add(ta);// 設置窗體關閉f.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});// 對按鈕添加事件bu.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {// 獲取文本框的值String tf_str = tf.getText().trim();// 清空數據tf.setText("");// 設置給文本域// ta.setText(tf_str);// 追加和換行ta.append(tf_str + "\r\n");//獲取光標tf.requestFocus();}});// 設置窗體顯示f.setVisible(true);}}
? ? ?
package cn.itcast_06;import java.awt.Button;import java.awt.Color;import java.awt.FlowLayout;import java.awt.Frame;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;public class FrameDemo {public static void main(String[] args) {// 創建窗體對象final Frame f = new Frame("更改背景色");// 設置窗體屬性和布局f.setBounds(400, 200, 400, 300);f.setLayout(new FlowLayout());// 創建四個按鈕Button redButton = new Button("紅色");Button greenButton = new Button("綠色");Button buleButton = new Button("藍色");// 添加按鈕f.add(redButton);f.add(greenButton);f.add(buleButton);// 設置窗體關閉f.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});// 對按鈕添加動作事件// redButton.addActionListener(new ActionListener() {// @Override// public void actionPerformed(ActionEvent e) {// f.setBackground(Color.RED);// }// });// 對按鈕添加鼠標點擊事件// redButton.addMouseListener(new MouseAdapter() {// @Override// public void mouseClicked(MouseEvent e) {// f.setBackground(Color.RED);// }// });// 對按鈕添加鼠標的進入事件redButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseEntered(MouseEvent e) {f.setBackground(Color.RED);}});redButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseExited(MouseEvent e) {f.setBackground(Color.WHITE);}});greenButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseEntered(MouseEvent e) {f.setBackground(Color.GREEN);}});greenButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseExited(MouseEvent e) {f.setBackground(Color.WHITE);}});buleButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseEntered(MouseEvent e) {f.setBackground(Color.BLUE);}});buleButton.addMouseListener(new MouseAdapter() {@Overridepublic void mouseExited(MouseEvent e) {f.setBackground(Color.WHITE);}});// 設置窗體顯示f.setVisible(true);}}
? ?
package cn.itcast_07;import java.awt.FlowLayout;import java.awt.Frame;import java.awt.Label;import java.awt.TextField;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;/** 你輸入的如果是非數字字符,就取消你鍵盤錄入的效果。*/public class FrameDemo {public static void main(String[] args) {// 創建窗體對象并設置屬性Frame f = new Frame("不能輸入非數字字符");f.setBounds(400, 200, 400, 300);f.setLayout(new FlowLayout());// 創建Label標簽對象Label label = new Label("請輸入你的QQ號碼,不能是非數字,不信你試試");TextField tf = new TextField(40);// 添加到窗體上f.add(label);f.add(tf);// 設置窗體關閉f.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});// 給文本框添加事件tf.addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {// 如果你取得的字符不是數字字符就取消事件// 思路:先獲取字符,判斷字符,取消事件// char getKeyChar() char ch = e.getKeyChar();// System.out.println(ch);if(!(ch>='0' && ch<='9')){e.consume();}}});// 設置窗體可見f.setVisible(true);}} 多級菜單package cn.itcast_09;import java.awt.FlowLayout;import java.awt.Frame;import java.awt.Menu;import java.awt.MenuBar;import java.awt.MenuItem;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;import java.io.IOException;/** 多級菜單*/public class FrameDemo {public static void main(String[] args) {// 創建窗體對象并設置屬性final Frame f = new Frame("多級菜單");f.setBounds(400, 200, 400, 300);f.setLayout(new FlowLayout());final String name = f.getTitle();// 創建菜單欄MenuBar mb = new MenuBar();// 創建菜單Menu m1 = new Menu("文件");Menu m2 = new Menu("更改名稱");// 創建菜單項final MenuItem mi1 = new MenuItem("好好學習");final MenuItem mi2 = new MenuItem("天天向上");MenuItem mi3 = new MenuItem("恢復標題");MenuItem mi4 = new MenuItem("打開記事本");MenuItem mi5 = new MenuItem("退出系統");// 誰添加誰呢m2.add(mi1);m2.add(mi2);m2.add(mi3);m1.add(m2);m1.add(mi4);m1.add(mi5);mb.add(m1);// 設置菜單欄f.setMenuBar(mb);// 設置窗體關閉f.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});mi1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {f.setTitle(mi1.getLabel());}});mi2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {f.setTitle(mi2.getLabel());}});mi3.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {f.setTitle(name);}});mi4.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {Runtime r = Runtime.getRuntime();try {r.exec("notepad");} catch (IOException e1) {e1.printStackTrace();}}});mi5.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.exit(0);}});// 設置窗體可見f.setVisible(true);}}
?? 如何讓Netbeans的東西Eclipse能訪問。
?????? 在Eclipse中創建項目,把Netbeans項目的src下的東西給拿過來即可。
?????? 注意:修改項目編碼為UTF-8
??????
??MenuBar,Menu,MenuItem
先創建菜單條,再創建菜單,每一個菜單中建立菜單項。
也可以菜單添加到菜單中,作為子菜單。
通過setMenuBar()方法,將菜單添加到Frame中。
???
A:所謂IP地址就是給每個連接在Internet上的主機分配的一個32bit地址。按照TCP/IP規定,IP地址用二進制來表示,每個IP地址長32bit,比特換算成字節,就是4個字節。例如一個采用二進制形式的IP地址是“00001010000000000000000000000001”,這么長的地址,人們處理起來也太費勁了。為了方便人們的使用,IP地址經常被寫成十進制的形式,中間使用符號“.”分開不同的字節。于是,上面的IP地址可以表示為“10.0.0.1”。IP地址的這種表示法叫做“點分十進制表示法”,這顯然比1和0容易記憶得多。
B:IP地址的組成
IP地址 = 網絡號碼+主機地址
A類IP地址:第一段號碼為網絡號碼,剩下的三段號碼為本地計算機的號碼
B類IP地址:前二段號碼為網絡號碼,剩下的二段號碼為本地計算機的號碼
C類IP地址:前三段號碼為網絡號碼,剩下的一段號碼為本地計算機的號碼
特殊地址:
127.0.0.1 回環地址,可用于測試本機的網絡是否有問題. ping 127.0.0.1??
DOS命令 ipconfig:查看本機IP地址
xxx.xxx.xxx.0 網絡地址
xxx.xxx.xxx.255 廣播地址
A類????? 1.0.0.1---127.255.255.254???
(1)10.X.X.X是私有地址(私有地址就是在互聯網上不使用,而被用在局域網絡中的地址)??????????????????????????????????????????
(2)127.X.X.X是保留地址,用做循環測試用的。
B類????? 128.0.0.1---191.255.255.254?????
172.16.0.0---172.31.255.255是私有地址。169.254.X.X是保留地址。
C類????? 192.0.0.1---223.255.255.254?????
192.168.X.X是私有地址
D類???? 224.0.0.1---239.255.255.254 ???
E類????? 240.0.0.1---247.255.255.254?????
為了方便我們對IP地址的獲取和操作,java提供了一個類InetAddress 供我們使用。
? UDP
????????????? 將數據源和目的封裝成數據包中,不需要建立連接;每個數據報的大小在限制在64k;因無連接,是不可靠協議;不需要建立連接,速度快
TCP
????????????? 建立連接,形成傳輸數據的通道;在連接中進行大數據量傳輸;通過三次握手完成連接,是可靠協議;必須建立連接,效率會稍低
總結:
udp:
面向無連接。不可靠。速度快。將數據封包傳輸,數據包最大64k。
舉例:
聊天留言,在線視頻,視頻會議,發短信,郵局包裹。
tcp:面向連接。安全可靠效率稍低。通過三次握手確保連接的建立。
舉例:
下載,打電話,QQ聊天(你在線嗎,在線,就回應下,就開始聊天了)
?
??????
? Socket套接字:
網絡上具有唯一標識的IP地址和端口號組合在一起才能構成唯一能識別的標識符套接字。
Socket原理機制:
通信的兩端都有Socket。
網絡通信其實就是Socket間的通信。
數據在兩個Socket間通過IO傳輸。
???????
? ?
package cn.itcast_02;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;/** UDP協議發送數據:* A:創建發送端Socket對象* B:創建數據,并把數據打包* C:調用Socket對象的發送方法發送數據包* D:釋放資源*/public class SendDemo {public static void main(String[] args) throws IOException {// 創建發送端Socket對象// DatagramSocket()DatagramSocket ds = new DatagramSocket();// 創建數據,并把數據打包// DatagramPacket(byte[] buf, int length, InetAddress address, int port)// 創建數據byte[] bys = "hello,udp,我來了".getBytes();// 長度int length = bys.length;// IP地址對象InetAddress address = InetAddress.getByName("192.168.12.92");// 端口int port = 10086;DatagramPacket dp = new DatagramPacket(bys, length, address, port);// 調用Socket對象的發送方法發送數據包// public void send(DatagramPacket p)ds.send(dp);// 釋放資源ds.close();}}package cn.itcast_02;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;/** UDP協議接收數據:* A:創建接收端Socket對象* B:創建一個數據包(接收容器)* C:調用Socket對象的接收方法接收數據* D:解析數據包,并顯示在控制臺* E:釋放資源*/public class ReceiveDemo {public static void main(String[] args) throws IOException {// 創建接收端Socket對象// DatagramSocket(int port)DatagramSocket ds = new DatagramSocket(10086);// 創建一個數據包(接收容器)// DatagramPacket(byte[] buf, int length)byte[] bys = new byte[1024];int length = bys.length;DatagramPacket dp = new DatagramPacket(bys, length);// 調用Socket對象的接收方法接收數據// public void receive(DatagramPacket p)ds.receive(dp); // 阻塞式// 解析數據包,并顯示在控制臺// 獲取對方的ip// public InetAddress getAddress()InetAddress address = dp.getAddress();String ip = address.getHostAddress();// public byte[] getData():獲取數據緩沖區// public int getLength():獲取數據的實際長度byte[] bys2 = dp.getData();int len = dp.getLength();String s = new String(bys2, 0, len);System.out.println(ip + "傳遞的數據是:" + s);// 釋放資源ds.close();}}
? --------》待續
?
?
?
轉載于:https://www.cnblogs.com/yc74/p/5493377.html
總結
以上是生活随笔為你收集整理的JAVA笔记(十四)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: maven打包:找不到符号 符号: 方法
- 下一篇: aggregations 详解1(概述)