2014年1月13日

connection pool

老師 我下課跟你問到的connection pool問題 我想一下 因為你說 不要管理connection要從sql 語法去克服 但是我回家想一下 假設connection pool最大值是100 那不管connection狀況下 假設同時有101個人提出需求要connection 系統可能會出包 但在保證 所有登入的使用者 皆可順利操作的前提下 我撰寫下面方法 當然如果能改善sql寫法 效能才會到達最佳 這點我覺得是我要加強的
 public void isDate(String user){
  //判斷 使用者是否超過 20分鐘 1200秒 操作Connection
  Date date = null;
  //DBTimeMap 是 HashMap 儲存所有使用者上一次使用的時間記錄 以user為key
  date = (Date) DBTimeMap.get(user);
  if(date == null){
   date = Calendar.getInstance().getTime();
  }else{
   long d = Calendar.getInstance().getTime().getTime() - date.getTime();
   date = Calendar.getInstance().getTime();
   if(d/1000 > 1200-5){//超過20分鐘
//以下兩個方法會釋放掉 user 的 connection 以利後面程式重建connection
    this.releaseDBConnection(user);
    this.releaseDB2Connection(user);
   }
  }
  DBTimeMap.put(user, date);
 }
管理部份我使用的是Singleton設計方法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletContext;

public class Singleton {
 private static Singleton instance = null;
 
 private HashMap DBConMap = new HashMap();
 private HashMap DB2ConMap = new HashMap();
 private ServletContext context;
 
 private HashMap DBTimeMap = new HashMap();
 
 public HashMap SysMap;
 public HashMap DBMap;
 public HashMap AirMap;
 public static Singleton getInstance(ServletContext context) {
  if (instance == null){
   synchronized(Singleton.class){
    if(instance == null) {
     instance = new Singleton(context);
    }
   }
  }
  return instance;
 }
 private Singleton(ServletContext context){
  //同步區
  this.context = context;
//處理 SysMap DBMap DBMap…略
 }
 
 public void isDate(String user){
  //判斷 使用者是否超過 20分鐘 1200秒 操作Connection
  Date date = null;
  date = (Date) DBTimeMap.get(user);
  if(date == null){
   date = Calendar.getInstance().getTime();
  }else{
   long d = Calendar.getInstance().getTime().getTime() - date.getTime();
   date = Calendar.getInstance().getTime();
   if(d/1000 > 1200-5){//超過20分鐘
    this.releaseDBConnection(user);
    this.releaseDB2Connection(user);
   }
  }
  DBTimeMap.put(user, date);
 }
 
 public Connection getDBConnection(String user){
  isDate(user);
  Connection con = (Connection) DBConMap.get(user);
  try {
   if(con == null){
    //建立DBCon
    HashMap map = SysMap;
    Class.forName("com.mysql.jdbc.Driver");
    String Driver = 
     "jdbc:mysql://"+
     map.get("DB")+":"+map.get("DBport")+"/"+map.get("DBname")+"?" +
     "user="+map.get("DBuser")+"&" +
     "password="+map.get("DBpwd")+"&" +
     "useUnicode=true&characterEncoding=utf-8" +
     "&autoReconnect=true&initialTimeout=0";
    con = DriverManager.getConnection(Driver);
    
    DBConMap.put(user, con);
   }
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  } catch (SQLException e) {
   e.printStackTrace();
  }
  return con;
 }
 public Statement getDBStatement(String user){
  Connection con = this.getDBConnection(user);
  Statement stmt = null;
  try {
   stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
  } catch (SQLException e) {
   e.printStackTrace();
  }
  return stmt;
 }
 public void releaseDBConnection(String user){
  DBConMap.remove(user);//釋放DBCon
 }
 public Connection getDB2Connection(String user){
  isDate(user);
  Connection con = (Connection) DB2ConMap.get(user);
  try{
   if(con == null){
    //建立DB2Con
    HashMap map = SysMap;
    Class.forName("com.mysql.jdbc.Driver");
    String Driver = 
     "jdbc:mysql://"+
     map.get("DB")+":"+map.get("DBport")+"/"+map.get("CorpDBname")+"?" +
     "user="+map.get("DBuser")+"&" +
     "password="+map.get("DBpwd")+"&" +
     "useUnicode=true&characterEncoding=utf-8" +
     "&autoReconnect=true&initialTimeout=0";
    con = DriverManager.getConnection(Driver);
    
    DB2ConMap.put(user, con);
   }
  }catch(ClassNotFoundException e){
   e.printStackTrace();
  }catch(SQLException e){
   e.printStackTrace();
  }
  return con;
 }
 public Statement getDB2Statement(String user){
  Connection con = this.getDB2Connection(user);
  Statement stmt = null;
  try {
   stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
  } catch (SQLException e) {
   e.printStackTrace();
  }
  return stmt;
 }
 public void releaseDB2Connection(String user){
  DB2ConMap.remove(user);//釋放DB2Con
 }
}

2012年9月4日

程式與香雞排


程式與香雞排 



當程式員很可憐,在台灣當程式員尤其可憐。薪資低、工作量大、地位不高、技術又容易被淘汰。難怪有人半開玩笑地告訴我,他以後不寫程式要改行去賣香雞排。

照理說,軟體開發是很專業的領域,越是專業的領域,越是處於金字塔的尖端,應該薪資很不錯才是,但不知怎地,台灣的程式員就是從來未獲重視。我們不要表面上的重視,我們要薪資上的重視。據我所知,大陸程式員的薪資水平,比起我們台灣高出許多(從國民所得、物價、房價來比較),美國程式員的薪資更是高得讓我猛嚥口水。

想想看,如果你在台北市租一間會漏水的小公寓,月租兩萬元(管理費和水電另計)。莫名其妙的多元入學方案實施之後,小孩壓力更大,要補習的東西更多。如果你有兩個小孩,每個月的補習費共要花上五千元。小孩要學費、生活費,又是另一個五千元。(乾脆含淚將小孩送人扶養。)

長得不怎麼好看的老婆就只會天天敷 SKII 面膜,因為她妄想 SKII 獨特的 Pitera 成分可以讓她的皮膚水水嫩嫩的,就和鄭秀文一樣。明明身材不好,卻又特別喜歡買 DKNY 昂貴的流行服裝。

光是這些支出加上你自己的支出,就已經超過五萬元了。你認為軟體公司會花五萬元請一個程式員嗎?在台灣,程式員要有五萬元以上的收入,恐怕要另有兼職才行。

於是你到歐萊禮兼職翻譯書,拼了老命把下班後的時間和假日的時間都拿來翻譯書,結果超過半年才翻譯完一本,還好歐萊禮仁慈不扣你延遲交稿的違約金。但這半年來身體變差了,微薄的稿酬光是拿來扣掉白蘭式雞精和補藥的支出,平均一個月也只多了約一萬元的收入,但總算因此達到收支平衡。

但這倒也不算真正的收支平衡,意外的收入支出也是有的:統一發票中獎收入平均一個月進帳 200 元,但偶而被倒會,加上有某個不長進的親戚時常來伸手要錢,你每個月還得多支出 5,000 元。婚喪喜慶的禮金支出、平常還要繳這個稅和那個稅、這個費和那個費的 ... 每每讓你心疼地暗暗叫苦。

台灣的軟體公司一向不肯好好地花錢雇用優秀的程式員,還奢談什麼知識經濟。在寫程式與賣香雞排之間作抉擇,如果我要留在台灣,我可能會選擇賣香雞排,如果我要出國謀生(美國、新加坡 ...),我會選擇寫程式。畢竟,要寫程式,就要到一個尊重程式員專業能力的地方。寫程式的薪資不高,就沒辦法吸收好的人才,至少我就不打算在台灣寫程式寫太久。興趣當然重要,但付不出帳單光靠興趣撐著,你認為能撐多久?賣香雞排稱不上是知識經濟,但只要不炸得太難吃,至少收入比寫程式好。

所以我覺得,到夜市賣香雞排的提議還真是可以考慮考慮,畢竟在台灣當程式員,一家大小在除夕夜如同賣火材的小女孩一般餓死凍死的機會很高。賣香雞排,雖然辛苦,但看著香雞排老闆們眉開眼笑的,荷包滿滿的,還可以趁著傍晚開市前,開著賓士轎車帶著全家出遊呢。

台北市饒河街夜市的攤販告訴我,攤位租金一個月一萬元出頭,我估算了一下,如果我平均一天擺攤 6 小時,賣了香雞排 300 個,每個淨賺 13 元,一個月淨賺 117,000 元,扣掉攤位租金 15,000,可以收入約十萬新台幣(免稅),實在比程式員普遍的月薪 30,000~40,000(未稅)好太多了。而且香雞排的炸法不會每年推出新版本。

在台灣的軟體公司內部,有許多非科班出身的程式員,他們的薪資低廉,通常又很努力。軟體公司就算聘到了這種便宜又努力的程式員,也不要太高興,因為這樣的程式員,通常都只是把目前的公司當一個學習的過渡階段,等到學得差不多,拍拍屁股就走人了,才沒打算一輩子接受這樣的低薪。但可悲的是,大部分的公司都沒有良好的程式員生涯規劃制度,反正大家互相利用。所以這些程式員很可能在做計畫的過程中,學不到東西又磨得身心俱疲。

所以,何苦來哉!不如我們通通去賣香雞排吧!但是你們只能到通化街夜市和士林夜市賣,不可以到我屬意的饒河街夜市和我搶生意(我打聽過,饒河街的攤位租金是三者中最便宜的)。我的攤位名稱要取做什麼呢?... 嗯!就叫做「Java 雞排」好了,以紀念我曾有過的 Java 程式員身份。我打算把雞排分成三種大小,最大到最小分別叫做 J2EE、J2SE 以及 J2ME。哪天你到饒河街夜市,發現了一個乾乾瘦瘦、看起來營養不良的少年頭家用著生硬的台語在吆喝著:「來呦!來呦!好呷的香雞排,J2EE 一塊 50,J2SE 一塊 40,J2ME 一塊 30......」請你也來光顧一下吧!... 看在 Java 的份上。

本文作者:蔡學鏞
張貼日期:12/12/01


再論香雞排


由於許多讀者缺乏版權觀念,在網路上到處張貼轉寄「程式與香雞排」一文,使得該文章在網路上引起程式員廣大的迴響。當「該文作者」在 BBS 各版和各種網頁討論區都看到自己的文章被人到處張貼討論時,驚駭莫名。更荒謬的是,該文章居然還繞了一圈被人轉寄到「該文作者」的 email 信箱中。該文章引起迴響的程度遠遠超出「該文作者」的預期。

有的人對於「該文作者」寄予無限的同情,畢竟該文章內容寫得太負面了。Oh! No. 你們搞錯同情對象了,事實上該文並非「該文作者」的寫照,畢竟「該文作者」未婚(不用擔心 SKII 和 DKNY 的支出),也還沒未婚生子(不用擔心多元入學方案和補習費),也從不標會(對高風險事物沒興趣),也從不對統一發票的中獎號碼(這點小錢根本不放在眼裡),也沒有不長進的親戚敢上門伸手要錢(言語犀利苛薄,親戚躲他像躲鬼一樣避之唯恐不及),也不是非科班出身的便宜程式員(雖然沒本事取得博士學位,但好歹也是個清華大學的資訊碩士),也在台灣和大陸的 Java 圈子都小有名氣(但不排除有些人孤陋寡聞)。橫看豎看,「該文作者」都不算是一個受到壓榨的程式員。甚至「該文作者」經常逛街瘋狂瞎拼買到手軟,出門懶得擠公車只坐計程車,在路上看到賣口香糖的老人或殘障人士一定會捐錢,...... 這麼努力花錢,但不知怎地錢就是花不完,所以「該文作者」可以說是生活得相當優渥的。而且「該文作者」還得寸進尺,常嚷嚷不想工作,宣稱以後要辭職回家變賣家產,靠父母親一點一滴掙來的財產來過無憂無慮的生活。你一定想問:既然如此,「該文作者」幹嘛寫了一篇胡亂抱怨的文章,無端惹來你掬一把同情之淚?我希望你不要因此怨懟「該文作者」欺騙你的感情,「該文作者」只是利用文學中「示現修辭格」的手法來撰寫該文章,以求得強烈的閱讀效果,這和「十八歲賺一億」一書作者蓄意欺騙的行徑是完全不同的。「該文作者」悲天憫人,對於許多程式員的遭遇感同身受,透過該文章,將他所知道的一切披露出來,代替許許多多台灣的程式員發聲。

夠了!我們不要再談論「該文作者」了!免得讓你因為過度羨慕他而開始哀聲嘆氣,畢竟這麼有福氣又囂張的人實在不多。該文作者「托夢」請我整理這些日子以來讀者的看法,我無法拒絕這樣的請託,因為我和「該文作者」的關係實在太密切了。

有一些有志進入軟體產業的在學學生憂心忡忡,表示看了該文章之後,信心開始動搖,有幻滅的感覺。我認為,幻滅是成長的開始,早點經歷幻滅總是好事,才不會一廂情願地只看到事物好的一面,也因此會多做好一些準備(不管是心理上的準備或技能上的準備),成功的機會就會大幅提高。學生距離就業還有許多年的光景,只要好好把握這些年充實自己,其實以後你們在軟體產業的發展前途仍然是很不錯的。至於程式與香雞排的作者,則是一個「先天下之憂而憂,後天下之樂仍憂」的一個「馬不停蹄地憂傷」的小子,所以你們不要把他那過度負面的看法放在心上。香雞排,你們負責吃就好了,要賣也是我來賣。

也有許多讀者對於該文章感到心有戚戚焉,這類的讀者以程式員居多。我要警告這類的程式員,如果你平常不好好加強自己的分析設計技巧、管理能力、或其他技能,當程式員當了五年後仍然只是最低階的程式員,還得親自寫程式,辛辛苦苦地追著瑣碎的技術跑,那麼你就真得要小心考慮,賣香雞排或許真的比較適合你。

也有人的薪資不止五萬元,質疑該文章太悲觀。一般來說,這種人可能在外商公司、或者已經脫離程式員等級、或者在不太軟的軟體公司(例如 chip design),或者在非軟體公司的 MIS 部門。我認識一個年資約兩年的程式員,在一家不太軟的外商軟體公司當程式員,月薪約 6 萬台幣,但這樣的價碼可是大多數的程式員都無法達到的。薪水這麼高的程式員,不需要轉行賣香雞排。

有些人則沒有受到「該文作者」的恫嚇所打擊,仍堅持要繼續在軟體行業走下去,我很佩服這樣的人,因為你正是軟體產業需要的人。你不把錢看得太重,而且肯努力、有興趣,只要繼續持之以恆,我相信你在未來的報酬自然也不會太差的。但是你千萬要慎選公司,選擇一個有發展前景又願意栽培你的公司,否則你最後還是可能會去賣香雞排的。

還有一些讀者提出許多有建設性的寶貴意見,這些意見包括了:「雞排一塊不只賺 13 元,一天不只賣 300 個,十萬元的估計太保守」、「珍珠奶茶其實更有賺頭,每杯淨賺八成」、「滷味不需要技巧,比較適合程式員轉行」、「當靈修講師不需要大學學歷,輕輕鬆鬆月入七萬元」。但不管怎樣,我還是對賣香雞排情有獨鍾,我兩小時前才剛到饒河街夜市吃了一個香雞排,此刻仍然齒頰留香,回味無窮。賣香雞排的收入也有很大的差異,有些香雞排的攤位門可羅雀,有些香雞排的攤位生意好到老闆累得一邊吊點滴一邊炸香雞排。前陣子我看到電視新聞採訪一位在新竹科學園區附近賣香雞排的女老闆,她說她每個月賺 45 萬元以上。她還告訴記者香雞排好吃的秘訣在於醬料,但任憑記者怎麼追問,她仍不肯透露醬料的作法。急於開店賣香雞排的我對此婆娘小氣之舉很不以為
然,我悻悻然地自言自語:「哼!秘訣?你以為我無法得知你的醬料配方?」我決定重金禮聘擅長偷拍的「郭女士」出馬,先接近該香雞排店的女老闆成為她的靈修姊妹淘,取得信任之後,再潛入該女老闆的廚房裝設針孔攝影機。我相信,以郭女士純熟的偷拍手法,醬料的配方會落入我手中。有了她的醬料,加上我獨門研發使用高筋麵粉和數十種珍貴藥材做出來的銷魂蝕骨酥皮,我寫程式的苦日子即將結束,我終將成為香雞排大亨的。想到這裡,我喜孜孜地笑了。

本文作者:蔡學鏞
張貼日期:01/01/02


香雞排三部曲:完結篇 


我所撰寫的香雞排首部曲(程式與香雞排)在台灣程式員圈子造成一股轟動,幾乎每個程式員都讀過,成了網路上的熱門話題。香雞排話題太過度發酵,是我所不樂見的。每當有程式員感嘆自己的收入太低時,就會丟出一句「不如改行去賣香雞排」以為自嘲,香雞排儼然是軟體產業主管最不願意碰觸的禁忌圖騰。

據我所知,許多程式員讀過該文章之後,紛紛開始自怨自艾,不想在這個圈子繼續待下去。我自感罪孽深重,所以連忙以比較樂觀的態度寫了香雞排第二部曲(再論香雞排),希望達到平衡作用。但是現在,我必須告訴你,香雞排第二部曲太過於樂觀,我必須寫下這篇香雞排第三部曲,也就是香雞排系列的完結篇,告訴你其實也不要太樂觀。為了提高可信度,本文章會提出許多數據,以為佐證。

根據我多方打量,在台灣,大學畢業,具有工作經驗一年的程式員,約 30,000~35,000 新台幣(月薪),我們就姑且取最高值 35,000 新台幣來估算好了。而在中國大陸,大學畢業,具有工作經驗一年的程式員,(月薪)薪資差異頗大,有 2,000 人民幣的,也有 4,000 人民幣的,我取估計值為 3,500 人民幣,約等於 14,000 新台幣(人民幣幣值以新台幣四倍估算)。

你很覺得很更高興嗎?因為你的薪資是大陸程式員的 2.5 倍(35,000 / 14,000 = 2.5)。先別高興,你必須把物價和國民所得也考慮進去才行。

考慮物價因素。台灣電腦雜誌的售價 200 元新台幣,大陸電腦雜誌的售價 10 元人民幣,約 40 元新台幣,是台灣的 1/5。台灣電腦書籍的售價 600 新台幣,大陸書籍的售價 30 人民幣,約 120 新台幣,是台灣的 1/5。也就是說,台灣的資訊出版品售價約為大陸的 5 倍,但台灣的程式員薪資只有大陸的 2.5 倍。也就是說,在台灣的程式員買一本書,在大陸的程式員可以買兩本書。

考慮國民所得因素。台灣國民所得年平均近 15,000 美金,約等於 525,000 新台幣,是台灣程式員月收入的 15 倍。大陸國民所得年平均近 1,000 美金,約等於 35,000 新台幣,是大陸程式員月收入的 2.5 倍。簡單來說,大陸程式員工作 2.5 個月,就能賺到大陸民眾一整年的所得;台灣程式員工作 15 個月,才能賺到台灣民眾一整年的所得。比較起來,大陸程式員賺錢的速度是台灣程式員的 15 / 2.5 倍,也就是 6 倍。

因為大陸的都市生活水平比未開發的地方高出許多,貧富差距、城鄉差距很大,為了減少誤差,我們必須把這些因素所造成的影響也算進去。我不知道大陸的房租、交通費、餐飲費用為何,所以無法比較。但我估計,這會使得前述的「6 倍」數字稍微降低一點,所以我把「6 倍」降為「5 倍」,這樣的估算應該算合理,差距 5 倍耶!如果你的薪水原本是四萬元,五倍就是 20 萬新台幣。想想,在台灣,一個月有了二十萬的進帳,日子豈不快樂似神仙。

台灣程式員的薪資水準比人家差五倍,難道能力也比人家差五倍?我不這麼認為,我反倒認為台灣的程式員普遍能力比大陸程式員好,因為台灣的資訊產業、資訊教育很早就開始了。像我這種寫了近 19 年程式的人也不是很少見,有過十年以上程式經驗的人更是比比皆是。

香雞排三部曲系列文章不是為我自己抱怨,因為我對自己的未來有一套規劃,不打算讓自己陷入「富爸爸,窮爸爸」一書所謂的「mouse race」中。只是,有多少程式員會有這樣的規劃。台灣的程式員就像是在被熱水緩慢地煮熟的青蛙。而我就像是一隻已經跳離開鍋子,開始尋找水塘的青蛙,我寧願在夏天發燙的柏油路上,被川流不息的來車壓成扁扁的「青蛙乾」,也不願意當一隻任人烹煮的青蛙。

