Fantasy's World

          世界的小世界,我的大世界^_^

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            6 Posts :: 0 Stories :: 16 Comments :: 0 Trackbacks

          2005年12月21日 #

          首先看看我寫的一個(gè)小程序:

          public class TestTry extends Exception
          {
           static boolean f=false;
           static int sum=0;
           static int created=0;
           static int i=0;
           TestTry()
           {
            i=created++;
            if(created>=299) f=true;
            }
           public void finalize()
           {
            sum++;
            }
           public static void main(String[] args)
           {
            while(!TestTry.f)
            {
             try{
              throw new TestTry();
              }catch(Exception e){}
              finally{
               System.out.println("Creat "+TestTry.i+" TestTry, "+TestTry.sum+" has been finalized!");
               }
              }
            //System.out.println("Creat "+TestTry.created+" TestTry, "+TestTry.sum+" has been finalized!"); 
            }
           }

          這個(gè)是我在測(cè)試在try語句拋出異常后,在try語句中建立的對(duì)象是否會(huì)調(diào)用自身的終止函數(shù)時(shí)發(fā)現(xiàn)的,這里有個(gè)奇怪的現(xiàn)象在if(created>=299) f=true;這條語句中,如果把條件created>=299改為>=比299更大的數(shù),你會(huì)發(fā)現(xiàn)System.out.println("Creat "+TestTry.i+" TestTry, "+TestTry.sum+" has been finalized!");這條語句的輸出的結(jié)果并不是你預(yù)想的那樣(輸出判斷的數(shù)字+1的行數(shù)),而只是顯示最后的三百行。那么在這之前拋出的異常上哪里去了呢?難道說Java只處理最后拋出的三百的異常么?
          posted @ 2005-12-29 18:21 FinalFantasy 閱讀(367) | 評(píng)論 (0)編輯 收藏

          這個(gè)文檔是老師給我們看的,看了之后收獲不少,帖出來讓大家也看看:)

          引言

          Java的堆是一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū),類的實(shí)例(對(duì)象)從中分配空間。Java虛擬機(jī)(JVM)的堆中儲(chǔ)存著正在運(yùn)行的應(yīng)用程序所建立的所有對(duì)象,這些對(duì)象通過newnewarrayanewarraymultianewarray等指令建立,但是它們不需要程序代碼來顯式地釋放。一般來說,堆的是由垃圾回收 來負(fù)責(zé)的,盡管JVM規(guī)范并不要求特殊的垃圾回收技術(shù),甚至根本就不需要垃圾回收,但是由于內(nèi)存的有限性,JVM在實(shí)現(xiàn)的時(shí)候都有一個(gè)由垃圾回收所管理的堆。垃圾回收是一種動(dòng)態(tài)存儲(chǔ)管理技術(shù),它自動(dòng)地釋放不再被程序引用的對(duì)象,按照特定的垃圾收集算法來實(shí)現(xiàn)資源自動(dòng)回收的功能。

          垃圾收集的意義

          C++中,對(duì)象所占的內(nèi)存在程序結(jié)束運(yùn)行之前一直被占用,在明確釋放之前不能分配給其它對(duì)象;而在Java中,當(dāng)沒有對(duì)象引用指向原先分配給某個(gè)對(duì)象的內(nèi)存時(shí),該內(nèi)存便成為垃圾。JVM的一個(gè)系統(tǒng)級(jí)線程會(huì)自動(dòng)釋放該內(nèi)存塊。垃圾收集意味著程序不再需要的對(duì)象是"無用信息",這些信息將被丟棄。當(dāng)一個(gè)對(duì)象不再被引用的時(shí)候,內(nèi)存回收它占領(lǐng)的空間,以便空間被后來的新對(duì)象使用。事實(shí)上,除了釋放沒用的對(duì)象,垃圾收集也可以清除內(nèi)存記錄碎片。由于創(chuàng)建對(duì)象和垃圾收集器釋放丟棄對(duì)象所占的內(nèi)存空間,內(nèi)存會(huì)出現(xiàn)碎片。碎片是分配給對(duì)象的內(nèi)存塊之間的空閑內(nèi)存洞。碎片整理將所占用的堆內(nèi)存移到堆的一端,JVM將整理出的內(nèi)存分配給新的對(duì)象。

          垃圾收集能自動(dòng)釋放內(nèi)存空間,減輕編程的負(fù)擔(dān)。這使Java 虛擬機(jī)具有一些優(yōu)點(diǎn)。首先,它能使編程效率提高。在沒有垃圾收集機(jī)制的時(shí)候,可能要花許多時(shí)間來解決一個(gè)難懂的存儲(chǔ)器問題。在用Java語言編程的時(shí)候,靠垃圾收集機(jī)制可大大縮短時(shí)間。其次是它保護(hù)程序的完整性, 垃圾收集是Java語言安全性策略的一個(gè)重要部份。

          垃圾收集的一個(gè)潛在的缺點(diǎn)是它的開銷影響程序性能。Java虛擬機(jī)必須追蹤運(yùn)行程序中有用的對(duì)象, 而且最終釋放沒用的對(duì)象。這一個(gè)過程需要花費(fèi)處理器的時(shí)間。其次垃圾收集算法的不完備性,早先采用的某些垃圾收集算法就不能保證100%收集到所有的廢棄內(nèi)存。當(dāng)然隨著垃圾收集算法的不斷改進(jìn)以及軟硬件運(yùn)行效率的不斷提升,這些問題都可以迎刃而解。

          垃圾收集的算法分析

          Java語言規(guī)范沒有明確地說明JVM使用哪種垃圾回收算法,但是任何一種垃圾收集算法一般要做2件基本的事情:(1)發(fā)現(xiàn)無用信息對(duì)象;(2)回收被無用對(duì)象占用的內(nèi)存空間,使該空間可被程序再次使用。

          大多數(shù)垃圾回收算法使用了根集(root set)這個(gè)概念;所謂根集就量正在執(zhí)行的Java程序可以訪問的引用變量的集合(包括局部變量、參數(shù)、類變量),程序可以使用引用變量訪問對(duì)象的屬性和調(diào)用對(duì)象的方法。垃圾收集首選需要確定從根開始哪些是可達(dá)的和哪些是不可達(dá)的,從根集可達(dá)的對(duì)象都是活動(dòng)對(duì)象,它們不能作為垃圾被回收,這也包括從根集間接可達(dá)的對(duì)象。而根集通過任意路徑不可達(dá)的對(duì)象符合垃圾收集的條件,應(yīng)該被回收。下面介紹幾個(gè)常用的算法。

          1、  引用計(jì)數(shù)法(Reference Counting Collector)

          引用計(jì)數(shù)法是唯一沒有使用根集的垃圾回收的法,該算法使用引用計(jì)數(shù)器來區(qū)分存活對(duì)象和不再使用的對(duì)象。一般來說,堆中的每個(gè)對(duì)象對(duì)應(yīng)一個(gè)引用計(jì)數(shù)器。當(dāng)每一次創(chuàng)建一個(gè)對(duì)象并賦給一個(gè)變量時(shí),引用計(jì)數(shù)器置為1。當(dāng)對(duì)象被賦給任意變量時(shí),引用計(jì)數(shù)器每次加1當(dāng)對(duì)象出了作用域后(該對(duì)象丟棄不再使用),引用計(jì)數(shù)器減1,一旦引用計(jì)數(shù)器為0,對(duì)象就滿足了垃圾收集的條件。

          基于引用計(jì)數(shù)器的垃圾收集器運(yùn)行較快,不會(huì)長(zhǎng)時(shí)間中斷程序執(zhí)行,適宜地必須 實(shí)時(shí)運(yùn)行的程序。但引用計(jì)數(shù)器增加了程序執(zhí)行的開銷,因?yàn)槊看螌?duì)象賦給新的變量,計(jì)數(shù)器加1,而每次現(xiàn)有對(duì)象出了作用域生,計(jì)數(shù)器減1

          2tracing算法(Tracing Collector)

          tracing算法是為了解決引用計(jì)數(shù)法的問題而提出,它使用了根集的概念。基于tracing算法的垃圾收集器從根集開始掃描,識(shí)別出哪些對(duì)象可達(dá),哪些對(duì)象不可達(dá),并用某種方式標(biāo)記可達(dá)對(duì)象,例如對(duì)每個(gè)可達(dá)對(duì)象設(shè)置一個(gè)或多個(gè)位。在掃描識(shí)別過程中,基于tracing算法的垃圾收集也稱為標(biāo)記和清除(mark-and-sweep)垃圾收集器.

          3compacting算法(Compacting Collector)

          為了解決堆碎片問題,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的過程中,算法將所有的對(duì)象移到堆的一端,堆的另一端就變成了一個(gè)相鄰的空閑內(nèi)存區(qū),收集器會(huì)對(duì)它移動(dòng)的所有對(duì)象的所有引用進(jìn)行更新,使得這些引用在新的位置能識(shí)別原來 的對(duì)象。在基于Compacting算法的收集器的實(shí)現(xiàn)中,一般增加句柄和句柄表。  

          4copying算法(Coping Collector)

          該算法的提出是為了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時(shí)把堆分成 一個(gè)對(duì)象 面和多個(gè)空閑面, 程序從對(duì)象面為對(duì)象分配空間,當(dāng)對(duì)象滿了,基于coping算法的垃圾 收集就從根集中掃描活動(dòng)對(duì)象,并將每個(gè) 活動(dòng)對(duì)象復(fù)制到空閑面(使得活動(dòng)對(duì)象所占的內(nèi)存之間沒有空閑洞),這樣空閑面變成了對(duì)象面,原來的對(duì)象面變成了空閑面,程序會(huì)在新的對(duì)象面中分配內(nèi)存。

          一種典型的基于coping算法的垃圾回收是stop-and-copy算法,它將堆分成對(duì)象面和空閑區(qū)域面,在對(duì)象面與空閑區(qū)域面的切換過程中,程序暫停執(zhí)行。

          5generation算法(Generational Collector)
            stop-and-copy垃圾收集器的一個(gè)缺陷是收集器必須復(fù)制所有的活動(dòng)對(duì)象,這增加了程序等待時(shí)間,這是coping算法低效的原因。在程序設(shè)計(jì)中有這樣的規(guī)律:多數(shù)對(duì)象存在的時(shí)間比較短,少數(shù)的存在時(shí)間比較長(zhǎng)。因此,generation算法將堆分成兩個(gè)或多個(gè),每個(gè)子堆作為對(duì)象的一代(generation)。由于多數(shù)對(duì)象存在的時(shí)間比較短,隨著程序丟棄不使用的對(duì)象,垃圾收集器將從最年輕的子堆中收集這些對(duì)象。在分代式的垃圾收集器運(yùn)行后,上次運(yùn)行存活下來的對(duì)象移到下一最高代的子堆中,由于老一代的子堆不會(huì)經(jīng)常被回收,因而節(jié)省了時(shí)間。

          6adaptive算法(Adaptive Collector)

          在特定的情況下,一些垃圾收集算法會(huì)優(yōu)于其它算法。基于Adaptive算法的垃圾收集器就是監(jiān)控當(dāng)前堆的使用情況,并將選擇適當(dāng)算法的垃圾收集器。

          透視Java垃圾回收

          1、命令行參數(shù)透視垃圾收集器的運(yùn)行

          2、使用System.gc()可以不管JVM使用的是哪一種垃圾回收的算法,都可以請(qǐng)求Java的垃圾回收。在命令行中有一個(gè)參數(shù)-verbosegc可以查看Java使用的堆內(nèi)存的情況,它的格式如下:

          java -verbosegc classfile

            可以看個(gè)例子:

          class TestGC
          {
           public static void main(String[] args)
           {
            new TestGC();
            System.gc();
            System.runFinalization();
           }
          }


            在這個(gè)例子中,一個(gè)新的對(duì)象被創(chuàng)建,由于它沒有使用,所以該對(duì)象迅速地變?yōu)榭蛇_(dá),程序編譯后,執(zhí)行命令: java -verbosegc TestGC 后結(jié)果為:

          [Full GC 168K->97K(1984K), 0.0253873 secs]

            機(jī)器的環(huán)境為,Windows 2000 + JDK1.3.1,箭頭前后的數(shù)據(jù)168K97K分別表示垃圾收集GC前后所有存活對(duì)象使用的內(nèi)存容量,說明有168K-97K=71K的對(duì)象容量被回收,括號(hào)內(nèi)的數(shù)據(jù)1984K為堆內(nèi)存的總?cè)萘浚占枰臅r(shí)間是0.0253873秒(這個(gè)時(shí)間在每次執(zhí)行的時(shí)候會(huì)有所不同)。

            2finalize方法透視垃圾收集器的運(yùn)行

            在JVM垃圾收集器收集一個(gè)對(duì)象之前 ,一般要求程序調(diào)用適當(dāng)?shù)姆椒ㄡ尫刨Y源,但在沒有明確釋放資源的情況下,Java提供了缺省機(jī)制來終止化該對(duì)象心釋放資源,這個(gè)方法就是finalize()。它的原型為:

          protected void finalize() throws Throwable

            在finalize()方法返回之后,對(duì)象消失,垃圾收集開始執(zhí)行。原型中的throws Throwable表示它可以拋出任何類型的異常。

            之所以要使用finalize(),是由于有時(shí)需要采取與Java的普通方法不同的一種方法,通過分配內(nèi)存來做一些具有C風(fēng)格的事情。這主要可以通過"固有方法"來進(jìn)行,它是從Java里調(diào)用非Java方法的一種方式。CC++是目前唯一獲得固有方法支持的語言。但由于它們能調(diào)用通過其他語言編寫的子程序,所以能夠有效地調(diào)用任何東西。在非Java代碼內(nèi)部,也許能調(diào)用Cmalloc()系列函數(shù),用它分配存儲(chǔ)空間。而且除非調(diào)用了free(),否則存儲(chǔ)空間不會(huì)得到釋放,從而造成內(nèi)存"漏洞"的出現(xiàn)。當(dāng)然,free()是一個(gè)CC++函數(shù),所以我們需要在finalize()內(nèi)部的一個(gè)固有方法中調(diào)用它。也就是說我們不能過多地使用finalize(),它并不是進(jìn)行普通清除工作的理想場(chǎng)所。

            在普通的清除工作中,為清除一個(gè)對(duì)象,那個(gè)對(duì)象的用戶必須在希望進(jìn)行清除的地點(diǎn)調(diào)用一個(gè)清除方法。這與C++"破壞器"的概念稍有抵觸。在C++中,所有對(duì)象都會(huì)破壞(清除)。或者換句話說,所有對(duì)象都"應(yīng)該"破壞。若將C++對(duì)象創(chuàng)建成一個(gè)本地對(duì)象,比如在堆棧中創(chuàng)建(在Java中是不可能的),那么清除或破壞工作就會(huì)在"結(jié)束花括號(hào)"所代表的、創(chuàng)建這個(gè)對(duì)象的作用域的末尾進(jìn)行。若對(duì)象是用new創(chuàng)建的(類似于Java),那么當(dāng)程序員調(diào)用C++delete命令時(shí)(Java沒有這個(gè)命令),就會(huì)調(diào)用相應(yīng)的破壞器。若程序員忘記了,那么永遠(yuǎn)不會(huì)調(diào)用破壞器,我們最終得到的將是一個(gè)內(nèi)存"漏洞",另外還包括對(duì)象的其他部分永遠(yuǎn)不會(huì)得到清除。

            相反,Java不允許我們創(chuàng)建本地(局部)對(duì)象--無論如何都要使用new。但在Java中,沒有"delete"命令來釋放對(duì)象,因?yàn)槔占鲿?huì)幫助我們自動(dòng)釋放存儲(chǔ)空間。所以如果站在比較簡(jiǎn)化的立場(chǎng),我們可以說正是由于存在垃圾收集機(jī)制,所以Java沒有破壞器。然而,隨著以后學(xué)習(xí)的深入,就會(huì)知道垃圾收集器的存在并不能完全消除對(duì)破壞器的需要,或者說不能消除對(duì)破壞器代表的那種機(jī)制的需要(而且絕對(duì)不能直接調(diào)用finalize(),所以應(yīng)盡量避免用它)。若希望執(zhí)行除釋放存儲(chǔ)空間之外的其他某種形式的清除工作,仍然必須調(diào)用Java中的一個(gè)方法。它等價(jià)于C++的破壞器,只是沒后者方便。

            下面這個(gè)例子向大家展示了垃圾收集所經(jīng)歷的過程,并對(duì)前面的陳述進(jìn)行了總結(jié)。

          class Chair {
           static boolean gcrun = false;
           static boolean f = false;
           static int created = 0;
           static int finalized = 0;
           int i;
           Chair() {
            i = ++created;
            if(created == 47)
             System.out.println("Created 47");
           }
           protected void finalize() {
            if(!gcrun) {
             gcrun = true;
             System.out.println("Beginning to finalize after " + created + " Chairs have been created");
            }
            if(i == 47) {
             System.out.println("Finalizing Chair #47, " +"Setting flag to stop Chair creation");
             f = true;
            }
            finalized++;
            if(finalized >= created)
             System.out.println("All " + finalized + " finalized");
           }
          }

          public class Garbage {
           public static void main(String[] args) {
            if(args.length == 0) {
             System.err.println("Usage: \n" + "java Garbage before\n or:\n" + "java Garbage after");
             return;
            }
            while(!Chair.f) {
             new Chair();
             new String("To take up space");
            }
            System.out.println("After all Chairs have been created:\n" + "total created = " + Chair.created +
          ", total finalized = " + Chair.finalized);
            if(args[0].equals("before")) {
              System.out.println("gc():");
              System.gc();
              System.out.println("runFinalization():");
              System.runFinalization();
            }
            System.out.println("bye!");
            if(args[0].equals("after"))
             System.runFinalizersOnExit(true);
           }
          }


            上面這個(gè)程序創(chuàng)建了許多Chair對(duì)象,而且在垃圾收集器開始運(yùn)行后的某些時(shí)候,程序會(huì)停止創(chuàng)建Chair。由于垃圾收集器可能在任何時(shí)間運(yùn)行,所以我們不能準(zhǔn)確知道它在何時(shí)啟動(dòng)。因此,程序用一個(gè)名為gcrun的標(biāo)記來指出垃圾收集器是否已經(jīng)開始運(yùn)行。利用第二個(gè)標(biāo)記fChair可告訴main()它應(yīng)停止對(duì)象的生成。這兩個(gè)標(biāo)記都是在finalize()內(nèi)部設(shè)置的,它調(diào)用于垃圾收集期間。另兩個(gè)static變量--created以及finalized--分別用于跟蹤已創(chuàng)建的對(duì)象數(shù)量以及垃圾收集器已進(jìn)行完收尾工作的對(duì)象數(shù)量。最后,每個(gè)Chair都有它自己的(非staticint i,所以能跟蹤了解它具體的編號(hào)是多少。編號(hào)為47Chair進(jìn)行完收尾工作后,標(biāo)記會(huì)設(shè)為true,最終結(jié)束Chair對(duì)象的創(chuàng)建過程。(關(guān)于這個(gè)例子的更具體的分析和說明請(qǐng)參看《Java編程思想》的第四章)

            關(guān)于垃圾收集的幾點(diǎn)補(bǔ)充

            經(jīng)過上述的說明,可以發(fā)現(xiàn)垃圾回收有以下的幾個(gè)特點(diǎn):

            (1)垃圾收集發(fā)生的不可預(yù)知性:由于實(shí)現(xiàn)了不同的垃圾收集算法和采用了不同的收集機(jī)制,所以它有可能是定時(shí)發(fā)生,有可能是當(dāng)出現(xiàn)系統(tǒng)空閑CPU資源時(shí)發(fā)生,也有可能是和原始的垃圾收集一樣,等到內(nèi)存消耗出現(xiàn)極限時(shí)發(fā)生,這與垃圾收集器的選擇和具體的設(shè)置都有關(guān)系。

            (2)垃圾收集的精確性:主要包括2 個(gè)方面:(a)垃圾收集器能夠精確標(biāo)記活著的對(duì)象;(b)垃圾收集器能夠精確地定位對(duì)象之間的引用關(guān)系。前者是完全地回收所有廢棄對(duì)象的前提,否則就可能造成內(nèi)存泄漏。而后者則是實(shí)現(xiàn)歸并和復(fù)制等算法的必要條件。所有不可達(dá)對(duì)象都能夠可靠地得到回收,所有對(duì)象都能夠重新分配,允許對(duì)象的復(fù)制和對(duì)象內(nèi)存的縮并,這樣就有效地防止內(nèi)存的支離破碎。(3)現(xiàn)在有許多種不同的垃圾收集器,每種有其算法且其表現(xiàn)各異,既有當(dāng)垃圾收集開始時(shí)就停止應(yīng)用程序的運(yùn)行,又有當(dāng)垃圾收集開始時(shí)也允許應(yīng)用程序的線程運(yùn)行,還有在同一時(shí)間垃圾收集多線程運(yùn)行。

            (4)垃圾收集的實(shí)現(xiàn)和具體的JVM 以及JVM的內(nèi)存模型有非常緊密的關(guān)系。不同的JVM 可能采用不同的垃圾收集,而JVM 的內(nèi)存模型決定著該JVM可以采用哪些類型垃圾收集。現(xiàn)在,HotSpot 系列JVM中的內(nèi)存系統(tǒng)都采用先進(jìn)的面向?qū)ο蟮目蚣茉O(shè)計(jì),這使得該系列JVM都可以采用最先進(jìn)的垃圾收集。

            (5)隨著技術(shù)的發(fā)展,現(xiàn)代垃圾收集技術(shù)提供許多可選的垃圾收集器,而且在配置每種收集器的時(shí)候又可以設(shè)置不同的參數(shù),這就使得根據(jù)不同的應(yīng)用環(huán)境獲得最優(yōu)的應(yīng)用性能成為可能。

            針對(duì)以上特點(diǎn),我們?cè)谑褂玫臅r(shí)候要注意:

            (1)不要試圖去假定垃圾收集發(fā)生的時(shí)間,這一切都是未知的。比如,方法中的一個(gè)臨時(shí)對(duì)象在方法調(diào)用完畢后就變成了無用對(duì)象,這個(gè)時(shí)候它的內(nèi)存就可以被釋放。

            (2Java中提供了一些和垃圾收集打交道的類,而且提供了一種強(qiáng)行執(zhí)行垃圾收集的方法--調(diào)用System.gc(),但這同樣是個(gè)不確定的方法。Java 中并不保證每次調(diào)用該方法就一定能夠啟動(dòng)垃圾收集,它只不過會(huì)向JVM發(fā)出這樣一個(gè)申請(qǐng),到底是否真正執(zhí)行垃圾收集,一切都是個(gè)未知數(shù)。

            (3)挑選適合自己的垃圾收集器。一般來說,如果系統(tǒng)沒有特殊和苛刻的性能要求,可以采用JVM的缺省選項(xiàng)。否則可以考慮使用有針對(duì)性的垃圾收集器,比如增量收集器就比較適合實(shí)時(shí)性要求較高的系統(tǒng)之中。系統(tǒng)具有較高的配置,有比較多的閑置資源,可以考慮使用并行標(biāo)記/清除收集器。

            (4)關(guān)鍵的也是難把握的問題是內(nèi)存泄漏。良好的編程習(xí)慣和嚴(yán)謹(jǐn)?shù)木幊虘B(tài)度永遠(yuǎn)是最重要的,不要讓自己的一個(gè)小錯(cuò)誤導(dǎo)致內(nèi)存出現(xiàn)大漏洞。

            (5)盡早釋放無用對(duì)象的引用。大多數(shù)程序員在使用臨時(shí)變量的時(shí)候,都是讓引用變量在退出活動(dòng)域(scope)后,自動(dòng)設(shè)置為null,暗示垃圾收集器來收集該對(duì)象,還必須注意該引用的對(duì)象是否被監(jiān)聽,如果有,則要去掉監(jiān)聽器,然后再賦空值。

            結(jié)束語

            一般來說,Java開發(fā)人員可以不重視JVM中堆內(nèi)存的分配和垃圾處理收集,但是,充分理解Java的這一特性可以讓我們更有效地利用資源。同時(shí)要注意finalize()方法是Java的缺省機(jī)制,有時(shí)為確保對(duì)象資源的明確釋放,可以編寫自己的finalize方法。

           

           

           

          posted @ 2005-12-26 17:46 FinalFantasy 閱讀(1253) | 評(píng)論 (2)編輯 收藏

          Problem Statement

          You are given a String[] cityMap representing the layout of a city. The city consists of blocks. The first element of cityMap represents the first row of blocks, etc. A 'B' character indicates a location where there is a bus stop. There will be exactly one 'X' character, indicating your location. All other characters will be '.'. You are also given an int walkingDistance, which is the maximum distance you are willing to walk to a bus stop. The distance should be calculated as the number of blocks vertically plus the number of blocks horizontally. Return the number of bus stops that are within walking distance of your current location.

          Definition

          Class:BusStops
          Method:countStops
          Parameters:String[], int
          Returns:int
          Method signature:int countStops(String[] cityMap, int walkingDistance)
          (be sure your method is public)

          Constraints

          -cityMap will contain between 1 and 50 elements, inclusive.
          -Each element of cityMap will contain between 1 and 50 characters, inclusive.
          -Each element of cityMap will contain the same number of characters.
          -Each character of each element of cityMap will be 'B', 'X', or '.'.
          -There will be exactly one 'X' character in cityMap.
          -walkingDistance will be between 1 and 100, inclusive.

          Examples

          0)

          {"...B.",
           ".....",
           "..X.B",
           ".....",
           "B...."}
          3
          Returns: 2
          You can reach the bus stop at the top (3 units away), or on the right (2 units away). The one in the lower left is 4 units away, which is too far.

          1)

          {"B.B..",
           ".....",
           "B....",
           ".....",
           "....X"}
          8
          Returns: 3
          A distance of 8 can get us anywhere on the map, so we can reach all 3 bus stops.

          2)

          {"BBBBB",
           "BB.BB",
           "B.X.B",
           "BB.BB",
           "BBBBB"}
          1
          Returns: 0
          Plenty of bus stops, but unfortunately we cannot reach any of them.

          3)

          {"B..B..",
           ".B...B",
           "..B...",
           "..B.X.",
           "B.B.B.",
           ".B.B.B"}
          3
          Returns: 7


          說實(shí)話我覺得這一題沒啥意思,超簡(jiǎn)單,首先先確定X的位置,再用遍歷數(shù)組找B的位置,再求相減的絕對(duì)值然后判斷是否超出給出的最大距離就行了。相對(duì)這題PlayCars卻很有意思,到現(xiàn)在我也沒想出除了窮舉以外的一個(gè)更好的算法,因?yàn)槲矣X得窮舉可能會(huì)超時(shí)。有哪位有其它的辦法的話,請(qǐng)告訴我,大家探討一下,謝謝。好了,不廢話了,下面是這題的答案:

          public class BusStops {
           public static void main(String[] arg){
            BusStops total = new BusStops();
            
              System.out.println(total.countStops({"...B.",".....","..X.B",".....","B...."},3));
           }
           
           public int countStops(String[] cityMap, int walkingDistance){
            int sum= 0;
            int locationX = -1;
            int locationY = -1;
            for(int i=0;i<cityMap.length;i++){
             for(int j=0;j<cityMap[i].length();j++){
              if(cityMap[i].charAt(j)=='X'){
               locationX = i;
               locationY = j;
              }
             }
            }
            for(int i=0;i<cityMap.length;i++){
             for(int j=0;j<cityMap[i].length();j++){
              if(cityMap[i].charAt(j)=='B' && (Math.abs(locationX - i) + Math.abs(locationY - j)<=walkingDistance))
               sum++;
             }
            }
            return sum;
           }
          }
          posted @ 2005-12-21 18:24 FinalFantasy 閱讀(665) | 評(píng)論 (1)編輯 收藏

          主站蜘蛛池模板: 吴桥县| 鹤岗市| 育儿| 峨山| 阜宁县| 定日县| 巴塘县| 黔东| 吴川市| 桑日县| 黑水县| 新宁县| 溧阳市| 泾川县| 湘潭市| 岳西县| 新和县| 鱼台县| 高淳县| 叶城县| 嘉善县| 资源县| 吴桥县| 上蔡县| 阿图什市| 泰安市| 连平县| 中宁县| 沁源县| 郎溪县| 红安县| 商河县| 甘泉县| 永登县| 武山县| 肃北| 天全县| 沐川县| 浦东新区| 饶河县| 弥勒县|