不要一味地迷信,要善于質疑,善于打破。這應該是我們在學習框架時應該保持的心態。Hibernate 是所有 JDBC 框架中封裝最高的、使用起來最便利的框架之一。對于初學者而言,要么在感嘆它的神奇,要么敬畏它的存在。但是,作為一個真正的開發者,應該有破有立的想法。本節課程試圖通過一個簡易的 JDBC 框架的實現流程描述,讓大家更清晰地了解 Hibernate 框架的設計過程。TIps: 框架的編寫是一個比較復雜的過程,并不是一言兩語能說清楚的,本文中的代碼介于偽代碼和真實代碼之間 ,僅僅用來幫助大家理解 Hibernate 的框架基礎原理。
棧和隊列在我們自己的開發工作中使用是相對比較少的,但是對它們的實際應用卻隨處可見:我們的開發工具會對括號 “(” 關閉進行匹配校驗,就是在輸入左括號 “(” 時將其壓入棧內,在輸入右括號 “)” 時從棧中取出并進行匹配校驗我們在進行一系列操作后想要撤回上一步操作,也是從我們的操作記錄棧中取出了之前操作的歷史記錄關于迷宮的解法也用到了棧,用于在使用 “窮舉解法” 時記錄前面的嘗試記錄隊列因為可以完美模擬排隊場景,因此在餐廳叫號程序、銀行醫院的排隊系統中都會用到隊列結構。
Hibernate 只是解決 JDBC 的問題,在項目中,不可避免的需要和其它框架進行整合。如 Spring 之流,這里面會有一個很大的坑,就是版本兼容問題。典型的表現就是明明添加了相應的包,但是,出現 class not found。這時就要考慮是否是版本之間的兼容問題。這個坑有的時候很讓人迷惑,明明剛剛添加了相應的包,卻告知不存在相應的類。Spring Boot 提供了 DATA JPA 實現,本質上是使用 Hibernate 的持久化功能。Spring Boot 開箱即用,很好解決了版本的兼容性問題。建議大家使用。
ruby-sass 為我們提供了一個抽象的基類 Sass::Importers::Base ,我們可以通過它來自定義導入器,擴展的子類的路徑名需要使用 URL 格式,不過這需要很強的 Ruby 語言基礎,這里我們就暫時不舉例子了,否則看著會很迷惑,還有就是 ruby-sass 已經逐漸被官方棄用,所以你僅需要了解下就好。
從編碼層面上講,就是如何在 Student 類 與 Address 類 之間體現出數據庫表中數據之間的關系。先從 Student 類 中開始,在 Student 類 中添加一個屬性字段。private Address address;address 屬性是一個 Address 類類型,數據庫不認得這玩意兒,Hibernate 表示開始要一個頭兩個大了,眩暈啦。null 你先進入學生表,然后根據學生表中的 addressId 進入到地址表,找到對應數據。Hibernate 又沒有讀心術,它如何知道你心里所想。所以,需要通過 XML 或注解語法把開發者的想法告訴 Hibernate:private Address address;@OneToOne(targetEntity = Address.class)@JoinColumn(name = "addressId")public Address getAddress() {return address;}@OneToOne 注解告訴 Hibernate :address 屬性的值要麻煩您先找到 學生表的 addressId,再辛苦去一下 地址表,把對應的地址信息查詢出來;@JoinColumn:告訴 Hibernate 帶著 addressId 到地址表中查找。主配置文件中添加如下信息:<property name=*"hbm2ddl.auto"*>create</property><mapping class=*"com.mk.po.Student"* /><mapping class=*"com.mk.po.Address"* />在 Hibernate 創建完畢后,添加幾條測試數據,操作完成后別忘記改回來。此處操作自動完成!相信聰明如你,一定沒問題。<property name="hbm2ddl.auto">update</property>
說實話,這個問題確實比較難以回答,我們先來看下百度百科對算法的定義:算法(Algorithm)是指解題方案的準確而完整的描述,是一系列解決問題的清晰指令,算法代表著用系統的方法描述解決問題的策略機制簡單點說算法就是解決一個問題的步驟或者方法。比如針對去上班這個問題,我們的步驟是這樣:首先是出門走路到地鐵站,然后坐地鐵到里公司最近的地鐵口下,最后走路到公司。這樣一個過程,可以稱之為完成這個上班任務的一個算法。但是很明顯,去上班的算法有很多種,并不止坐地鐵這一種,我們可以打的去公司、坐公交去公司等等,這樣不同的步驟也對應著不同的算法。這些方式有好又有壞,有快也有慢,同樣算法也是一樣有好有壞有快有慢的。同一個問題,有多種解決方法,也就是多種算法,不同的算法之間也會好壞之分。但是不管算法如何定義,它一定要具備以下五個特征才能稱之為算法:有窮性:算法必須能在有限步驟之后終止。無窮無盡執行下去,那根本不是解決問題的辦法,也就不能稱之為解決該問題的方法;確切性:算法的每一步必須要有確定的含義;輸入項:算法需要有輸入或者說初始條件。比如我們上班的算法,我們的初始條件就是從家出發;輸出項:算法必須要有一個或者多個輸出。比如我們上班的算法,輸出項就是順利到達公司;可行性:算法必須是可以實現的步驟。那種天馬行空、無法實現的方法就不能稱之為算法了。如果坐著宇宙飛碟去上班,這顯然不切實際,當然也就不能成為之上班的一個算法了。
介紹語法之前先看一個簡單的 demo:1067是不是看起來有點眼熟,沒錯,它就是基于 XML 語法格式。math 元素之最頂層的根元素,每個實例都必須包含在 math標簽內,一個 math 元素不能包含另一個 math 元素。
調用方和方法之間有參數的傳遞時,要注意方法傳值問題。
除了上面代碼中使用的最基本的 AtomicInteger (int)、AtomicInteger ()、 set () 、get () 和 decrementAndGet () 方法之外,我們還需要掌握其他幾組核心方法的使用。下面逐個介紹。getAndAdd (int) 方法與 AddAndGet (int) 方法第 1 個方法是先獲取原值,之后再對原值做增加。注意獲取的值是變更之前的值。而第 2 個方法正好相反,是先對原值做增加操作之后再獲取更新過的值。AtomicInteger atomicInteger = new AtomicInteger();System.out.println(atomicInteger.get()); // 0System.out.println(atomicInteger.getAndAdd(10)); // 0,獲取當前值并加10System.out.println(atomicInteger.get()); // 10System.out.println(atomicInteger.addAndGet(20)); // 30,當前值先加20再獲取System.out.println(atomicInteger.get()); // 30getAndIncrement () 方法與 incrementAndGet () 方法第 1 個方法是先獲取值,之后再對原值做增 1 操作,注意獲取的值是變更之前的值。而第 2 個方法正好相反,是先對原值做增 1 的操作之后再獲取更新過的值。AtomicInteger atomicInteger = new AtomicInteger();System.out.println(atomicInteger.get()); // 0System.out.println(atomicInteger.getAndIncrement()); // 0,獲取當前值并自增1System.out.println(atomicInteger.get()); // 1System.out.println(atomicInteger.incrementAndGet()); // 2,當前值先自增1再獲取System.out.println(atomicInteger.get()); // 2compareAndSet(int expect, int update)原值與 expect 相比較,如果不相等則返回 false 且原有值保持不變,否則返回 true 且原值更新為 update。AtomicInteger atomicInteger = new AtomicInteger(10);System.out.println(atomicInteger.get()); // 10int expect = 12;int update = 20;Boolean b =atomicInteger.compareAndSet(expect, update);System.out.println(b); // 10 不等于 12 不滿足期望,所以返回false,且保持原值不變System.out.println(atomicInteger.get());
上篇文章我們一起研究了 Kotlin 實現常見的單例模式,這篇文章我們將繼續 Kotlin 實現常用的代理模式。代理模式可以說很多初級中級開發者迷惑的設計模式。但是它確實應用很廣,不用多說大家非常熟悉的 Retrofit 框架,內部使用了動態代理設計模式,以注解的方式簡化網絡請求參數傳遞,從而實現更高解耦。然而在 Kotlin 中有天然支持的屬性代理語法特性,可以簡化 Java 中代理模式實現的模板代理。此外還會深入動態代理源碼分析,幫助大家復習和鞏固下動態代理的基本原理。
addColorStop() 方法給漸變添加一個由偏移值和顏色值指定的斷點。如果偏移值不在0到1之間,將拋出錯誤,如果顏色值不能被解析為有效的 CSS 顏色值 color,也將拋出錯誤。語法:void gradient.addColorStop(offset, color);變量說明:變量名類型是否必須說明offsetNumber是偏移值,0到1之間的值,超出范圍將拋出錯誤。colorstring是顏色值。
我們給 name 綁定了一個 handler 方法,之前我們寫的 watch 方法其實默認寫的就是這個handler。當 name 發生改變時, handler 方法就會執行。579代碼解釋:第 7-11 行,我們定義了偵聽器 name。它是一個對象,當 name 發生變化的時候,會調用 handler 的方法。。
我們知道人類是通過語言進行溝通的。比如,帥哥 A 說:“慕課網的課程都很棒!”。而美女 B 是 imooc 迷,隨聲附和道:“嗯,確實!”。然而美女 C 完全不了解 imooc, 她可能默不作聲,或者反問:“慕課網是什么?”。這意味著,人們的溝通是基于一定的前提假設的,是基于一些大家都能理解的、約定俗成的規定的。我們把這些約定或者規則叫做協議(Protocol)。兩臺計算機之間的通信也是模擬人類交流的,通信之前也需要有一些約定,也就是說要提前設計好協議。計算機網絡協議的規模非常龐大,數據包的收發過程也非常復雜。為了使計算機網絡容易理解、傳播和實現,科學家們對網絡進行了分層設計,并對其進行了標準化,最終形成了經典的 ISO/OSI 參考模型和 TCP/IP 參考模型。
在 Java 5.0 后,可以使用eunm關鍵字來定義一個枚舉類,比較便捷,推薦大家使用這個方法來定義枚舉類。通常需要以下幾個步驟:使用enum關鍵字定義枚舉類,這個類隱式繼承自java.lang.Enum類;在枚舉類內部,提供當前枚舉類的多個對象,多個對象之間使用逗號分割,最后一個對象使用分號結尾;聲明枚舉類的屬性和構造方法,在構造方法中為屬性賦值;提供 getter 方法,由于Enum類重寫了 toString()方法,因此一般不需要我們自己來重寫。具體實例如下:/** * @author colorful@TaleLin */public class EnumDemo2 { public static void main(String[] args) { Sex male = Sex.MALE; // 打印 Sex 對象 System.out.println(male); // 打印 getter方法的值 System.out.println(male.getSexName()); System.out.println(Sex.FEMALE.getSexName()); System.out.println(Sex.UNKNOWN.getSexName()); }}/** * 使用 enum 關鍵字定義枚舉類,默認繼承自 Enum 類 */enum Sex { // 1.提供當前枚舉類的多個對象,多個對象之間使用逗號分割,最后一個對象使用分號結尾 MALE("男"), FEMALE("女"), UNKNOWN("保密"); /** * 2.聲明枚舉類的屬性 */ private final String sexName; /** * 3.編寫構造方法,為屬性賦值 */ Sex(String sexName) { this.sexName = sexName; } /** * 4.提供getter */ public String getSexName() { return sexName; }}運行結果:MALE男女保密
Groovy 的方法定義跟 Java 比較類似,它的返回類型可以用返回值的類型或是def定義,也可以使用 public,static,private等修飾。如下我們定義一個add(int a)方法:class Example { static void main(String[] args) { def i = 3; println("befor add(i): "+ i); i=add(i); println("after add(i): "+i); } static def add(int a) { ++a; return a; };}執行結果如下:befor add(): 3after add(): 4這點跟 Java 是非常相似的。但是大家注意一點:那就是方法不要定義在 main 方法里面,之前遇到有同學問我這么一個錯誤:Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead. at line: 7 column: 4. File: ConsoleScript42 at line: 7, column: 4這個錯的原因就是,他把自己的方法定義在 main 方法里面了。這里特別提一下讓大家謹記。
在之前的學習之中,我們學習了很多的網絡模型,比如 CNN、RNN 等基本的網絡模型,雖然這些模型是根據人的信息處理方式來進行設計并實現的,但是這些模型都有一些特點,那就是只是會根據輸入的數據進行機械地輸出。那么我們這節課便要來學習一下更加 “貼近人的信息處理方式的方法”———— 注意力機制。
實際上,讓開發變得簡單,是 Spring 誕生的原動力。Java 官方推出的企業級開發標準是 EJB ,但 EJB 是相當臃腫、低效的,且難以測試,把當時的 Java 開發者折騰得不輕。Spring 官網介紹:讓 Java 變簡單那時候,國外有一個年輕的小伙 Rod Johnson,對 SSH 的繁瑣產生了質疑。他不光質疑,還去做了他認為對的事情。經過不斷的經驗總結和實踐,他在 2004 年推出了經典力作《Expert one-on-one J2EE Development without EJB》。該書奠定了 Spring 框架的思想基礎,把 EJB 的種種缺點逐一否定,還提出了簡潔的替代方案。從此 Rod Johnson 和 Spring 框架一炮而紅,其影響之深遠,恐怕連 Rod Johnson 自己都想不到吧。有時候,不要過于迷信官方,也要敢于思考和質疑。實踐是檢驗真理的唯一標準,編程也不外乎是。
saveOrUpdate( ) 方法很好理解,是 save( ) 和 update( ) 方法的綜合簡化版,內在本質沒改變。save() 和 persist() 方法有細節上的區別。save() 方法原型:public Serializable save(Object object);上一段 save ( ) 方法的測試實例:try { Student stu = new Student("save()方法", "男"); Serializable stuId = session.save(stu); System.out.println("----------輸出學生編號Id---------"); System.out.println(stu.getStuId()); System.out.println(stuId); System.out.println("----------事務在后面-------"); transaction = session.beginTransaction(); transaction.commit();} catch (Exception e) { transaction.rollback(); } finally { session.close();} 輸出結果:Hibernate: insert into Student (stuName, stuPassword, stuPic, stuSex) values (?, ?, ?, ?)----------輸出學生編號Id---------4040----------事務在后面------- 結果即結論:Save() 方法可以在事務之外執行;有一個關鍵點需要引起重視:無論是在事務之內還是事務之外,save() 方法都會向數據庫發送了一條 Sql 語句請求,控制臺輸出結果是一樣的。但是:如果程序中 Hibernate 不顯示發送事務提交指令,數據會回滾(丟失);只有當數據庫系統接收到程序中發送過來的事務提交指令后,才會真正意義上保存。很好理解,因為事務是交給 Hibernate 管理的,數據庫接收到插入指令后,在沒有明確事務提交指令之前,只會把數據緩存在內存中。也就是說,雖然 save() 方法看起來不依賴事務就可插入數據,但,沒有事務組件的指令,最后也是虛行一場。persist() 方法原型:public void persist(Object object); 上一段 persist() 測試實例:try { Student stu = new Student("persist()方法", "男"); session.persist(stu); System.out.println("----------輸出學生編號Id---------"); System.out.println(stu.getStuId()); System.out.println("----------事務在后面-------"); transaction = session.beginTransaction(); System.out.println("-------------事務提交---------------"); transaction.commit(); System.out.println(stu.getStuId());} catch (Exception e) { transaction.rollback();} finally { session.close();}輸出結果:----------輸出學生編號Id---------null----------事務在后面--------------------事務提交---------------Hibernate: insert into Student (stuName, stuPassword, stuPic, stuSex) values (?, ?, ?, ?)39 persist() 方法只有當事務提交后,才會發送 Sql 請求,數據直接寫入數據庫,方法本身沒有返回值。save() 和 persist() 方法區別:在事務之內調用時,兩者區別不大;事務之外,區別明顯。save() 返回主鍵值,persist() 方法沒有返回值;persist() 完全依賴事務組件,否則不會提交 Sql 請求;persist() 方法除了可進行 save 操作,還可以進行 update 操作。
使用語法:let resultString = str.repeat(count);該方法構造并返回一個新字符串,表示將原字符串重復 n 次,并不會改變原字符串。參數說明:參數描述 count 介于 0 和正無窮大之間的整數: [0, +∞)。表示在新構造的字符串中重復了多少遍原字符串。count 取負數的時候會報錯,但是在 (-1.0] 之間不會報錯,而會把 count 處理成 0
今天我們聊一聊計算機中非常重要和常用的一種算法:分治算法。它在計算機領域應用廣泛,幾乎無處不在。不僅計算機領域,在信號處理領域,分而治之也是十分常見的一種信號處理方法。著名快速傅里葉變換算法 (FFT) 正是使用了分而治之的思路,才使得數字信號處理算能廣泛使用,這也才造就了我們今天豐富多彩的生活。
在我們之前的數據處理過程之中,我們都是采用的 ASCII 碼或者其他編碼處理數據格式的,但是這些編碼并不能夠完全表示當前所有語言的所有字符,比如我們就無法使用 ASCII 碼來表示漢語。因此這個時候我們就需要用到一種新的編碼方式來進行字符的處理,于是這節課我們來學習如何在 TensorFlow 之中處理 Unicode 格式的數據。
ChannelPipeline 的最常用方法:方法描述 addFirst(…) 添加 ChannelHandler 在 ChannelPipeline 的第一個位置 addBefore(…) 在 ChannelPipeline 中指定的 ChannelHandler 名稱之前添加 ChannelHandleraddAfter(…) 在 ChannelPipeline 中指定的 ChannelHandler 名稱之后添加 ChannelHandleraddLast(…) 在 ChannelPipeline 的末尾添加 ChannelHandlerremove(…) 刪除 ChannelPipeline 中指定的 ChannelHandlerreplace(…) 替換 ChannelPipeline 中指定的 ChannelHandlerChannelHandler first() 獲取鏈表當中的第一個節點 ChannelHandler last() 獲取鏈表當中的最后一個節點實例:ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<NioSocketChannel>() { protected void initChannel(NioSocketChannel ch) { ch.pipeline().addLast(new Handler1()); ch.pipeline().addLast(new Handler2()); ch.pipeline().addLast(new Handler3()); ch.pipeline().addLast(new Handler4()); } });總結,ChannelPipeline 的用法比較固定,雖然方法很多,但是一般常用的就是 addLast。
除過上面代碼中使用的最基本的 accumulate (int)、get () 方法之外,我們再介紹兩個方法的使用。reset () 方法將累加器值置為 0,即為后繼使用重新歸位。getThenReset () 方法此方法邏輯等同于先調用 get () 方法再調用 reset () 方法。
除過上面代碼中使用的最基本的 add (int)、sum () 方法之外,我們再介紹兩個方法的使用。reset () 方法將累加器值置為 0,即為后繼使用重新歸位。sumThenReset () 方法此方法邏輯等同于先調用 sum () 方法再調用 reset () 方法,簡化代碼編寫。
方法區的實現,虛擬機規范中并未明確規定,目前有 2 種比較主流的實現方式:HotSpot 虛擬機 1.8之前:在 JDK1.6 及之前版本,HotSpot 使用 “永久代(permanent generation)” 的概念作為實現,即將 GC 分代收集擴展至方法區。這種實現比較偷懶,可以不必為方法區編寫專門的內存管理,但帶來的后果是容易碰到內存溢出的問題(因為永久代有 - XX:MaxPermSize 的上限)。在 JDK1.7,HotSpot 逐漸改變方法區的實現方式,如 1.7 版本移除了方法區中的字符串常量池,但為發生本質的變化。HotSpot 虛擬機 1.8之后:1.8 版本中移除了方法區并使用 metaspace(元數據空間)作為替代實現。metaspace 占用系統內存,也就是說,只要不碰觸到系統內存上限,方法區會有足夠的內存空間。但這不意味著我們不對方法區進行限制,如果方法區無限膨脹,最終會導致系統崩潰。
// 首先創建一個 AtomicInteger 對象AtomicInteger atomicInteger = new AtomicInteger();// 在操作之前先賦值,如果不顯式賦值則值默認為 0 ,就像 int 型變量使用前做初始化賦值一樣。atomicInteger.set(1000);// 之后可以調用各種方法進行增減操作...// 獲取當前值atomicInteger.get();// 先獲取當前值,之后再對原值加100atomicInteger.getAndAdd(100)// 先獲取當前值,之后再對原值減1atomicInteger.getAndDecrement()...是不是很簡單,AtomicInteger 在我們日常實踐中,到底應該應用在哪些場合比較合適呢?下面我們給出最常用的場景說明。
什么是主方法呢?請觀察示例代碼的 class 內部(指的是類名 HelloWorld 后面用大括號 {} 包含的內容),這個方法被稱為主方法。每個類只能擁有一個主方法。需要特別注意的是:所有的 Java 程序都從主方法開始執行。 以下的寫法是固定的,所以你暫時無需深究:public static void main(String[] args) { ...}而在主方法內部(指的是 main() 后面一對大括號中間包含的內容)我們可以定義一些指令,例如:System.out.println("Hello World!");我們稱這個指令為輸出語句,它的作用是向屏幕輸出 Hello World! 。輸出語句在后面會經常用到。我們也可以在主方法內部多次調用輸出語句,以輸出多條內容:349另外補充一點,類的內部不僅可以包含一個主方法,也可以包含多個方法。在學習方法的概念之前,我們將主要在主方法中編寫示例代碼。
sub () 函數用于數據集之間對應索引的減法操作,該操作不同于加法操作,字符操作是不存在減法操作的,算術上的減法只用于數值類型的數據運算,包括整形、浮點型等。# 創建 Series 對象new_series = pd.Series(['11',33], index=['推出時間','價格'])print(new_series)# --- 輸出結果 ---推出時間 11價格 33dtype: object# data 為從 Excel 解析出的 DataFrame 對象# 通過 sub 函數進行減法運算new_result=data.sub(new_series)print(new_result)# --- 輸出結果 ---……TypeError: unsupported operand type(s) for -: 'float' and 'str'TypeError: unsupported operand type(s) for -: 'str' and 'str'輸出解析:因為 pandas 中的 sub () 減法操作函數只在數值類型的數據之間有效,因此在 數值和字符串型,以及字符串與字符串之間進行 sub () 操作都會報錯。下面我們只對兩個數據集的價格索引了列進行 sub () 操作。# 創建 Series 對象new_series = pd.Series([33], index=['價格'])print(new_series)# --- 輸出結果 ---價格 33dtype: int64# data 為從 Excel 解析出的 DataFrame 對象# 通過 sub 函數進行減法運算new_result=data.sub(new_series)print(new_result)# --- 輸出結果 --- 主要創始人 價格 推出時間 編程語言0 NaN 12.6 NaN NaN1 NaN 34.0 NaN NaN2 NaN 0.9 NaN NaN3 NaN 26.5 NaN NaN4 NaN 36.9 NaN NaN5 NaN 42.0 NaN NaN輸出解析:這里我們對兩個數據集的價格列進行了相減操作,可以看到價格列的數據均減去了 33。
因為 Django 框架是使用 Python 進行開發的,所以在使用 Django 框架開發項目的時候是需要使用 Python 語言的,所以學習這門課程需要有 Python 的語法基礎。如果你對 Python 的語法比較陌生或者想要系統的進行學習一遍的話可以去看這門《Python 語法入門教程》,不僅有入門語法,還有《Python 進階應用教程》,在學習完這兩門課程之后就可以更平滑更順暢的學習這門 Django 框架教程了。
Channel 是一個連接通道,客戶端和服務端連接成功之后,會維持一個 Channel,可以通過 Channel 來發送數據。Channel 有且僅有一個 ChannelPipeline 與之相對應,ChannelPipeline 又維護著一個由多個 ChannelHandlerContext 組成的雙向鏈表,ChannelHandlerContext 又關聯著一個 ChannelHandler。它們之間的關系,大概如下圖所示: