@autowired的註解能夠在不一樣層次上應用:java
工做原理:node
4個專門用於處理註解的Bean後置處理器。linux
當 Spring 容器啓動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中全部 Bean,當發現 Bean 中擁有@Autowired 註解時就找到和其匹配(默認按類型匹配)的 Bean,並注入到對應的地方中去。 源碼分析以下:c++
經過org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor能夠實現依賴自動注入。經過這個類來處理@Autowired和@Value這倆Spring註解。它也能夠管理JSR-303的@Inject註解(若是可用的話)。在AutowiredAnnotationBeanPostProcessor構造函數中定義要處理的註解:git
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
...
/** * Create a new AutowiredAnnotationBeanPostProcessor * for Spring's standard {@link Autowired} annotation. * <p>Also supports JSR-330's {@link javax.inject.Inject} annotation, if available. */
@SuppressWarnings("unchecked")
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
...
}
複製代碼
以後,有幾種方法來對@Autowired註解進行處理。github
第一個,private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz)解析等待自動注入類的全部屬性。它經過分析全部字段和方法並初始化org.springframework.beans.factory.annotation.InjectionMetadata類的實例來實現。web
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
Class<?> targetClass = clazz;
do {
final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
//分析全部字段
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//findAutowiredAnnotation(field)此方法後面會解釋
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
//分析全部方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isWarnEnabled()) {
logger.warn("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
//返回一個InjectionMetadata初始化的對象實例
return new InjectionMetadata(clazz, elements);
}
...
/** * 'Native' processing method for direct calls with an arbitrary target instance, * resolving all of its fields and methods which are annotated with {@code @Autowired}. * @param bean the target instance to process * @throws BeanCreationException if autowiring failed */
public void processInjection(Object bean) throws BeanCreationException {
Class<?> clazz = bean.getClass();
InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
try {
metadata.inject(bean, null, null);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
"Injection of autowired dependencies failed for class [" + clazz + "]", ex);
}
}
複製代碼
InjectionMetadata類包含要注入的元素的列表。注入是經過Java的API Reflection (Field set(Object obj, Object value) 或Method invoke(Object obj,Object ... args)方法完成的。此過程直接在AutowiredAnnotationBeanPostProcessor的方法中調用public void processInjection(Object bean) throws BeanCreationException。它將全部可注入的bean檢索爲InjectionMetadata實例,並調用它們的inject()方法。spring
public class InjectionMetadata {
...
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate) {
if (debug) {
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
}
//看下面靜態內部類的方法
element.inject(target, beanName, pvs);
}
}
}
...
public static abstract class InjectedElement {
protected final Member member;
protected final boolean isField;
...
/** * Either this or {@link #getResourceToInject} needs to be overridden. */
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
//具體的注入看此處咯
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
...
}
}
複製代碼
AutowiredAnnotationBeanPostProcessor類中的另外一個重要方法是private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao)。它經過分析屬於一個字段或一個方法的全部註解來查找@Autowired註解。若是未找到@Autowired註解,則返回null,字段或方法也就視爲不可注入。編程
@Nullable
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
if (ao.getAnnotations().length > 0) {
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
if (attributes != null) {
return attributes;
}
}
}
return null;
}
複製代碼
問1:如何查看當前的Linux服務器運行級別?設計模式
答:who -r 和 runlevel 命令能夠用來查看當前的Linux服務器的運行級別。
Linux的運行級別有7種:
0 全部進程將被終止,機器將有序的中止,關機時系統處於這個運行級別
1 單用戶模式。用於系統維護,只有少數進程運行,同時全部服務也不啓動
2 多用戶模式。和運行級別3同樣,只是網絡文件系統(NFS)服務沒被啓動
3 多用戶模式。容許多用戶登陸系統,是系統默認的啓動級別 4 留給用戶自定義的運行級別
5 多用戶模式,而且在系統啓動後運行X-Window,給出一個圖形化的登陸窗口
6 全部進程被終止,系統從新啓動
問2:如何查看Linux的默認網關?
答:用route -n 或 netstat -nr命令,咱們能夠查看默認網關,除了默認網關信息,這兩個命令還能夠顯示當前的路由表。
問3:cpio 命令是什麼?
答:cpio命令是經過重定向的方式將文件進行打包備份,還原恢復的工具,它能夠解壓以「.cpio」或者「.tar」結尾的文件。
詳細請查看cpio命令詳解
問4:patch命令是什麼,如何使用?
答:顧名思義,patch命令用來用來將補丁寫進文本文件裏面。patch命令一般是接受diff的輸出,並把文件的舊版本轉換爲新版本。
舉個例子:
diff -Naur old_file new _file > diff_file 舊文件和新文件要麼都是單個的文件要麼就是包含文件的目錄,-r參數支持目錄樹遞歸。一旦diff文件建立好,咱們就能夠在舊文件上打上補丁,把他變成新文件:
patch < diff_file 問題5:如何識別Linux系統中指定文件(/etc/fstab)的關聯包(即查詢一個已經安裝的文件屬於哪一個軟件包)?
答:命令rmp -qf /etc/fstab能夠列出提供」/etc/fstab」這個文件的包。
RPM是RedHat Package Manager(RedHat軟件包管理工具)相似Windows裏面的「添加/刪除程序」
rpm 執行安裝包,二進制包(Binary)以及源代碼包(Source)兩種。二進制包能夠直接安裝在計算機中,而源代碼包將會由RPM自動編譯、安裝。源代碼包常常以src.rpm做爲後綴名。
經常使用命令組合:
- ivh:安裝顯示安裝進度--install--verbose--hash
- Uvh:升級軟件包--Update;
- qpl:列出RPM軟件包內的文件信息[Query Package list];
- qpi:列出RPM軟件包的描述信息[Query Package install package(s)];
- qf:查找指定文件屬於哪一個RPM軟件包[Query File];
- Va:校驗全部的RPM軟件包,查找丟失的文件[View Lost];
- e:刪除包
rpm -q samba //查詢程序是否安裝
rpm -ivh /media/cdrom/RedHat/RPMS/samba-3.0.10-1.4E.i386.rpm //按路徑安裝並顯示進度
rpm -ivh --relocate /=/opt/gaim gaim-1.3.0-1.fc4.i386.rpm //指定安裝目錄
rpm -ivh --test gaim-1.3.0-1.fc4.i386.rpm    //用來檢查依賴關係;並非真正的安裝;
rpm -Uvh --oldpackage gaim-1.3.0-1.fc4.i386.rpm //新版本降級爲舊版本
rpm -qa | grep httpd      #[搜索指定rpm包是否安裝]--all搜索*httpd*
rpm -ql httpd         #[搜索rpm包]--list全部文件安裝目錄
rpm -qpi Linux-1.4-6.i368.rpm #[查看rpm包]--query--package--install package信息
rpm -qpf Linux-1.4-6.i368.rpm #[查看rpm包]--file
rpm -qpR file.rpm       #[查看包]依賴關係
rpm2cpio file.rpm |cpio -div #[抽出文件]
rpm -ivh file.rpm  #[安裝新的rpm]--install--verbose--hash
rpm -ivh
rpm -Uvh file.rpm #[升級一個rpm]--upgrade
rpm -e file.rpm #[刪除一個rpm包]--erase
複製代碼
經常使用參數:
Install/Upgrade/Erase options:
-i, --install install package(s)
-v, --verbose provide more detailed output
-h, --hash print hash marks as package installs (good with -v)
-e, --erase erase (uninstall) package
-U, --upgrade=<packagefile>+ upgrade package(s)
--replacepkge 不管軟件包是否已被安裝,都強行安裝軟件包
--test 安裝測試,並不實際安裝
--nodeps 忽略軟件包的依賴關係強行安裝
--force 忽略軟件包及文件的衝突
Query options (with -q or --query):
-a, --all query/verify all packages
-p, --package query/verify a package file
-l, --list list files in package
-d, --docfiles list all documentation files
-f, --file query/verify package(s) owning file
複製代碼
問題6:Linux系統中的/proc文件系統有什麼用?
答:/proc文件系統是一個基於內存的文件系統,維護着有關於當前正在運行的內核狀態信息,其中包括CPU、內存、分區劃分、 I/O地址、直接內存訪問通道和正在運行的進程。這個文件系統所表明的並非各類實際存儲信息的文件,他們指向的是內存裏的信息。 /proc文件系統是由系統自動維護的。
問題7: 如何在/usr目錄下找出大小超過10MB的文件?
答:find /usr -size +10M
問題8:如何在/home目錄下找出120天以前被修改過的文件?
答:find /home -mtime +120
問題9:如何在/var目錄下找出90天以內未被訪問過的文件?
答:find /var ! -atime -90
問題10:在整個目錄樹下查找文件「core」,若是發現則無需提示,直接刪除他們?
答:find / -name core -exec rm {} ; , -exec 參數後面跟的是command命令,它的終止是以;爲結束標誌的,因此這句命令後面的分號是不可缺乏的,考慮到各個系統中分號會有不一樣的意義,因此前面加反斜槓。
問題11:strings命令有什麼做用?
答:strings命令用來提取和顯示非文本文件中的文本字符串。
問題12:tee過濾器有什麼做用?
答:tee過濾器用來想多個目標發送輸出的內容。若是用於管道的話,他能夠將輸出複製一份到文件,兵複製另一份到屏幕上(或一些其餘的程序)。
詳細請查看tee命令詳解
問題13:export PS1="PWD:" 這條指令是在作什麼?
答:這條export命令會更改登陸提示符來顯示用戶名、本機名、和當前的工做目錄。
問題14:ll | awk ‘{print $3, 「owns」, $9}’這條命令是在作什麼?
答:會顯示這些文件的名稱和他們的擁有者。
詳細請看awk命令詳解
問題15:Linux中at命令有什麼用?
答:at命令用來安排一個程序在將來的作一次性執行。因此有提交的任務都會被放在/var/spool/at目錄下,而且到了執行時間的時候經過atd守護進程來執行。
詳細請看at命令詳解
從命令行搜索文件,它能夠用於根據各類搜索標準查找文件,如權限、用戶全部權、修改數據/時間 find [searching path] [options] [keyword]
有兩種類型的Internet協議(IP)。它們是TCP或傳輸控制協議和UDP或用戶數據報協議。TCP是面向鏈接的——一旦創建了鏈接,數據就能夠雙向發送。UDP是一種更簡單、無鏈接的Internet協議。
TCP和UDP是兩種傳輸層協議,在internet上普遍用於將數據從一個主機傳輸到另外一個主機。
首先,TCP表明傳輸控制協議,UDP表明用戶數據報協議,二者都被普遍用於構建Internet應用程序。
1)面向鏈接和無鏈接 它們之間的首要區別是TCP是面向鏈接的協議,而UDP是無鏈接協議。這意味着在客戶端和服務器之間創建鏈接,而後才能發送數據。鏈接創建過程也稱爲TCP握手,其中控制消息在客戶端和服務器之間互換。附加圖像描述了TCP握手的過程,例如,在客戶端和服務器之間交換哪些控制消息。
客戶端是TCP鏈接的發起者,它將SYN消息發送到正在偵聽TCP端口的服務器。服務器接收併發送SYN-ACK消息,該消息再次由客戶端接收並使用ACK進行響應。一旦服務器收到此ACK消息,就創建TCP鏈接並準備好進行數據傳輸。另外一方面,UDP是無鏈接協議,在發送消息以前未創建點對點鏈接。這就是爲何UDP更適合於消息的多播分發,單個傳輸中的一對多數據分佈。
2)可靠性 TCP提供了傳輸保證,即保證使用TCP協議發送的消息被傳遞到客戶端。若是消息在傳輸過程當中丟失,則使用重發恢復消息,這由TCP協議自己處理。另外一方面,UDP是不可靠的,它不提供任何交付保證。數據報包可能在傳輸過程當中丟失。這就是爲何UDP不適合須要保證交付的程序。
3)順序 除了提供保證以外,TCP還保證消息的順序。消息將以服務器發送的相同順序發送給客戶端,儘管它們可能會按照順序發送到網絡的另外一端。TCP協議將對您進行全部的排序和排序。UDP不提供任何排序或排序保證。
數據報包能夠以任何順序到達。這就是爲何TCP適用於須要按順序交付的應用程序,儘管也有基於UDP的協議,它經過使用序列號和重發(例如TIBCO Rendezvous,其實是一個基於UDP的應用程序)來提供排序和可靠性。
4)數據邊界 TCP不保留數據邊界,UDP保留。在傳輸控制協議中,數據以字節流的形式發送,而且沒有向信號消息(段)邊界傳輸任何明顯的指示。在UDP上,數據包是單獨發送的,只有到達時才檢查其完整性。數據包有必定的邊界,這在接收端套接字上的讀取操做將產生一個完整的消息,就像它最初發送的那樣。儘管TCP也會在組裝完全部字節後發送完整的消息。消息在發送以前存儲在TCP緩衝區中,以優化網絡帶寬的使用。
5)速度 總之,TCP很慢,UDP很快。因爲TCP必須建立一個鏈接,確保有保證和有序的交付,因此它所作的工做要比UDP多得多。
6)重量型vs輕量型 因爲上面提到的開銷,與輕量級UDP協議相比,傳輸控制協議被認爲是重量級的。UDP的一個簡單的咒語,在不須要任何建立鏈接和保證交付或訂單保證的狀況下發送消息,使其重量更輕。這也反映在它們的頭大小中,頭大小用於攜帶元數據。
7)頭 TCP的頭比UDP大。TCP報頭的通常大小是20字節,大於8字節的兩倍,是UDP數據報報頭的大小。TCP報頭包含序列號、Ack編號、數據偏移、保留、控制位、窗口、緊急指針、選項、填充、校驗和、源端口和目標端口。而UDP頭只包含長度、源端口、目的端口和校驗和。下面是TCP和UDP報頭的樣子:
8)擁堵或流量控制 TCP流量控制。TCP須要三個包來設置套接字鏈接,而後才能發送任何用戶數據。TCP處理可靠性和擁塞控制。另外一方面,UDP沒有流控制選項。
9)使用和應用 在internet上TCP和UDP在哪裏使用?在瞭解了TCP和UDP之間的關鍵差別以後,咱們能夠很容易地得出適合它們的狀況。因爲TCP提供了交付和排序保證,所以它最適合須要高可靠性的應用程序,並且傳輸時間相對不那麼重要。
而UDP更適合須要快速、高效傳輸的應用程序,如遊戲。UDP的無狀態特性對於回答大量客戶端的小查詢的服務器也頗有用。在實踐中,TCP被用於金融領域,例如FIX protocol是基於TCP的協議,UDP在遊戲和娛樂站點中被大量使用。
10)基於TCP和UDP的協議 基於TCP的高級端協議的最好例子之一是HTTP和HTTPS,這在internet上隨處可見。實際上,您所熟悉的大多數常見協議(如Telnet、FTP和SMTP)都是基於傳輸控制協議的。UDP沒有像HTTP那樣流行的東西,可是UDP是在DHCP(動態主機配置協議)和DNS(域名系統)這樣的協議中使用的。另外一些基於用戶數據報協議的協議是簡單網絡管理協議(SNMP)、TFTP、BOOTP和NFS(早期版本)。
順便說一句,在基於Linux的TCP/UDP應用程序中工做時,最好記住基本的網絡命令,例如telnet和netstat,它們對於調試或排除任何鏈接問題都有很大的幫助。
這就是TCP和UDP協議的不一樣之處。永遠記得要提到TCP是鏈接的,可靠的,緩慢的,提供保證的交付和保持消息的順序,而UDP是無鏈接的,不可靠的,沒有訂購保證,可是一個快速的協議。TCP開銷也比UDP高得多,由於它比UDP每包傳輸更多的元數據。
值得一提的是,傳輸控制協議的報頭大小爲20字節,而用戶數據報協議的報頭大小爲8字節。使用TCP,若是你不能承受丟失任何消息,而UDP更適合高速數據傳輸,在這種狀況下,一個數據包的丟失是能夠接受的,例如視頻流或在線多人遊戲。
在給出使用Spring框架的好處以前,讓咱們簡單地描述一下Spring。
Spring框架是一種用於企業Java (JEE)的功能強大的輕量級應用程序開發框架。
如下是Spring的好處:
這是一個使用鏈表實現堆棧的Java程序。堆棧是一個內存區域,它包含任何函數使用的全部局部變量和參數,並記住調用函數的順序,以便函數返回正確。每次調用一個函數時,它的局部變量和參數都被「推到」堆棧上。當函數返回時,這些局部變量和參數將被「彈出」。所以,程序堆棧的大小隨着程序的運行而不斷波動,可是它有一些最大的大小。堆棧是第一個(LIFO)抽象數據類型和線性數據結構的最後一個。鏈表是由一組節點組成的數據結構,它們共同表明一個序列。這裏咱們須要應用鏈表的應用來執行棧的基本操做。 下面是使用鏈表實現堆棧的Java程序的源代碼。Java程序被成功編譯並在Windows系統上運行。程序輸出以下所示。
/* * Java Program to Implement Stack using Linked List */
import java.util.*;
/* Class Node */
class Node {
protected int data;
protected Node link;
/* Constructor */
public Node() {
link = null;
data = 0;
}
/* Constructor */
public Node(int d,Node n) {
data = d;
link = n;
}
/* Function to set link to next Node */
public void setLink(Node n) {
link = n;
}
/* Function to set data to current Node */
public void setData(int d) {
data = d;
}
/* Function to get link to next node */
public Node getLink() {
return link;
}
/* Function to get data from current Node */
public int getData() {
return data;
}
}
/* Class linkedStack */
class linkedStack {
protected Node top ;
protected int size ;
/* Constructor */
public linkedStack() {
top = null;
size = 0;
}
/* Function to check if stack is empty */
public boolean isEmpty() {
return top == null;
}
/* Function to get the size of the stack */
public int getSize() {
return size;
}
/* Function to push an element to the stack */
public void push(int data) {
Node nptr = new Node (data, null);
if (top == null)
top = nptr;
else
{
nptr.setLink(top);
top = nptr;
}
size++ ;
}
/* Function to pop an element from the stack */
public int pop() {
if (isEmpty() )
throw new NoSuchElementException("Underflow Exception") ;
Node ptr = top;
top = ptr.getLink();
size-- ;
return ptr.getData();
}
/* Function to check the top element of the stack */
public int peek() {
if (isEmpty() )
throw new NoSuchElementException("Underflow Exception") ;
return top.getData();
}
/* Function to display the status of the stack */
public void display() {
System.out.print("\nStack = ");
if (size == 0)
{
System.out.print("Empty\n");
return ;
}
Node ptr = top;
while (ptr != null)
{
System.out.print(ptr.getData()+" ");
ptr = ptr.getLink();
}
System.out.println();
}
}
複製代碼
// x is the element to be pushed and s is stack
push(s, x)
1) Let size of q be s.
2) Enqueue x to q
3) One by one Dequeue s items from queue and enqueue them.
// Removes an item from stack
pop(s)
1) Dequeue an item from q
複製代碼
import java.util.LinkedList;
import java.util.Queue;
public class stack {
Queue<Integer> q = new LinkedList<Integer>();
// Push operation
void push(int val) {
// get previous size of queue
int size = q.size();
// Add current element
q.add(val);
// Pop (or Dequeue) all previous
// elements and put them after current
// element
for (int i = 0; i < size; i++)
{
// this will add front element into
// rear of queue
int x = q.remove();
q.add(x);
}
}
// Removes the top element
int pop() {
if (q.isEmpty())
{
System.out.println("No elements");
return -1;
}
int x = q.remove();
return x;
}
// Returns top of stack
int top() {
if (q.isEmpty())
return -1;
return q.peek();
}
// Returns true if Stack is empty else false
boolean isEmpty() {
return q.isEmpty();
}
// Driver program to test above methods
public static void main(String[] args) {
stack s = new stack();
s.push(10);
s.push(20);
System.out.println("Top element :" + s.top());
s.pop();
s.push(30);
s.pop();
System.out.println("Top element :" + s.top());
}
}
複製代碼
This method makes sure that newly entered element is always at the front of ‘q1’, so that pop operation just dequeues from ‘q1’. ‘q2’ is used to put every new element at front of ‘q1’.
push(s, x) // x is the element to be pushed and s is stack
1) Enqueue x to q2
2) One by one dequeue everything from q1 and enqueue to q2.
3) Swap the names of q1 and q2
// Swapping of names is done to avoid one more movement of all elements
// from q2 to q1.
pop(s)
1) Dequeue an item from q1 and return it.
複製代碼
/* Program to implement a stack using
two queue */
#include<bits/stdc++.h>
using namespace std;
class Stack
{
// Two inbuilt queues
queue<int> q1, q2;
// To maintain current number of
// elements
int curr_size;
public:
Stack()
{
curr_size = 0;
}
void push(int x)
{
curr_size++;
// Push x first in empty q2
q2.push(x);
// Push all the remaining
// elements in q1 to q2.
while (!q1.empty())
{
q2.push(q1.front());
q1.pop();
}
// swap the names of two queues
queue<int> q = q1;
q1 = q2;
q2 = q;
}
void pop(){
// if no elements are there in q1
if (q1.empty())
return ;
q1.pop();
curr_size--;
}
int top()
{
if (q1.empty())
return -1;
return q1.front();
}
int size()
{
return curr_size;
}
};
// driver code
int main()
{
Stack s;
s.push(1);
s.push(2);
s.push(3);
cout << "current size: " << s.size()
<< endl;
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;
cout << "current size: " << s.size()
<< endl;
return 0;
}
// This code is contributed by Chhavi
Output :
current size: 3
3
2
1
current size: 1
複製代碼
In push operation, the new element is always enqueued to q1. In pop() operation, if q2 is empty then all the elements except the last, are moved to q2. Finally the last element is dequeued from q1 and returned.
push(s, x)
1) Enqueue x to q1 (assuming size of q1 is unlimited).
pop(s)
1) One by one dequeue everything except the last element from q1 and enqueue to q2.
2) Dequeue the last item of q1, the dequeued item is result, store it.
3) Swap the names of q1 and q2
4) Return the item stored in step 2.
// Swapping of names is done to avoid one more movement of all elements
// from q2 to q1.
複製代碼
/* Program to implement a stack
using two queue */
#include<bits/stdc++.h>
using namespace std;
class Stack
{
queue<int> q1, q2;
int curr_size;
public:
Stack()
{
curr_size = 0;
}
void pop()
{
if (q1.empty())
return;
// Leave one element in q1 and
// push others in q2.
while (q1.size() != 1)
{
q2.push(q1.front());
q1.pop();
}
// Pop the only left element
// from q1
q1.pop();
curr_size--;
// swap the names of two queues
queue<int> q = q1;
q1 = q2;
q2 = q;
}
void push(int x)
{
q1.push(x);
curr_size++;
}
int top()
{
if (q1.empty())
return -1;
while( q1.size() != 1 )
{
q2.push(q1.front());
q1.pop();
}
// last pushed element
int temp = q1.front();
// to empty the auxiliary queue after
// last operation
q1.pop();
// push last element to q2
q2.push(temp);
// swap the two queues names
queue<int> q = q1;
q1 = q2;
q2 = q;
return temp;
}
int size()
{
return curr_size;
}
};
// driver code
int main()
{
Stack s;
s.push(1);
s.push(2);
s.push(3);
s.push(4);
cout << "current size: " << s.size()
<< endl;
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;
cout << "current size: " << s.size()
<< endl;
return 0;
}
複製代碼
public class Stack<E> {
private E[] arr = null;
private int CAP;
private int top = -1;
private int size = 0;
@SuppressWarnings("unchecked")
public Stack(int cap) {
this.CAP = cap;
this.arr = (E[]) new Object[cap];
}
public E pop() {
if(this.size == 0){
return null;
}
this.size--;
E result = this.arr[top];
this.arr[top] = null;//prevent memory leaking
this.top--;
return result;
}
public boolean push(E e) {
if (!isFull())
return false;
this.size++;
this.arr[++top] = e;
return false;
}
public boolean isFull() {
if (this.size == this.CAP)
return false;
return true;
}
public String toString() {
if(this.size==0){
return null;
}
StringBuilder sb = new StringBuilder();
for(int i=0; i<this.size; i++){
sb.append(this.arr[i] + ", ");
}
sb.setLength(sb.length()-2);
return sb.toString();
}
public static void main(String[] args) {
Stack<String> stack = new Stack<String>(11);
stack.push("hello");
stack.push("world");
System.out.println(stack);
stack.pop();
System.out.println(stack);
stack.pop();
System.out.println(stack);
}
}
複製代碼
能夠
/** * Created by mac on 2018/7/7. */
public interface interfacea {
public void print();
}
/** * Created by mac on 2018/7/7. */
public class test implements interfacea{
@Override
public void print() {
System.out.println("implements interfaces from test");
}
}
/** * Created by mac on 2018/7/7. */
public class testchild extends test{
public static void main(String[] args) {
testchild testchild = new testchild();
testchild.print();
}
}
output:
implements interfaces from test
複製代碼
Spring 框架就像一個家族,有衆多衍生產品例如 boot、security、jpa等等。但他們的基礎都是Spring 的 ioc和 aop ioc 提供了依賴注入的容器 aop ,解決了面向橫切面的編程,而後在此二者的基礎上實現了其餘延伸產品的高級功能。Spring MVC是基於 Servlet 的一個 MVC 框架 主要解決 WEB 開發的問題,由於 Spring 的配置很是複雜,各類XML、 JavaConfig、hin處理起來比較繁瑣。因而爲了簡化開發者的使用,從而創造性地推出了Spring boot,約定優於配置,簡化了spring的配置流程。
說得更簡便一些:Spring 最初利用「工廠模式」(DI)和「代理模式」(AOP)解耦應用組件。你們以爲挺好用,因而按照這種模式搞了一個 MVC框架(一些用Spring 解耦的組件),用開發 web 應用( SpringMVC )。而後有發現每次開發都寫不少樣板代碼,爲了簡化工做流程,因而開發出了一些「懶人整合包」(starter),這套就是 Spring Boot。
Spring MVC的功能
Spring MVC提供了一種輕度耦合的方式來開發web應用。
Spring MVC是Spring的一個模塊,式一個web框架。經過Dispatcher Servlet, ModelAndView 和 View Resolver,開發web應用變得很容易。解決的問題領域是網站應用程序或者服務開發——URL路由、Session、模板引擎、靜態Web資源等等。
Spring Boot的功能
Spring Boot實現了自動配置,下降了項目搭建的複雜度。
衆所周知Spring框架須要進行大量的配置,Spring Boot引入自動配置的概念,讓項目設置變得很容易。Spring Boot自己並不提供Spring框架的核心特性以及擴展功能,只是用於快速、敏捷地開發新一代基於Spring框架的應用程序。也就是說,它並非用來替代Spring的解決方案,而是和Spring框架緊密結合用於提高Spring開發者體驗的工具。同時它集成了大量經常使用的第三方庫配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot應用中這些第三方庫幾乎能夠零配置的開箱即用(out-of-the-box),大部分的Spring Boot應用都只須要很是少許的配置代碼,開發者可以更加專一於業務邏輯。
Spring Boot只是承載者,輔助你簡化項目搭建過程的。若是承載的是WEB項目,使用Spring MVC做爲MVC框架,那麼工做流程和你上面描述的是徹底同樣的,由於這部分工做是Spring MVC作的而不是Spring Boot。
對使用者來講,換用Spring Boot之後,項目初始化方法變了,配置文件變了,另外就是不須要單獨安裝Tomcat這類容器服務器了,maven打出jar包直接跑起來就是個網站,但你最核心的業務邏輯實現與業務流程實現沒有任何變化。
Spring 是一個「引擎」;
Spring MVC 是基於Spring的一個 MVC 框架 ;
Spring Boot 是基於Spring4的條件註冊的一套快速開發整合包。