我知道我這篇文章又會引起一些人的抗議,特別是資訊產業主管的抗議。如果你是這樣的主管,我勸你先別找我興師問罪,因為根據我的判斷,這篇文章效用只有短暫的。原本不自覺水溫上升的青蛙,在讀過這篇文章之後開始騷動「你說什麼!鍋底正在加熱!」... 一陣子緊張之後又漸漸歸於平靜,或許是因為已經習慣這樣的環境了,或許是因為擔心出了鍋子會找不到水源而乾死,所以青蛙繼續待在鍋內,真正跳出鍋子另覓水塘的青蛙只有極少數。而有趣的是,勸青蛙不要跳出鍋子的那些主管們,本身可能也是一隻待煮熟的青蛙呢!

拿起溫度計,現在就量一下你周圍的水溫有多少度?攝氏 60 度?攝氏 70 度?

本文作者:蔡學鏞
張貼日期:04/23/2002

2012年5月27日

Java 取得網頁資料

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;

public class HttpGetURL {


    public String str = "";
    public int line = 0;

    //public java.net.URL u;
    String url;
    String method;
    String code;
    
    public String allURL = "";
    
    public HttpGetURL() {}
    
    public void setURL(String url) {
        this.url = url;
        this.method = "GET";
        this.code = "";
        this.line = 0;
        this.allURL = url + "&" + Math.random();
        //HttpGetURL h = new HttpGetURL(url , "" , "GET");
        //str = h.str;
        //line = h.line;
    }

    public void setURL(String url, String code, String RequestMethod) {
        this.url = url;
        this.code = code;
        this.line = 0;
        this.method = RequestMethod;
        this.allURL = url + "?" + code + "&" + Math.random();
    }

    public void connect() {
        //StringBuffer s = new StringBuffer();
        String s = "";
        try {
            java.net.URL u = new java.net.URL(allURL);
            java.net.HttpURLConnection http = (java.net.HttpURLConnection) u.openConnection();

            http.setRequestMethod(method);
            //System.out.println(http.getRequestMethod());

            int n =  http.getResponseCode();

            //System.out.println(u.toString());
            //System.out.println(n + " " + HttpURLConnection.HTTP_OK);
            if (n == HttpURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        http.getInputStream(), "utf-8"));
                String tmp = null;

                while ((tmp = br.readLine()) != null) {
                    //s.append(tmp);
                    s += tmp;
                    line++;
                }

                str = s.toString();
            } else
                str = "Error";
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
            //StackTraceElement[] em = ex.getStackTrace();
            str = "Error";
        }
        //s.delete(0, s.length());
    }
}
public class MAIN {
 public static void main(String[] args){
  HttpGetURL link = new HttpGetURL();
  
  String url = "http://www.google.com/";
  String code = "a=1";
  String RequestMethod = "GET";
  
  link.setURL(url, code, RequestMethod);
  link.connect();
  System.out.println(link.allURL);
  System.out.println(link.str);
 }
}

2012年3月25日

等腰三角

    public static void main(String[] args) {
        int w = 10;//底邊長
        //case 0 : 無恥數學解
        for(int x = 0 ; x < w/2+1 ; x++){
            for(int y = 0 ; y < w ; y++){
                if(x-y+(w/2) == 0 || x+y-(w/2) == 0 || x == w/2+1-1)
                    System.out.print("* ");
                else 
                    System.out.print("- ");
            }
            //如果 底邊 長度是偶數 則要補一個* 不然會缺一角
            if(x == w/2+1-1 && w%2 == 0)
                System.out.print("* ");
            System.out.println();
        }
        
        System.out.println();
        //case 1 : 苦命解
        for(int x = 0 , cont = w/2 ; x < w/2+1 ; x++ , cont--){
            //印出每行前面的空白
            for(int y = 0 ; y < cont ; y++){
                System.out.print("- ");
            }
            //印出第一個*
            System.out.print("* ");
            //印出空心部分的空白
            if(x != w/2+1-1){
                for(int y = 0 ; y < ((w/2)-cont-1)*2+1 ; y++){
                    System.out.print("- ");
                    //最後印出第二個*
                    if(y == ((w/2)-cont-1)*2+1-1)
                        System.out.print("* ");
                }
            }else if(x == w/2+1-1){//如果到了最後一行則印出整行*
                for(int y = 0 ; y < w-1 ; y++){
                    System.out.print("* ");
                }
                //如果 底邊 長度是偶數 則要補一個* 不然會缺一角
                if(w%2 == 0)
                    System.out.print("* ");
            }
            System.out.println();
        }
    }

}

2012年2月10日

物件導向 by Aki

物件導向 by Aki

物件?

物件其實是一種概念,我們來想想一台車有甚麼,最簡單的一台車有車牌所以我們寫下

public class Car {

String id; //車牌

}

然後一台車總會走吧!於是我再多寫一個方法

public class Car {

String id; //車牌

public void go(){

System.out.println("GO 開車");

}

}

這是一個很簡單的class裡面只有一個變數id和一個go()方法但是足以解釋物件的本質

一個class必須要有屬性以及方法

public class Car {

String id; //車牌 (屬性)

public void go(){// (方法)

System.out.println("GO 開車");

}

}

講道這邊我必須說這是一個class(類別)而不是一個object(物件)

那麼我們該怎麼把class Car變成物件?

//code-MAIN

public class test {

public static void main(String[] args) {

Car car = new Car();

}

}

答案就是

Car car = new Car();

雖這個答案是對的 但是這個答案其實不標準

Car car ;

car = new Car();

在這之前我們應該知道一個變數的宣告是這樣的

