主頁 > 後端開發 > JAVA---抽象類和介面基礎知識詳解(及兩者異同點)

JAVA---抽象類和介面基礎知識詳解(及兩者異同點)

2021-12-12 07:55:32 後端開發

在本篇博客中將介紹JAVA里抽象類介面的基礎知識以及兩者的異同點,在有繼承和多型的基礎知識上學習會更好~

目錄

抽象類基礎知識

抽象類的定義、創建等基礎

抽象類的幾點說明(一)

為何使用抽象方法

抽象類的幾點說明(二)

介面基礎知識

介面的定義、創建等基礎

介面具體例題詳析(重要)

關于介面的幾點說明

抽象類和介面的異同點

抽象類與介面的相同點

抽象類與介面的相異點(重要)

抽象類與介面的區別運用


抽象類基礎知識

在學習完繼承和多型的知識后,我們對“類”的運用又有了更深的了解,那么在Java中還存在一個重要且特殊的類--抽象類,為什么說特殊,因為Java中的抽象類是不可以用于創建物件的,但是它可以包含抽象方法,這些方法將在具體的子類中實作,注意具體和子類兩個關鍵字,下面是抽象類的具體定義:

在繼承的層次結構中,每個新的子類都使類變得更加明確和具體,如果從一個子類向父類追溯,類就會變得更通用,也就更加不明確,類的設計應該確保父類包含它的子類的共同特征,有時候,一個父類設計得非常抽象,以至于它都沒有任何具體的實體,這樣的類稱為抽象類(abstract class) 這里要記住它的特殊性!沒有任何實體!

抽象類的定義、創建等基礎

我們來舉個栗子,創建下面這樣一個GeometricObject (幾何)類,這個在上一篇博客中也有,用來引入講繼承(大概意思是定義一個幾何類,那么像Circle類和Rectangle類都可以從它衍生出來成為子類(并不是子集!))

public class GeometricObject  //創建這樣一個試用于所有幾何的大類,簡稱父類
{
	private String color = "white";        //一般設定為私有變數
	private boolean filled;               //布爾型別,是否填充
	private java.util.Date dateCreated;
	
	public GeometricObject()               //創建一個初始的或者是錯誤的幾何物件,初始建構式
	{
		dateCreated = new java.util.Date();//記錄創建時間
	}
	
	public GeometricObject(String color,boolean filled) //創建一個初始的物件包含顏色和是否填充
	{
		dateCreated = new java.util.Date();  //更新創建時間
		this.color = color;
		this.filled = filled;
	}
	
	public String getColor()             //用戶想得知顏色可以回傳
	{
		return color;
    }
	
	public void setColor(String color)   //用戶在外部更改顏色
	{
		this.color = color;
	}
	
	public boolean isFilled()
	{
		return filled;
	}
	
	public void setFilled(Boolean filled)
	{
		this.filled = filled;
	}
	
	public java.util.Date getDateCreated()
	{
		return dateCreated;
	}
	
//回傳這個物件的基礎資訊,其實由前面學過的多載可知,我們這里是多載了toString這個函式,它的原始父類應該是在Object中
    @Override
	public String toString()              
	{
		return "created on " + dateCreated + "\ncolor: " + color + " and filled: " + filled;
	}
}

可以看到,GeometricObject類對幾何物件的共同特征進行了建模,那么假設我們寫了一個Circle類和Rectangle類(它的子類),然后它們都包含了分別用于計算圓和矩形的面積和周長的getArea()方法和getPerimeter()方法,

因為可以計算所有幾何物件的面積和周長,所以最好在GeometricObject類中定義getArea()和getPerimeter()方法,但是!這些方法不能在GeometricObject類中實作,因為它們的實作取決于幾何物件的具體型別!這樣的方法就稱之為抽象方法(abstract method),在方法頭中使用abstract修飾符表示,一旦在GeometricObject類中定義了這些方法后,GeometricObject就成為了一個抽象類,在類的頭部使用abstract修飾符表示該類為抽象類,我們現在給出新的GeometricObject類的定義:(很重要!認真看!)

public abstract class GeometricObject  //抽象類前也要用abstract關鍵詞定義
{
	private String color = "white";
	private boolean filled;
	private java.util.Date dateCreated;
	
	//創建一個初始的未設定的幾何物件/構造方法
	protected GeometricObject()              //抽象類的構造方法定義為protected,因為它只被子類使用
	{ 
		dateCreated = new java.util.Date();
	}
	
	//創建一個初始的帶設定的幾何物件/這個也是構造方法,看方法頭!
	protected GeometricObject(String color, boolean filled)
	{
		dateCreated = new java.util.Date();
		this.color = color;
		this.filled = filled;
	}
	
	//接下來顏色和是否填充的獲取器和修改器方法和之前的都一樣
	//下面這些就是抽象方法!也是使得這個類成為抽象類的原因!
	
	public abstract double getArea();
	public abstract double getPerimeter();
	//注意!這里都不需要寫怎么計算或者回傳什么,因為并不確定具體的幾何物件,也就是具體的子類!
}

抽象類的幾點說明(一)

其實上面的注釋中也提到了關于抽象類的重要知識點,我們在這里再總結一下:

1.抽象類和常規類很像,但是不能使用new運算子創建它的實體!抽象方法只有定義而沒有實作!它的實作由子類提供!一個包含抽象方法的類必須宣告為抽象類

2.抽象類的構造方法定義為protected,因為它只被子類使用!創建一個具體子類的實體時,其父類的構造方法被呼叫以初始化父類中定義的資料域!

那么Circle類在上一篇博客的繼承中也有,這時候繼承這個新定義的GeometricObject類就可以除錯試試,寫法上是沒有任何差別的,呼叫定義抽象方法即可,同學們可以回上一篇看看

為何使用抽象方法

其實既然提到子類既然和之前的創建書寫都沒有什么不一樣,那么為什么要在GeometricObject類中定義方法getArea()和getPerimeter()為抽象的,而不是在每個子類中定義他們,這樣有什么好處?

我們來看一下下面這個代碼,程式創建了兩個幾何物件:一個圓和一個矩形,呼叫equalArea方法來檢查它們的面積是否相同,然后呼叫displayGeometricObject方法來顯示它們:

public class TestGeometricObject
{
	public static void main(String[] args)
	{
		GeometricObject geoObject1 = new Circle(5);         //向上轉型!
		GeometricObject geoObject2 = new Rectangle(5, 3);  //向上轉型!
		
		System.out.println("The two objects hava the same area? " + equalArea(geoObject1, geoObject2));
		
		displayGeometricObject(geoObject1);
		displayGeometricObject(geoObject2);
	}
	
	public static boolean equalArea(GeometricObject object1, GeometricObject object2)
	{
		return object1.getArea() == object2.getArea();
	}

    public static void displayGeometricObject(GeometricObject object)
    {
	    System.out.println();
	    System.out.println("The area is " + object.getArea());
	    System.out.println("The perimeter is " + object.getPerimeter());
    }
}

//輸出結果是:
//The two objects have the same area? false
//The area is 78.53981633974483
//The perimeter is 31.41592653589793
//The area is 13.0
//The perimeter is 16.0

要注意的是:Circle類和Rectangle類中重寫了定義在GeometricObject類中的getArea()和fetPerimeter()方法,從陳述句第五到六行可以看出,創建了一個新的圓和一個新的矩形,并把它們賦值給變數geoObject1和geoObject2,這兩個變數都是GeometricObject型別的,這是向上轉型!!!

我們這里分析一下,當呼叫equalArea方法時,由于geoObject1是一個圓,所以object1.getArea()使用的是Circle類定義的getArea()方法,而另一個是一個矩形,所以它呼叫時使用的是Rectangle類中定義的getArea方法,類似地在呼叫displayGeometricObject方法時,呼叫的那些物件方法都是子類中定義的同名的重寫方法,這也表明,JVM在運行時根據呼叫該方法的實際物件的型別來動態地決定呼叫哪一個方法 (可以回顧多型的相關知識)

注意!如果GeometricObject類中沒有定義getArea()等這些抽象方法,就不能再該程式中定義equalArea方法來計算這兩個幾何物件的面積是否相同,所以這可以看做是定義抽象方法的好處

抽象類的幾點說明(二)

下面是關于抽象類值得注意的幾點:

1.抽象方法不能包含在非抽象類中,如果抽象父類的子類不能實作所有的,注意是所有的抽象方法,那么子類也必須定義為抽象的,換句話說,在繼承自抽象類的非抽象子類中,必須實作所有的抽象方法,還要注意到,抽象方法是非靜態的!

2.象類不能使用new運算子來初始化,也就是說它沒有實體,但是!仍然可以定義它的構造方法!這個構造方法在它的子類的構造方法中呼叫,比如我們上面的GeometricObject類的構造方法在Circle類和Rectangle類中呼叫,也就是回顧多型的向上轉型知識!

3.包含抽象方法的類必須是抽象的,然而,可以定義一個不包含抽象方法的抽象類,這個抽象類用于作為定義新子類的基類,

4.子類可以重寫父類的方法并將它定義為抽象的,這很少見,但是它在當父類的方法實作在子類中變得無效時是很有用的,那么也可以知道在這種情況下,這個子類也必須被定義為抽象的,

5.即是子類的父類是具體的,但是這個子類也可以是抽象的!例如,大類基類Object是具體的,但是它的子類比如我們定義的GeometricObject可以是抽象的,

6.不能使用new運算子從一個抽象類創建一個實體,但是抽象類可以用作一種資料型別,比如下面的陳述句創建一個元素是GeometricObjecy型別的陣列是正確的:

GeometricObject[] objects = new GeometricObject[10];

然后可以創建一個GeomettricObject的實體,并將它的參考賦值給陣列,如下:

object[0] = new Circle();

建議這里可以回顧多型的知識~

介面基礎知識

我們現在學習下介面的基礎知識,其實介面在許多方面都與抽象類很相似,它也是一種與類相似的結構,用于為物件定義共同的操作,但是!它的目的是指明相關或者不相關類的物件的共同行為,例如,使用適當的介面,可以指明這些物件是課比較的、可食用的或者可克隆的,我們下面會深入理解這些話的意思,

介面的定義、創建等基礎

為了區分介面和類(我們上面也說了介面只是一種與類相似的結構),Java用下面的語法來定義介面:

modifier /*介面類別,公用的還是私有的等等*/ interface InterfaceName /*介面名稱*/
{
	//Constant declarations  常數宣告
	//Abstract method signatures  抽象方法簽名
}

//interface為介面關鍵字,同抽象類的abstract一樣
//下面是一個介面的例子:

public interface Edlib
{
	// Describle hou to eat
	public abstract String howToEat();   //必須包含抽象方法
}

從上述定義代碼也可以看出,介面包括常量和抽象方法(只能包括抽象方法,下面有總結),但是這里提一點,Cloneable介面是一個特殊情況,這個介面是空的,實作Cloneable介面的類標記為可克隆的,而且它的物件可以使用在Object類中定義的clone()方法克隆,感興趣的同學可以去了解一下,

在Java中,介面被看做是一種特殊的類,就像常規類一樣,每個介面都被編譯為獨立的位元組碼檔案,使用介面或多或少有點像使用抽象類,例如,可以使用介面作為參考變數的資料型別或型別轉換的結果等,與抽象類相同的是,不能使用new運算子創建介面的實體!!我們也可以理解為因為介面中是包含抽象方法的!它需要依靠具體的類實作!!

介面具體例題詳析(重要)

現在通過下面的這個包含介面實作(介面用上面的那個Edlib)、抽象類、常規類以及測驗等等的代碼例題來理解介面的運用與意義:

