【第11天】Java的單例模式、介面以及Object類常用的方法
1 單例模式
-
什麼是設計模式?
一套被反覆使用、多數人知曉的、經過分類的、程式碼設計經驗的總結。為了程式碼可重用性、讓程式碼更容易被他人理解、保證程式碼可靠性。世上本沒有設計模式,用的人多了,也便有了設計模式。 -
什麼是單例模式?
用來控制一個類有且只有一個物件的設計模式。
1.1 醉漢式
- 實現的注意事項:
- 私有化構造方法,以防止類體之外別人隨意建立物件,通過new Moon獲取到。
- 建立一個私有的、靜態的、屬於本類型別的物件。
- 提供一個公共的、靜態的、返回本類型別物件的方法。
public class Test{
public static void main(String[] args){
//驗證:
Moon x = Moon.getMm();
Moon y = Moon.getMm( );
Moon z = Moon.getMm();
System.out.println(x == y);
System.out.println(y == z);
}
}
//只有一個月亮
class Moon{
//私有化構造方法
//private:私有化構造方法,防止類體之外別人隨意new Moon物件獲取到
private Moon(){}
//private:防止類體之外別人隨意的對靜態屬性賦值,若設定為“Moon.mm = null;”就尷尬了
//static:防止死迴圈* Moon-> mm -> mm -> mm......
private static Moon mm = new Moon();
//getter
//public:封裝
//static: 防止方法依賴於物件,只有類才可以定義,
public static Moon getMm(){//月亮.getMm();
return mm;
}
}
-
為何要“static Moon mm = new Moon();”靜態化mm物件?
- 類似
class Student{ int age = 20; }
-
這樣會造成如圖的死迴圈,所以一定要使用static讓每次呼叫都共享一個成員moon。
class Moon{ Moon moon = new Moon(); }
1.2 懶漢式
因為還沒有學習到執行緒控制,所以這裡的懶漢式是不完善的,學習執行緒後再補全這裡的內容。
class Moon{
private Moon(){}
private static Moon only;
public static Moon getOnly(){
//當被呼叫時物件是否存在,如果不存在,new一個返回,如果存在則直接返回
//如果這樣寫,呼叫時可能會出現執行緒併發問題,需要繼續完善
if(only == null){
only = new Moon();
return only;
}else{
return only;
}
}
}
1.3 兩者之間的區別
醉漢式不管用不用,總是先例項化,可能會浪費記憶體,但是隻要呼叫就很快返回這個例項。效率較高,但記憶體空間佔用較大。
懶漢式注重記憶體管理,節省記憶體空間,如果不呼叫就不建立。效率較低,但記憶體空間佔用較小。
2 介面(interface)
相當於工業生產中的規範。它是Java四大類*中的第二大型別,與abstract抽象類一樣,它不能建立物件。
-
Java四大類(是編譯之後生成對應的.class檔案的那種,注意與資料型別作區分)
- 類(class)
- 介面(interface)
- 列舉(enum)
- 註解(@interface)
-
interface如何定義?
interface XXX{
//屬性:
//接口裡面的屬性預設加上三個修飾符:
//public static final
int x = 45;
String y = "etoak";
//方法:返回型別 方法簽名();
//接口裡面的方法預設加上兩個修飾符:
//public abstract
void test();
int show();
}
類實現介面之後,值不需要修改了,方法需要覆蓋(重寫)後再呼叫執行。
- 例:
public class TestInterface{
public static void main(String[] args){
//一個USB裝置接入電腦
USBKeyboard df = new USBKeyboard();
Computer dell = new Computer();
dell.open(df);
}
}
/**
USB裝置和電腦之間的關係:
先制定所有USB裝置都需要尊重的規範/條約 -> 介面 interface
找到一個型別的開發滿足這樣的規範 -> USB滑鼠 USB鍵盤
找到一個型別的開發使用這樣的規範 -> 電腦
*/
//指定所有USB裝置的規範/條約
interface USB{
//接口裡面定義屬性和方法
//標定電壓
//接口裡面的屬性預設加上三個修飾符:
//public static final
int v = 5;
//連線電腦的功能
//接口裡面的方法預設加上兩個修飾符:
//public abstract
void connect();
}
class USBKeyboard implements USB{
@Override
public void connect(){
System.out.println("USB鍵盤連線電腦的方法");
}
}
//類 implements 實現/遵循 介面規範
class USBMouse implements USB{
//當我們拿著一個類去實現一個介面的時候 需要給出介面
//裡面所有抽象方法的具體實現
@Override
public void connect(){
System.out.println("USB滑鼠連線電腦的方法");
}
}
class Computer{
public void open(USB x){
x.connect();
System.out.println("電腦開啟連線");
}
}
- 面試題
1 類與介面兩兩之間的關係:
類與類之間:繼承關係(extends)
介面與介面:繼承關係(extends)
類與介面:實現關係(implements)
另外
Java中的類只允許單根繼承
Java中的介面允許多重實現
也就是說Java中的類在繼承一個類的同時可以實現多個介面
2 從哪個版本開始,方法覆蓋的時候允許加@Override註解?
類和類之間的方法覆蓋:JDK5.0及以上
類和介面之間的方法覆蓋:JDK6.0及以上
4:介面和抽象類之間的區別?★
名稱 | 兩者之間的關係 | 單根繼承/多重實現 | 型別 | 對屬性的定義 | 對方法的定義 |
---|---|---|---|---|---|
介面 | 類implements(實現)介面 | 多重實現(一個類實現多個介面) | interface | 靜態的最終變數(public static final) | 抽象方法(public abstract) |
抽象類 | 類extends抽象類 | 單根繼承(只允許單繼承) | class | 普通屬性 | 抽象方法 + 普通方法 |
介面是對事物動作的抽象,而抽象類是對事物根源的抽象。 動作的抽象可以被不同事物的抽象共享,而事物的抽象屬性只能對一類事物使用,比如飛機和鳥都會飛,飛這個動作就可以抽象為一個介面的方法供飛機和鳥實現,只是實現的內容不同。但是飛機和鳥自身特有的屬性要定義在抽象類中。
關於介面和抽象類的區別理解,我找到了一篇能很全面並形象描述的文章,出自[email protected] 大神。
3 Object類常用的方法
Object(物件)類,是所有引用資料型別的直接父類或者間接父類(父類的父類)。每個類直接或者間接繼承了Object類,也就是說每個類建立之後預設都有自己的如下幾個方法。定義返回型別為Object的方法,如果使用其他引用型別接收,需要強轉。
- 存在一個許可權較小但功能較好的方法,如何將其許可權改大:
public class Test{
public static void main(String[] args){
}
}
class A{
protected void test(){
System.out.println("優秀的方法實現");
}
}
class B extends A{
//重寫將其訪問許可權改大
@Override
public void test(){
//直接使用super呼叫父類的test()
super.test();
}
}
3.1 clone()
使用Object類中clone()克隆出來的陣列、物件雖然內容與之前相同,但地址發生改變。
public class TestClone{//extends Object
public static void main(String[] args){
Sheep s1 = new Sheep("克隆羊母體");
Sheep s2 = s1.clone();
System.out.println(s1 == s2);
}
}
class Sheep{//extends Object
String name;
public Sheep(String name){
this.name = name;
}
}
上面的程式碼報“錯誤: clone()可以在Object中訪問protected/不相容的型別”,是因為clone()沒有顯式重寫前,預設執行的是Object類中的clone()方法。
檢視Object類原始碼可得“protected native Object clone() throws CloneNotSupportedException”,protected意為可以在包(目錄)內或者包外的具有繼承關係的子類中使用,然而這裡是在TestClone類中訪問了Sheep類中的clone()方法,報錯。如果是在Sheep類呼叫Sheep類的clone()則是可以的。
結合前敘中改大許可權的辦法,我們可以在Sheep類中將clone()方法重寫,使其許可權增大,這樣就可以在TestClone類中訪問了。
改後:
public class TestClone{//extends Object
public static void main(String[] args) throws Exception{
Sheep s1 = new Sheep("克隆羊母體");
//呼叫的.clone()方法需要丟擲異常,在方法上丟擲
Sheep s2 = s1.clone();
System.out.println(s1 == s2);//--->false
}
}
//如果類能夠克隆,它需要滿足某個條約(實現Cloneable介面)
class Sheep implements Cloneable{//extends Object
String name;
public Sheep(String name){
this.name = name;
}
//這裡的返回型別使用了協變返回型別:任何Object類的子類都所以可以作為返回型別
//重寫Object類中的clone()方法,可以改大訪問許可權,在TestClone類中訪問到
//因為是super.直接呼叫了父類的clone(),所以異常丟擲需與父類相同或更小
@Override
public Sheep clone() throws CloneNotSupportedException{
//在子類呼叫父類的clone()幫助我們去克隆一個物件,與父類相同
Object obj = super.clone();
//返回子類Sheep型別的obj
return (Sheep)obj;
}
}
所以要使得類Sheep可以在TestClone類中呼叫其自身clone()方法,需要:
- 重寫父類Object的clone()
- 在Sheep類實現Cloneable介面
- 在TestClone這個需要訪問clone()方法的類丟擲一個異常
3.2 finalize()
物件的“遺言”方法,當一個物件要被gc執行緒回收時,會主動呼叫這個物件。
public class TestFinalize{
public static void main(String[] arfgs){
while(true){
Teacher tea = new Teacher();
//主動召喚gc執行緒進來回收
//System.gc();
}
}
}
class Teacher{//extends Object
public Teacher(){
System.out.println("建立Teacher的物件");
}
//記憶體快要滿了時,GC出來工作回收這個物件之前,執行這個方法
@Override
public void finalize(){
System.out.println("快要被GC回收了=======================");
}
}
- 如何主動召喚gc執行緒進來回收? 使用“System.gc();”
3.3 toString() (需重寫)
指定一個物件列印顯示的內容,當要列印一個引用型別的物件時,底層都會使用這個物件呼叫toString()。
- 在toString()沒有覆蓋(直接呼叫由Object類繼承來的方法)時列印:型別@XXX。如下例
public class TestToString1{
public static void main(String[] args){
String str = new String("張三");
System.out.println(str);//--->張三
System.out.println(str.toString());//--->張三
Student stu = new Student("張三");
System.out.println(stu);//--->[email protected]
System.out.println(stu.toString());//--->[email protected]
}
}
class Student{
String name;
public Student(String name){
this.name = name;
}
}
為何String的toString()、直接輸出可以獲得“張三”,而自定義的引用資料型別輸出的是地址?
因為String類重寫了父類Object類中的toString()方法,這樣在輸出其物件引用時,直接輸出其toString()方法返回的內容。Student類中未重寫該方法。
如果我們想要得到一條有用的資訊時,需要在我們定義的Object子類中重寫toString()。
public class TestToString2{
public static void main(String[] args){
String str = new String("張三");
System.out.println(str);//--->張三
System.out.println(str.toString());//--->張三
Student stu = new Student("張三");
System.out.println(stu);//--->張三
System.out.println(stu.toString());//--->張三
}
}
class Student{
String name;
public Student(String name){
this.name = name;
}
//重寫了Object類中的toString()方法
@Override
public String toString(){
return name;
}
}
例題:
//使用toString()打印出有用的資訊
public class ExampleToString{
public static void main(String[] args){
Person x = new Person("張三",33,'男');
System.out.println(x);
Person y = new Person("李四",28,'女');
System.out.println(y);
}
}
class Person{
String name;
int age;
char gender;
public Person(String name,int age,char gender){
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public String toString(){
return name + (gender == '男'? "先生":"女士" ) + "今年" + age + "歲";
}
}
3.4 equals()(需重寫)
制定一個型別的比較規則,當我們想要將記憶體裡面不同的兩個物件視為“邏輯”相等物件的時候,需要重寫equals方法,來定義我們自己的相等法則。
在equals()沒有被覆蓋時,比較兩個物件地址。如下例
public class TestEquals1{
public static void main(String[] args){
String x = new String("OK");
String y = new String("OK");
System.out.println(x == y);//判斷地址是否相同--->false
System.out.println(x.equals(y));//判斷內容是否相同--->true
Student a = new Student("張三");
Student b = new Student("張三");
System.out.println(a == b);//判斷地址是否相同--->false
System.out.println(a.equals(b));//判斷地址是否相同--->false
}
}
class Student{//extends Object
String name;
public Student(String name){
this.name = name;
}
}
Student類中重寫equals(),使Student的引用呼叫equals()時判斷名字是否相同。也可以傳入更多的值,判斷多個條件符合來返回equals()方法的結果(邏輯相等),此處只是舉一個例子。
public class TestEquals2{
public static void main(String[] args){
String x = new String("OK");
String y = new String("OK");
System.out.println(x == y);//判斷地址是否相同--->false
System.out.println(x.equals(y));//判斷內容是否相同--->true
Student a = new Student("張三");
Student b = new Student("張三");
System.out.println(a == b);//判斷地址是否相同--->false
System.out.println(a.equals(b));//判斷內容是否相同--->true
}
}
class Student{//extends Object
String name;
public Student(String name){
this.name = name;
}
//重寫:只要兩個學生的姓名一樣就視為相等物件
@Override
public boolean equals(Object obj){//stu1.equals(stu2)
//先找到要比較的兩個學生物件
Student s1 = this;//當前呼叫該方法的物件
Student s2 = (Student)obj;//要比較的第二個學生物件
//分別通過物件得到他們的姓名
String x = s1.name;
String y = s2.name;
//使用String的equals(),判斷學生的姓名內容是否相同
return x.equals(y);
}
}
但上面這樣重寫的方式並不是特別健壯和高效,需要注意新增一些條件判斷以備出現的不健壯情況,並提升效率。
public class TestEquals3{
public static void main(String[] args){
String x = new String("OK");
String y = new String("OK");
System.out.println(x == y);//判斷地址是否相同--->false
System.out.println(x.equals(y));//判斷內容是否相同--->true
Student a = new Student("張三");
Student b = new Student("張三");
System.out.println(a == b);//判斷地址是否相同--->false
System.out.println(a.equals(b));//判斷內容是否相同--->true
}
}
class Student{//extends Object
String name;
public Student(String name){
this.name = name;
}
//重寫:只要兩個學生的姓名一樣就視為相等物件
@Override
public boolean equals(Object obj){
//對引數obj排空判斷
//引數是Object類,任何一個引用資料型別預設值都是null
//為了保證程式碼健壯,此處不考慮呼叫物件的引用為空的情況,只考慮引數列表內的情況
if(obj == null) return false;
//由於引數是Object型別,導致所有的引用資料型別都可以傳進來
//但學生物件就應該和學生類的物件比較,instanceof的意思是判斷obj是否是Student類的物件
//為了保證程式碼健壯
if(!(obj instanceof Student)) return false;
//為了保證程式更加高效
if(this == obj) return true;
//先找到要比較的兩個學生物件
Student s1 = this;//當前呼叫該方法的物件
Student s2
相關推薦
【第11天】Java的單例模式、介面以及Object類常用的方法
1 單例模式
1.1 醉漢式
1.2 懶漢式
2 介面(interface)
3 Object類常用的方法
3.1 clone()
3.2 finalize()
【第22天】Java執行緒基礎、併發集合
1 概述
2 生命週期(五狀態圖)
3 如何定義一個執行緒
4 控制執行緒執行的方法
1 概述 程式當中一條獨立的執行線索。Java中的主執行緒是一個J
【第17天】Java集合(四)---Sorted介面實現的TreeSet集合及單值型別集合總結
1 TreeSet簡介
2 基本用法與特點
3 制定單值比較規則
3.1 自然排序(compareTo(Object obj))
3.2 定製排序(定義比較器類)
3.2.1 普通類內定義
【第12天】Java集合(一)
1 什麼是集合?有哪些分類
1.1 JCF(Java Collections FrameWork)
2 ArrayList ★
2.1 包裝類
2.2 基本用法與特點
2.3 刪除元素
【第10天】Java面向物件的高階特徵(修飾符的介紹)
1 訪問許可權
2 static
2.1 靜態成員
2.2 程式碼塊
2.3 載入順序
3 final
4 abstract
1 訪問許可權
修飾符:(√:可訪問
【第9天】Java中字串的處理
1 String類的初始化、與StringBuffer類和StringBuilder類三者的區別
1.1 String類的初始化兩種方式
1.2 String類、StringBuffer類和StringBuilder類三者的區別
【第8天】Java方法過載、方法重寫(覆蓋)、構造方法及引數傳值
1 方法過載(overload)
2 方法重寫(覆蓋)(override)
3 構造方法
4 引數傳值
1 方法過載(overload)
方法過載的作用?
同時滿足使用者的不同需求。 同一個方法,使用者可以傳入不同
【第18天】Java集合(五)---Map介面概述及Map介面實現的HashMap類、SortedMap介面實現的TreeMap類
1 Map的通性
1.1 基本用法與特點
1.2 遍歷
2 HashMap集合的特性
3 TreeMap集合的特性
1 Map的通性
&nb
【第16天】Java集合(三)---Set介面實現的HashSet集合
1 HashSet簡介
2 基本用法與特點
3 HashSet的唯一性
4 增刪改時需要注意
1 HashSet簡介
作為Set介面的一個實現類,特
【第13天】Java集合(二)---手動實現ArrayList及其他List介面實現的集合
1 ArrayList(續)
1.1 擴容與縮容
1.2 手動實現ArrayList
2 Vector
3 LinkedList
4 Stack
1 ArrayList(續)
1.1
【Java 單例模式】Java 單例模式在多執行緒環境中可能存在的問題
在多執行緒環境下,使用延遲載入的方式實現單例模式,會出現錯誤。
例如,使用如下方式實現單例類:
package study20170307;
/**
* Created by apple on 17/3/7.
*/
public class Sin
【Velocity官方指南】使用單例模式還是非單例模式
譯者:大胃 原文連結
從Velocity 1.2以後的版本,開發者對於Velocity引擎的使用有了兩種方式,單例模型(Singleton)以及多個獨立例項模型。Velocity的核心部分也採用了這兩種模型,目的是為了讓Velocity可以更容易與你的JAVA應用相整合。
單例模式(Sin
【php】利用單例模式設計資料庫連線Model類
之前在《【php】利用php的建構函式與解構函式編寫Mysql資料庫查詢類》(點選開啟連結)寫過的Mysql資料庫查詢類還不夠完美,利用《【Java】單例模式》(點選開啟連結)介紹的思想可以將這個資料庫連結類搞成單例,不會因為多個使用者訪問網站就建立一個數據庫查詢例項,拖慢
【第20、21天】Java的內部類、異常處理機制
1 內部類
1.1 成員內部類
1.2 靜態內部類
1.3 區域性內部類
1.4 匿名內部類
2 異常處理機制
2.1 異常類的體系結構及各部分介紹
2.2
【直播預告】:Java Spring Boot開發實戰系列課程【第11講】:訊息中介軟體 RabbitMQ 與api原始碼解析
內容概要:mq訊息中介軟體在高併發系統架構中扮演關鍵角色,阿里雙11高併發使用了mq技術。本次課程一起學習最新Java Spring Boot 2.0、RabbitMQ中介軟體的最新特性與實戰應用,同樣會分析核心api原始碼。主講人:徐雷(阿里雲棲特邀Java專家)直播時間:2019年1月8日 週二 今晚20
【java設計模式初探0】_單例模式
在java的幾十種設計模式中,可能單例模式算是最容易理解的吧!因為不論是目前的我自己,還是偶爾面試的別人,能稍微講清楚的,基本就是單例模式。
什麼叫單例模式?顧名思義,就是單一的例項,唯一的例項。也就是說對於某個java類來說,他的例項物件最多隻能建立一個。
Django 【第五篇】ORM單表增刪改查
contains 字典 exc 單表 pytho name屬性 作者 包括 刪除數據 一、添加表記錄
對於單表有兩種方式
# 添加數據的兩種方式
# 方式一:實例化對象就是一條表記錄
Frank_obj = models.Student(name ="海
C語言Windows程序開發—MessageBox函數介紹【第01天】
class ner windows.h can lpctstr 字符串 return napi ext (一)MessageBox函數的參數介紹:
1 int MessageBox (
2 HWND hWnd, //彈出Messa
C語言Windows程序開發—TextOut函數介紹【第02天】
菜單 stock rec null 主函數 callback 介紹 關閉 windows.h (一)TextOut函數的參數介紹:
1 BOOL TextOut ( //如果函數調用成功,返回TRUE,否則,返回FALSE
2 H
【Python設計模式】02 單例模式
1. python實現經典的單例模式
python通過覆蓋__new__()方法來控制物件的建立。 if not hasattr(cls, ‘instance’):方法hasattr用於檢視物件cls是否具有屬性instance, 該屬性的作用是檢查該類是否已經生成了一個物件。