//型態 名稱 = 值 ;

int i = 0;

意思是說我們宣告了一個type為int的記憶體空間

clip_image002

然後我們在裡面存進0這個值

clip_image004

也就是說 = (等號) 也就是那個箭頭

回到剛剛的

Car car ;

car = new Car();

也就是說第二行的 car = new Car(); 就是下圖

clip_image006

這邊可能有個觀念可能會錯亂

以前我們看到 A = B 會說B存到A

但是有另一個解釋就是A參考至B

new Car();

其實這就是把Car()這個class實體化成一個物件

然而這個剛剛從class實體化成的object需要一個名稱去參考就是car

car = new Car();

2011年11月22日

梅花座

/*
 * 一班30個學生男女各半
 * 需安排座位成梅花座
 * 
 * 輸出格式範例
 * 請輸入橫排人數 : 5
 * 男95	女94	男86	女82	男84	
 * 女80	男79	女73	男78	女65	
 * 男76	女63	男69	女62	男68	
 * 女51	男63	女47	男56	女41	
 * 男49	女38	男41	女25	男21	
 * 女21	男15	女19	男4	女6
 * 
 * 請輸入橫排人數 : 6
 * 男97	女96	男96	女94	男94	女91	 
 * 女67	男89	女52	男77	女50	男65	 
 * 男58	女39	男46	女37	男41	女26	 
 * 女23	男35	女17	男20	女16	男19	 
 * 男18	女16	男17	女13	男13	女7
 * 
 * 以下程式為亂數產生學生分數 分數範圍為0~100 以及性別0表女 1表男
 * 並且輸出全班成績(未排序) 請接下去寫程式
 */
import java.util.Arrays;
import java.util.Scanner;
public class Scortandplumseat {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int student[][] = new int[30][2];//整班學生
		int sex = 0 , score = 1;//學生陣列代號 student[i][sex] student[i][score] 
		int sex_boy = 1 , sex_gril = 0;//性別代號
		int boy_totle = 0 , gril_totle = 0;//男女生人數統計
		
		int boy[][];//男生排序後的陣列
		int gril[][];//女生排序後的陣列
		
		int row_max = 4;//橫排人數
		int title = sex_boy;//排頭是男生還是女生
		
		//產生學生資料 以及假成績
		for(int i = 0; i < student.length ; i++){
			int sex_rand = (int)(Math.random()*2);//亂數性別 0=女 1=男
			int score_rand = (int)(Math.random()*100+1);//亂數分數 0~100
			if(sex_rand == sex_gril){
				if(gril_totle >= 15){//如果女生超過15人則重新產生亂數 
					i--;
					continue;					
				}else
					gril_totle++;//女生人數統計
			}else if(sex_rand == sex_boy){
				if(boy_totle >= 15){//如果男生超過15人則重新產生亂數
					i--;
					continue;
				}else
					boy_totle++;//男生人數統計
			}
			student[i][sex] = sex_rand;//存入該學生性別
			student[i][score] = score_rand;//存入該學生成績
		}
		
		//輸出全班成績
		System.out.println("全班成績 : ");
		System.out.println("編號\t性別\t分數");
		for(int i=0,j=0 ; i < student.length ; i++ ){
			if(student[i][sex] == sex_boy){
				System.out.println(i + "\t男\t" + student[i][score]);
			}else{
				System.out.println(i + "\t女\t" + student[i][score]);
			}
		}
		
	}
}

2011年11月11日

JavaScript 全形數字轉半形數字

function isValue(val){
    var v = val.value;
    if(v == 'NaN' || v == null || v == ''){
        return 0;
    }else{
        //全行轉半型
        result="";
        for(i=0;i < v.length;i++){        
         if( v.charCodeAt(i)== 12288){
                result+=" ";
         }else{
                if(v.charCodeAt(i) > 65280 && v.charCodeAt(i) < 65375){
                 result += String.fromCharCode(v.charCodeAt(i) - 65248);
                }else{
                 result += String.fromCharCode(v.charCodeAt(i));
                }
         }
        }
        val.value = result;
        v=result;
        return v;
    }
} 

2011年8月2日

UVa - p100

p100 問題連結

import java.io.BufferedInputStream;
import java.util.Scanner;

public class u100 {
	int max;
	int min;
	int cont;
	public u100(){
		Scanner sc = new Scanner(new BufferedInputStream(System.in));
		String s;
		while(sc.hasNext()){
			int a = sc.nextInt();
			int b = sc.nextInt();
			if(a > b){
				max = a;
				min = b;
			}else{
				max = b;
				min = a;
			}
			int contmax = 0;
			for(; min <= max ; min++){
				cont = 0;
				f(min,max);
				if(contmax < cont)
					contmax = cont;
			}
			System.out.println(a + " " + b + " " + contmax);
		}
	}
	
	public void f(int n , int j){
		//System.out.print(n + " ");
		cont++;
		if(n == 1){
			//stop
		}else{
			if(n%2==1){
				n = 3*n+1;
			}else{
				n = n/2;
			}
			f(n,j);
		}
	}
	
	public static void main(String[] args){
		new u100();
	}
}

2011年2月28日

遞迴練習 河內塔

public class tower {
	
	void tower(int n , String a , String b , String c){
		if(n == 1){
			System.out.println(a + " to " + c);
		}else{
			tower(n-1 , a , c , b);
			tower(1 , a , b , c );
			tower(n-1 , b , a , c);
		}
	}
	