abstract class Animal            //由上節學習過的知識可知,我們創建了一個抽象類(必包含抽象方法)
{
	private double weight;       //和常規類一樣,私有成員變數、修改器訪問器等方法
	
	public double getWeight()
	{
		return weight;
	}
	
	public void setWeight(double weight)
	{
		this.weight = weight;
	}
	
	public abstract String sound();  //包含的抽象方法,回傳動物的聲音的方法,其依賴于具體的子類(哪種動物)實作
}

//使用Edlib介面來指定一個物件是否是可食用的,使用implements關鍵字讓物件所屬的類實作這個介面
class Chicken extends Animal implements Edible 
{
	@Override                        //方法重寫前的關鍵字,可得知我們這里重寫了介面中的抽象方法,這是否是必須的?
	public String howToEat()         //若不重寫它或者說不需要它,你對這個子類使用介面的意義又何在?
	{
		return "Chicken: Fry it";
	}
	
	@Override
	public String sound()
	{
		return "Chicken: cock-a-doodle-doo";
	}
}

//這個Tiger類就僅僅是繼承自Animal類了,并沒有使用Edlib介面
class Tiger extends Animal
{
	@Override
	public String sound()           //從上節抽象類知識可知,繼承自抽象類的子類必須要重寫所有的抽象方法!
	{
		return "Tigher: RROOAARR";
	}
}

//注意!我們上面是繼承自抽象類Animal的子類Chicken去和介面連接
//而在這里Fruit類為什么要被定義為abstract的?還是說它就是一個抽象類連接介面?
abstract class Fruit implements Edlib
{
	//創建一些資料域,訪問器和修改器方法
}

class Apple extends Fruit
{
	@Override
	public String howToEat()
	{
		return "Apple: Make apple cider";
	}
}

class Orange extends Fruit
{
	@Override
	public String howToEat()
	{
		return "Orange: Make orange juice";
	}
}
//很顯然,繼承自Fruit的子類Apple和Orange有了“重寫howToEat的資格”

//現在測驗一下這些類和介面,觀察輸出結果
public class TestEdible 
{
	public static void main(String[] args)
	{
		//利用ArrayList來創建這些物件,更加方便,這是向上轉型!最后的執行方法取決于物件的實際型別!可以回顧多型知識!
		Object[] objects = {new Tiger(), new Chicken(), new Apple()};
		
		//回圈測驗,注意判別條件
		for (int i = 0;i < objects.length;i++)
		{
			if (objects[i] instanceof Edible)                          //這里使用instanceof關鍵字來判斷從屬關系
				System.out.println(((Edible)objects[i]).howToEat());   //這種格式是怎樣的?
			
			if (objects[i] instanceof Animal)
				System.out.println(((Animal)objects[i]).sound());
		}
	}
}

//輸出的結果是:
//Tiger: RROOAARR              它沒有Edlib介面,不輸出howToEat,它屬于Animal的子類,輸出聲音
//Chiken: Fry it               它有Edlib介面,輸出howToEat
//Chicken: cock-a-doodle-doo   它屬于Animal的子類,輸出聲音
//Apple: Make apple cider      它有Edlib介面,輸出howToEat,它不屬于Animal的子類,不輸出聲音

這個例子使用了多個類和介面,通過下面的UML圖來看看

關于介面的幾點說明

仔細看一遍代碼和注解后,其實我們很容易理解捋清這些類的繼承、介面關系等,捋清了這些后,我們總結一下在該例題中出現的知識點和需要注意的地方:

1.可以使用Edlib介面來指定一個物件是否是可食用的,這需要使用implements關鍵字讓物件所屬的類實作這個介面,比如我們這里的Chicken類和Fruit類實作了Edible介面

2.類和介面之間的關系稱為介面繼承,因為介面繼承和類繼承本質上是相同的,所以我們將它們都簡稱為繼承,像實作多型的條件之一就是必須有繼承關系,這里的繼承包括介面繼承

3.注意!當一個類實作介面時,該類實作定義在介面中的所有方法(不管是什么方法),在這里,Fruit類實作了Edible,但是!因為它沒有實作howToEat方法,所以Fruit類必須定義為abstract,這就是原因!正因如此,Fruit的具體子類必須實作howToEat方法,理解!不然他們也要被定義為抽象類!

強調:類與類之間也好,類與介面之間也罷,這些繼承、多型的關系一定要搞清楚,比如一個類是可以隨意定義的還是必須有某種關鍵字的,這樣我們自己才不會混亂,也不至于出錯

4.介面中的所有的資料域都是public static final 而且所有的方法都是public abstract(這也是介面區別于抽象類的關鍵之一!抽象類只需包含抽象方法即可,其他型別的方法是允許有的),所以Java允許忽略這些修飾符,比如下列在介面中的定義都是等價的:

public static final int k = 1; public abstract void p(); 等價于 int k = 1; void p();

抽象類和介面的異同點

抽象類與介面的相同點

其實在剛開始學習介面的程序中,就有一直提到介面其實和抽象類在使用上是比較相似的,這里總結幾點:

1.它們都是用來指定多個物件的共同特征的,即都是Java提供的對現實世界中的物體進行抽象的兩種機制

2.抽象類與介面都不能被實體化,即不能使用new運算子來創建它們的實體

3.在抽象類與介面中所列的所有抽象方法(當然介面中只含有抽象方法)都必須在別的地方中被重寫,如果達不到所有或者說沒有被重寫,那么它必須也定義為抽象的(例題中有說)

4.介面與類都可以定義一種型別,一個介面型別的變數可以參考任何實作該介面類的實體,如果一個類實作了一個介面,那么這個介面就類似于該類的一個父類,這也就是為什么叫做介面繼承的原因,也就是說可以將介面當做一種資料型別使用,將介面型別的變數轉換為它的子類,反過來也可以

其實學習了多型的相關知識(上一篇博客中),這句話很容易理解,我們也可以結合下面這個圖掌握,假設c是圖中Class2的一個實體,那么c也是Object、Class1、Interface1、Interface1_1、Interface1_2、Interface2_1和Interface2_2的實體

以上這些及上面的抽象類與介面的知識點中都是兩者極大的相似性,通過上面Edible介面的例題中也可以看到(我有在例題中做注釋),過多的相同點這里就不再贅述

抽象類與介面的相異點(重要)

雖說兩者相同處眾多,但其實在上面的學習程序里提及到的很多要點中我們也能感受到兩者在語法和使用意義上的多處不同

從根本上來說,抽象類是類,而介面不是(當然我們時常也將它當成一種特殊的類),它的目的是為了給其他類提供行為說明,包括抽象類,比如上面例題中的 abstract class Fruit implements Edible 就是很好地說明這一點(這里是因為沒有重寫Edible中的抽象方法而被定義為抽象類),很多地方也可以看出介面與類的不同,比如類的關鍵字是class,而介面的是interface,介面中的方法只有方法頭加分號結尾(因為都是抽象方法),沒有方法主體,而類中的不是......

從語法層面來說兩者也有以下不同:

更詳細一點可以總結為:

上面兩張表格就很詳盡地說明了抽象類與介面的從多個方面的不同,介面的語法從變數方法的類別等很多方面都比抽象類嚴格得多,這些也強調過很多遍了,現在我們著重看一下兩者在繼承方面的區別

一個類可以實作多個介面,但是只能繼承一個父類(比如抽象類),也就是說我們在學繼承關系的時候也提到,Java只允許為類的繼承做單一繼承,但是允許使用介面做多重繼承!這樣就解決了只能單一繼承的弊端,卻又沒有破壞單一繼承,這就是介面的好處!

當然了,我們會利用extends關鍵字使某類繼承某類,我們同樣也可以使用extends關鍵字使介面繼承其他介面,介面與介面之間正同于類與類之間存在繼承關系的,這樣的介面稱為子介面 我們仔捋一捋類與類,介面與介面,類與介面之間的繼承關系:

1.類與類之間可以存在繼承,但是只能做單一繼承,即一個類只能繼承自一個父類,而一個父類可以有多個繼承它的子類

2.介面與介面之間可以存在繼承,且可以做多重繼承,即一個介面可以繼承自其他幾個介面,比如:

public interface NewInterFace extends Interface1,...,InterfaceN {

//constants and abstract methods }

在這里,NewInterFace是Interface1,...,InterfaceN的子介面,一個實作NewInterFace的類必須實作在NewInterFace,Interface1,...,InterfaceN中定義的抽象方法(注意細節!包括NewInterFace)

3.一個類可以實作(繼承)一個或多個介面,使用implements關鍵字(說得更準確一點是使用該關鍵字讓這個類實作這個介面),稱為介面繼承,但是!介面不能繼承類,只能繼承介面!

4.我們都知道所有的類都共享一個根類Object,但是!介面沒有共同的根!

抽象類與介面的區別運用

最后,其實在大多數情況下使用介面會比使用類更加地靈活,也更加推薦使用介面

因為介面可以為不相關類定義共同的父型別,這也是我們介紹介面時就說了它的目的:指明相關或者不相關類的物件的共同行為,而抽象類定義的抽象行為是為具有相關類而設定的

我們可以繼續上面那個Edible介面的例子來更加清楚使用抽象類和使用介面的區別,現在考慮Animal類,假設Animal類中定義了howToEat方法:

abstract class Animal
{
	public abstract String howToEat();
}

//Animal的兩個子類定義如下:
class Chicken extends Animal
{
	@Override
	public String howToEat()
	{
		return "Fry it";
	}
}

class Duck extends Animal
{
	@Override
	public String howToEat()
	{
		return "Roast it";
	}
}

假設給定這個繼承體系結構,多型使你可以在一個型別為Animal的變數中保存Chicken物件或Duck物件的參考,(多型--向上轉型)如:

public static void main(String[] args)
{
	Animal animal = new Chicken();
	eat(animal);
	
	animal = new Duck();    //重新賦值新的物件,這個知識點講過很多了!
	eat(animal);
}

public static void eat(Animal animal)
{
	Ststem.out.println(animal.howToEat());
}

同樣的又是一句說過很多很多遍的話:

JVM會基于呼叫方法時所用的確切物件來動態地決定呼叫哪個howToEat方法(回顧多型的知識)

可以定義Animal的一個子類,但這里有個限制條件,那就是該子類必須是另一種動物,但是新問題產生了:如果一種動物不可食用,那么它繼承Animal類就不合適了,因為我們在這里定義的抽象類就是Animal類,它的子類必須重寫它的所有方法,這個很容易理解,

而介面完全沒有這種問題,介面比類擁有更多的靈活性,因為不用使所有東西都屬于同一個型別的類,可以在介面中定義howToEat()方法,然后把它當做其他類的共同父型別,

/* 這個代碼就像我們寫在介面的那個一樣(這里就不寫了)(∩_∩) */

要表示一個可食用物件的類,只需讓該類實作Edible介面即可,順理成章地,這個類就成了Edible型別的子型別,任何Edible物件都可以被傳遞以呼叫howToEat方法,我的意思是通過向上轉型定義一個型別為Edible的變數去參考物件

到此本篇的內容就全部結束了,逐一學懂抽象類介面(當然如果繼承和多型的知識掌握得很好那學起來就相當容易),每個總結都寫在文章里了,這樣區別兩者的異同也會輕車熟路,很深刻不會搞混,同的到底是在哪些地方同,不同的地方還是非常明顯,一用起來就知道了,所以還是要多實踐多寫代碼,加油!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/379474.html

標籤:java

上一篇:資料結構 Java資料結構 二叉樹

下一篇:(環境搭建+復現)CVE-2021-44228 Apache Log4j 遠程代碼執行漏洞

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more