	public static void main(String[] args) {
		tower t = new tower();
		t.tower(3, "B" , "C" , "A");
	}
}

遞迴練習 三角形

public class tri {
	/*
	Enter n = 5
	tri1
	*
	**
	***
	****
	*****
	tri2
	*****
	****
	***
	**
	*
	tri3
	    *
	   **
	  ***
	 ****
	*****
	tri4
	*****
	 ****
	  ***
	   **
	    * 
	*/
	public void prchar(String c , int n){
		for(int i = 0 ; i < n ; i++)
			System.out.print(c);
	}
	
	public void tri1(int n){
		if(n == 1){
			prchar("*",1);
			System.out.println();
		}else{
			tri1(n-1);
			prchar("*",n);
			System.out.println();
		}
	}
	
	public void tri2(int n){
		if(n == 1){
			prchar("*",1);
			System.out.println();
		}else{
			prchar("*",n);
			System.out.println();
			tri2(n-1);
		}
	}
	
	public void tri3(int n , int m){
		if(n == 1){
			prchar(" ",m-1);
			prchar("*",1);
			System.out.println();
		}else{
			tri3(n-1 , m);
			prchar(" ",m-n);
			prchar("*",n);
			System.out.println();
		}
	}
	
	public void tri4(int n , int m){
		if(n == 1){
			prchar(" ",m-1);
			prchar("*",1);
			System.out.println();
		}else{
			prchar(" ",m-n);
			prchar("*",n);
			System.out.println();
			tri4(n-1 , m);
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		java.util.Scanner sc = new java.util.Scanner(System.in);
		int n;
		System.out.print("Enter n = ");
		n = sc.nextInt();
		
		tri t = new tri();

		System.out.println("tri1");
		t.tri1(n);
		System.out.println("tri2");
		t.tri2(n);
		System.out.println("tri3");
		t.tri3(n, n);
		System.out.println("tri4");
		t.tri4(n, n);
		
	}
}

2010年10月8日

link list

/*
299418045 王國銘 
功能說明 : 可新增刪除節點 
*/ 
#include <stdio.h>
#include <stdlib.h>

struct node{
	int data;
	struct node *next;
};
struct node *front;

void insert(int key);
void show(void);
void del(int key);

void show(){
    struct node *this_node;
    if(front->next != NULL){
        this_node = front->next;
        printf("    front -> ");
        while(this_node != NULL){
            printf("%d -> ",this_node->data);
            this_node = this_node->next;
        }
        printf("NULL \n");
    }else{
        printf("    ERROR : link list中沒有資料可以顯示請按 1 輸入資料 \n");
    }
}

void del(int key){
    struct node *this_node , *tmp_node;
    this_node = front;
    while(this_node->next != NULL){
        if(this_node->next->data == key){
            tmp_node = this_node->next;
            if(tmp_node->next != NULL){
                //找到欲刪除節點 
                this_node->next = tmp_node->next;
            }else{
                //找到欲刪除節點 並在末端 
                this_node->next = NULL;
            }
            free(tmp_node);
            return;
        }
        this_node = this_node->next;
    }
    printf("    ERROR : 找不到指定資料!\n");
}

void insert(int key){
    struct node *new_node;
    new_node = (struct node *) malloc(sizeof(struct node));
    new_node->data = key;
    new_node->next = NULL;
    
    if(front->next == NULL){
        //新增第一筆資料 
        front->next = new_node;
    }else{
        //插入資料 
        struct node *this_node;
        this_node = front;
        while(this_node->next != NULL){
            if(this_node->next->data > key){
                //若下一筆 data 比 key 大 就安插在下一筆與這一筆之前 
                new_node->next = this_node->next;
                this_node->next = new_node;
                return;
            }
            this_node = this_node->next;
        }
        this_node->next = new_node;
    }
}

int main(){
	front = (struct node *)malloc(sizeof(struct node));
	front->next = NULL;
	
    int key = 0;
	while(key != 4){
		printf("1. 新增資料 \n2. 刪除資料 \n3. SHOW出現有link list \n4. 離開程式\n");
        printf("請輸入指令 : ");	
		scanf("%d",&key);
        int n = 0;
        switch(key){
            case 1://1. 新增資料
                printf("    請輸入一整數資料 = ");
                scanf("%d",&n);
                insert(n);	
                show();
                break;	
            case 2://2. 刪除資料
                printf("    請輸入欲的刪除資料 = ");
                scanf("%d",&n);
                del(n);
                show();
                break;	 
            case 3://3. SHOW出現有link list
                show();
                break; 
            case 4://4. 離開程式\n
                exit(0);
                break;
            default:
                break;
        }
        key = 0;
        printf("*************************************************************\n");
	}
}
/*
功能說明 : 可新增刪除節點 
test01.cpp
*/ 
#include <iostream>
using namespace std;  

struct node{
	int data;
	struct node *next;
};
struct node *front;

void insert(int key);
void show(void);
void del(int key);

void show(){
    struct node *this_node;
    if(front->next != NULL){
        this_node = front->next;
        while(this_node != NULL){
            cout << this_node->data <<" -> ";
            this_node = this_node->next;
        }
        cout << "NULL \n";
    }else{
        cout <<"沒有資料 \n";
    }
}

void del(int key){
    struct node *this_node , *tmp_node;
    this_node = front;
    while(this_node->next != NULL){
        if(this_node->next->data == key){
            tmp_node = this_node->next;
            if(tmp_node->next != NULL){
                //找到欲刪除節點 
                this_node->next = tmp_node->next;
            }else{
                //找到欲刪除節點 並在末端 
                this_node->next = NULL;
            }
            free(tmp_node);
            return;
        }
        this_node = this_node->next;
    }
    cout <<" ERROR : 找不到指定資料!\n";
}

void insert(int key){
    struct node *new_node;
    new_node = (struct node *) malloc(sizeof(struct node));
    new_node->data = key;
    new_node->next = NULL;
    
    if(front->next == NULL){
        //新增第一筆資料 
        front->next = new_node;
    }else{
        //插入資料 
        struct node *this_node;
        this_node = front;
        while(this_node->next != NULL){
            if(this_node->next->data > key){
                //若下一筆 data 比 key 大 就安插在下一筆與這一筆之前 
                new_node->next = this_node->next;
                this_node->next = new_node;
                return;
            }
            this_node = this_node->next;
        }
        this_node->next = new_node;
    }
}

int main(){
	front = (struct node *)malloc(sizeof(struct node));
	
	while(true){
		char key;
        
        cout << "請輸入資料或輸入d刪除資料 (輸入q離開程式\n ?";		
		cin >> key;	
		
        switch(key){
            case 'd':
                cout << "--請輸入欲刪除之資料\n ?";		
		        cin >> key;
		        del(key-48);
                show();		
                break;
            case 'q':
                 exit(0);
                 break;
            default:
                insert(key-48);
                show();	
        }
	}
}

2010年6月23日

關於 Abstract and Interface 三兩事

Abstract Class 和 Interface 本身都無法用來建構一個 object (物件實體) ,它們必須透過其他類別以 extends (繼承) 或 implements (實作) 來完成目的

  • Abstract
    • 當整個類別繼承體系有一致的行為時,我們通常會將這些行為抽離到上一層的 super class 去。如果這些行為的程式碼不在 super class 中定義的話,那麼會使得其 sub class 必須重覆地出現相同的程式片段,導致了壞味道的發生。然而有時我們並不打算讓這些 super class 可以被建構成物件實體,那麼它們就是所謂的 Abstract Class 。
  • Interface
    • 在我們確定了物件之間的溝通方式及規格,卻未能確定其實作細節時,就是利用 Interface 的時機。 Interface 能保證 Client 在操作物件上有一致的方式,而具體的表現方式則是讓實作的類別來決定。因此這些類別都必須實作在 Interface 裡定義的 method ,否則將會出現錯誤。在 Interface 中所有方法都是 abstract 的,定義方式和 Abstract Class 的抽象方法一樣,但是不用加上 abstract 關鍵字

兩者的使用時機

  1. 當類別有共同的行為或屬性時,可以考慮使用 Abstract Class。
  2. 類別有共同的操作介面,但是實作上卻有所差異時,可以考慮使用 Interface。

2010年4月2日

css 小記

研究浮動排列
image

body{
    width:1000px;
    margin: 0 auto;
}
 
.body{
    position: relative;
    padding:5px;
    background-color:red;
}
 
.top{
    position: relative;
    width:100%;
    height:100px;
    background-color:#fff;
}
 
.c{
    position: relative;
    top:5px;
    
    width:100%;
    height:600px;
    background-color:#fff;
}
.main{
    position: relative;
    display:inline-block;
    float:left;
    width:80%;
    top:5px;
    margin-left: 5px;
    border: 2px solid #ff8000;
}
.left{
    position: relative;
    display:inline-block;
    float:left;
    width:18%;
    top:5px;
    margin-left: 5px;
    border: 2px solid #ff8000;
}

 
<div class="body">
    <div class="top">top</div>
    <div class="c">
        <div  class="main">
            main<br>2<br>2<br>2<br>2<br>2<br>2<br>2<br>2<br>2<br>
        </div >
        <div  class="left">
            left<br>1<br>1<br>1<br>1<br>1<br>1<br>1<br>
        </div >
    </div>
</div>

2010年3月31日

CSS 忘光光

人真的是很妙的動物
我還是乖乖的把一些東西記錄下來好了

css

   1: body{
   2:     width:1000px;
   3:     margin:0 auto;
   4: }
   5: #top{
   6:     width:100%;
   7:     height:30px;
   8:     text-align:center;
   9:     background:#833;
  10:     margin:0 auto;
  11: }
  12: #main{
  13:     width:100%;
  14:     margin:0px auto;
  15:     background:white;
  16: }
  17: #sidebar{
  18:     width:25%;
  19:     float:left;
  20:     background:#383;
  21: }
  22: #content{
  23:     width:75%;
  24:     float:left;
  25:     background:#338;
  26: }
  27: #footer{
  28:     width:100%;
  29:     clear:left;
  30:     height:30px;
  31:     background:#833;
  32:     margin:0 auto;
  33: }



   1: <div id='top'>標題</div>
   2:  
   3: <div id='main'>
   4:     <div id='sidebar'>
   5:         邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>
   6:         邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>
   7:         邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>邊欄<br>
   8:     </div>
   9:     <div id='content'>
  10:         主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>
  11:         主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>
  12:         主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>
  13:         主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>主文<br>
  14:     </div>
  15: </div>
  16:  
  17: <div id='footer'>頁底</div>