總網頁瀏覽量

顯示具有 Java 標籤的文章。 顯示所有文章
顯示具有 Java 標籤的文章。 顯示所有文章

2013年5月31日 星期五

取得主機ip與名字---InetAddress

public static void main(String[] args)  {
try{
//註解是列印的結果

// InetAddress adr = InetAddress.getLocalHost();
//向主機取得InetAddress物件
//InetAddress adr = InetAddress.getByName("google.com");//google.com/74.125.31.100
//向網域名稱取得InetAddress物件

byte[] ip={8,8,8,8};
InetAddress adr = InetAddress.getByAddress(ip);
//google-public-dns-a.google.com/8.8.8.8
//以ip取得主機名稱

System.out.println(adr.getHostAddress());
System.out.println(adr.getHostName());
System.out.println(adr);

}catch(UnknownHostException e){

System.out.println("Error 404");

}
}

2013年5月30日 星期四

邏輯運算子與位元運算子

邏輯運算子: &&

4 && 5 會comple error
運算元必須是邏輯判斷式、true、false


位元運算子: &

4 & 5 相當於 100 and 101
結果等於4


應用在條件判斷式
if((num2>100)&(--num1>0))
如果num2>100為false那麼 num1不會進行運算

if((num2>100) && (--num1>0))
那麼即使num2>100為false
--num1會進行運算再作條件判斷



2013年5月4日 星期六

計算機(附打地鼠)


發想:
小學時候買過一種計算機
除了計算功能之外可以玩遊戲
其中有一款是打地鼠遊戲
因為找不到有程式這款遊戲
所以就寫個計算機程式當作練習
也順便實現這遊戲


本遊戲採用swing元件來實作

整個畫面是BoredLayout
North區塊放label;Center區塊放JPanel物件
JPanel採用GridLayout


第一個檔案UI.java

/*
 * 此檔專用來版面配置
 *
 * */

package EraseNum;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class UI extends JFrame {

static UI windows = new UI();
static Container cp = windows.getContentPane();
// static JButton game = new JButton("打地鼠");
// static JLabel label= new JLabel("這是Label");
static JTextField textfield = new JTextField();
static JPanel jpanel = new JPanel();
static JButton[] buttons = new JButton[25];

UI() {

}

public static void main(String[] args) {

windows.setTitle("Erase Number");
windows.setSize(550, 500);
cp.setLayout(new BorderLayout(10, 10));
// 10是水平與垂直間距
cp.setBackground(Color.pink);

// ======TextBox=====

Font font = new Font("新細明體", Font.ITALIC + Font.BOLD, 16);
Font lb_font = new Font("新細明體", Font.ITALIC + Font.BOLD, 58);
// label.setFont(lb_font);
// cp.add(label,BorderLayout.NORTH);
// BorderLayout.North不寫的話預設放在中間且填滿整個螢幕

// 靠右對其
textfield.setHorizontalAlignment(JTextField.RIGHT);
textfield.setFont(lb_font);
textfield.setEditable(false);
cp.add(textfield, BorderLayout.NORTH);

// ======TextBox=====

// =======Panel放置GridLayout
jpanel.setLayout(new GridLayout(5, 5, 5, 5));

String[] Button_Name =
{ "score", "GAME", "Back", "Calcu", "Level",
"7", "8", "9", "/", "sqrt",
"4", "5", "6", "*", "%",
"1", "2","3", "-", "pow",
"0", ".", "=", "+", "-/+" };

ButtonActionListener listener = new ButtonActionListener();

for (int i = 0; i < 25; i++) {
buttons[i] = new JButton(Button_Name[i]);
buttons[i].setFont(font);
buttons[i].setName(Button_Name[i]);
buttons[i].setEnabled(true);
// 設定按鈕可不可以按
buttons[i].addActionListener(listener);
// 事件傾聽者向各位按鈕註冊
jpanel.add(buttons[i]);

}
cp.add(jpanel);

// =====JPanel=======
windows.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
windows.setVisible(true);

}

}


第二個檔案:Mole.java



/*
 * 此檔案是打地鼠的程式運作
 *
 * */


package EraseNum;

public class Mole implements Runnable {

private String txtNumber;
private int Number;
private boolean isContinue = true;
// 因為thread不能重新start所以自行宣告method多加一層迴圈了

private int score = 0;
private int level = 1;
private int sleep = 1700;
private int life = 3;

@Override
public void run() {

while (true) {
while (isContinue) {
txtNumber = UI.textfield.getText();
Number = (int) (Math.random() * 10);

UI.textfield.setText(txtNumber + Integer.toString(Number));

try {

Thread.sleep(sleep);
} catch (InterruptedException e) {

e.printStackTrace();
}

if (UI.textfield.getText().length() == 12) {
isContinue = false;
}

}// isContinue
}// true

}

public void terminate() {

isContinue = false;

}

public void restart() {

isContinue = true;

}

public boolean isGameover() {

return isContinue;
}

public void addscore() {

int length = UI.textfield.getText().length();

switch (length) {
case 0:
case 1:
case 2:
case 3:
score = score + 100 * level;
break;
case 4:
case 5:
case 6:
score = score + 80 * level;
break;
default:
score = score + 60 * level;
break;
}

UI.buttons[0].setText(Integer.toString(score));
}

public void levelup() {
if (score > 150000) {
level = 10;
sleep = 400;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 70000) {
level = 9;
sleep = 500;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 45000) {
sleep = 600;
level = 8;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 30000) {
sleep = 700;
level = 7;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 15000) {
sleep = 800;
level = 6;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 10000) {
sleep = 900;
level = 5;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 5500) {
sleep = 1000;
level = 4;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 3000) {
sleep = 1300;
level = 3;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else if (score > 1000) {
sleep = 1500;
level = 2;
UI.buttons[4].setText("Level:"+Integer.toString(level));

} else {
sleep = 1700;
level = 1;
UI.buttons[4].setText("Level:"+Integer.toString(level));
}

}

public void  initialScore(){
score=0;
sleep=1700;
}


}


第三個檔案 ButtonActionListener.java


package EraseNum;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public class ButtonActionListener implements ActionListener {

private boolean isPlaying = false;
private boolean isCalculator = true;

Mole mole;
Thread thread;

@Override
public void actionPerformed(ActionEvent e) {

JButton btn = (JButton) e.getSource();
// 取得事件來源物件
String str = btn.getText();
String str2 = btn.getName();
// 如果沒有setName會回傳null喔
// 到底要用getText還是getName呢?

// 進入打地鼠遊戲
if (str.equals("GAME")) {
isCalculator = false;
isPlaying = true;

UI.buttons[4].setText("Level:"+1);
UI.buttons[0].setText("分數:0");

if (thread == null) {
//初次執行遊戲
UI.textfield.setText("");// 清空JTextfield
mole = new Mole();
thread = new Thread(mole);
thread.start();
// JTextField自動跑出數字
// start()? Thread()?
// 按下數字鍵會削掉數字

} else {
//重啟遊戲
//因為執行緒不可以再次.start()
//所以自己寫method解決掉吧
UI.textfield.setText("");
mole.initialScore();

mole.restart();
}

return;

}

// 計算機功能
if (str.equals("Calcu")) {
isCalculator = true;
isPlaying = false;

if (thread != null) {
mole.terminate();
thread = null;

}

UI.textfield.setText("0");
return;

}

if (isCalculator) {

Calculator(str);

} else {

EraseNumberGame(str);

}

}

public void Calculator(String str) {

// 按下小數點
if (str.equals(".")) {

String Jtxt = UI.textfield.getText();
if (!Jtxt.contains(".")) {
// 小數點只能出現一個
UI.textfield.setText(UI.textfield.getText() + str);
return;
}

}

// 加上負號
// if (str.equals("+/-")) {
//
// Game.textfield.setText(Game.textfield.getText() + str2);
// return;
//
// }

// 按下數字鍵
for (int i = 0; i < 10; i++) {
if (str.equals(Integer.toString(i))) {

String Jtxt = UI.textfield.getText();

if(Jtxt.length()==1 && Jtxt.charAt(0)=='0'){
UI.textfield.setText(str);
}
else{
// 沒有append method
UI.textfield.setText(UI.textfield.getText() + str);
// 做成append效果

}

return;
}
}

}

public void EraseNumberGame(String str) {
// 遊戲結束嗎
if (mole.isGameover()) {
// 按到哪個數字啊
for (int i = 0; i < 10; i++) {
if (str.equals(Integer.toString(i))) {
// JTextField的字串不可以空字串,否則會outofboundexception
if (UI.textfield.getText().length() > 0) {
// 如果textfield第一個字元跟玩家按的數字鍵一樣
if (String.valueOf(UI.textfield.getText().charAt(0))
.equals(Integer.toString(i))) { // 按下的數字鍵是textbox第一個字
// System.out.println(UI.textfield.getText().substring(1));
// 刪掉第一個數字
UI.textfield.setText(UI.textfield.getText()
.substring(1));

mole.addscore();
mole.levelup();

}
}
return;
}
}
}

}

}



Java UI2(swing)



swing是awt加強版。awt的元件都可被swing替代,swing改善awt耗費系統資源與介面醜陋的問題。

swing所有的元件都直接或間接繼承自java.awt.Container類別。

java並不是將物件放在JFrame這一層而是放在ContentPane這層
因此將物件放到視窗之前必須使用Container getContentPane();
method取得視窗容器


注意:
Container有設定Layout的話,Button,Lable等元件的大小、位置設置也會由layout管理。
也就是說layout除了版面配置也會對button,lable的設定做限制
BorderLayout裡面的元件不可以自己setSize設定大小


1.準備JFrame視窗設定大小與標題

import javax.swing.JFrame;

class GameWindow extends JFrame

GameWindow  windows = new GameWindow();
//如果宣告static GameWindow windows=new GameWindow();
//在建構子不可以用windows.setTitle()之類的method
//也許是在new時候還沒有配置記憶體給windows給他
//還沒初始化成功

//Œ–利用static宣告JFrame物件,不要在建構式裡面利用類別變數設定初值
//因為類別變數在執行時才會配置記憶體


windows.setTitle("JFrame視窗標題");
windows.setSize(550,500);
windows.setDefaultCloseOperation(JFrame.EXIST_ON_CLOSE);
windows.setVisible(true);


swing的JFrame視窗比awt複雜,swing視窗包含多個層級,Top level container,root pane , layered pane ,glass pane,每個層級都有特定的功用。
其中以content pane最常用,因為swing的物件幾乎放在content pane這層級。
一開始new 出的JFrame屬於Top level container層級
JFrame繼承自awt的Frame類別因此JFrame可以用Frame的method。

JFrame執行後如果按下關閉視窗X按鈕,JFrame仍會停留在記憶體
因此務必要加上

windows.setDefaultCloseOperation(JFrame.EXIST_ON_CLOSE);
告訴JFrame視窗關閉時候記憶體也要關閉JFrame
否則預設Hide_ON_Close,只是隱藏視窗而已




2.取得ContentPane並設定Layout

import java.awt.Container;
Coantainer cp=windows.getContentPane();//取得視窗容器
cp.setLayout(new FlowLayout());
cp.setBackground(Color.pink);

ContentPane物件相當於awt的Frame
設定Layout種類.setLayout(Layout物件);
設定背景顏色.setBackground(Color.pink);
皆在ContentPane


3.將物件放到ContentPane裡面

//Button game = new Button("打地鼠");
//會出現亂碼,即使workspace以及project property設定為UTF8
//run configuration→common→encoding設定UTF8也一樣
JButton game = new JButton("打地鼠");
//用JButton就OK了
cp.add(game);



4.
GridLayout附加元件順序是由左而右 由上而下





static Game windows = new Game();
static Container cp = windows.getContentPane();
static JButton game = new JButton("打地鼠");
static JLabel label= new JLabel("這是Label");
static JPanel jpanel = new JPanel();

Game(){
// windows.setTitle("Erase Number");
//windows.setSize(550,500 );
// windows.setVisible(true);


}

public static void main(String[] args) {

windows.setTitle("Erase Number");
windows.setSize(550,500);
// cp.setLayout(new GridLayout(4,4));
// cp.setLayout(new FlowLayout());
//如果要自己設定button大小,將layout設定Null
//因為設定layout就是讓layout管理該container
cp.setLayout(new BorderLayout(10,10));
cp.setBackground(Color.pink);

Font font=new Font("新細明體",Font.ITALIC+Font.BOLD,50);


//game.setSize(new Dimension(200,100));
//據說會被parent的setSize重設大小,按鈕在flowlayout看起來是wrap_content
//JButton會依照文字大小變化大小
game.setPreferredSize(new Dimension(50,50));
//無視版面配置自訂元件大小?? 在BorderLayout也沒用阿
//雖然大小解決了但是字體卻變成小黑點
//利用Font物件可以指定字體大小了
//但是flowlayout還是小黑點,結果好像是JButton大小裝不下這麼大的字體


game.setFont(font);

label.setSize(200, 100);
label.setFont(font);

cp.add(label,BorderLayout.NORTH);
//BorderLayout.North不寫的話預設放在中間且填滿整個螢幕
cp.add(game,BorderLayout.CENTER);

windows.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
windows.setVisible(true);

}

2013年5月3日 星期五

Date物件,DateFormat,NumberFormat,RegularExpression

Date相關類別放在
java.util.*;


Date date = new Date();//不給參數是抓程式執行時的時間
sysout(date);
印出Fri May 03 16:27:32 CST 2013

Date date = new Date(long number);
//抓取從19701/1/8:00開始經過number豪秒的日期時間
//如果number等於九億,那麼date就是1998/7/10凌晨十二點


date.getTime();
//回傳自1970/1/1 08:00:00以來的毫秒數



NumberFormat
數字轉換格式
例如:義大利的小數點跟千分位符號跟美國相反
這兩種不同文化數字轉換可以利用NumberFormat


DateFormat
轉換日期格式
美國日期格式轉換成台灣日期格式可以利用這方式




Regular Expression規則運算式
在java以字串表示     "\\s*,\\s*"

運算式撰寫規則先指定希望使用者可以輸入的字元
\s:表示字串可以出現任何空白字元\t\n\f\r
\d:表示字串要出現0~9的數字
再從後面加上指定字元可以出現幾次
{n}:剛好出現n次
*  :指定字元出現0次以上

例子
\\d{4} :零到九的數字要出現四次



import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class DateTest {

    public static void main(String[] args) {

    Date date = new Date();
//Date(0)的話取到1970/1/1的日期
//表示經過零秒的意思

    Locale locale = Locale.getDefault();
    //取得JVM當前語言環境資訊並回傳 回傳locale物件

    //System.out.println(date);

    System.out.println(date.getTime());
//取得date記載的時間離1970/1/1經過多少毫秒
    System.out.println(Locale.getDefault());
//取得JVM使用的語言與地區  印出zh_TW

//    System.out.println(locale.getCountry());
//印出TW
//    System.out.println(locale.getDisplayCountry());
//印出台灣
//    System.out.println(locale.getLanguage());
//    System.out.println(locale.getDisplayLanguage());

    
//    NumberFormat nf=NumberFormat.getInstance(locale);
//    nf.setMaximumFractionDigits(6);
//    nf.setMinimumFractionDigits(3);
//    System.out.println(nf.format(Math.PI));
//    System.out.println(nf.format(20));
//        try {
//            Number n = nf.parse("123,456.119");
//            System.out.println(n.doubleValue());
//        } catch (ParseException ex) {
//            Logger.getLogger(DateTest.class.getName()).log(Level.SEVERE, null, ex);
//        }

    
    String ds1= "Sep 30, 2008";
    //得到一筆日期資料 美國格式
    //2008前面要空格,格式要對否則會ParseException
    DateFormat medium=DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.US);
    //宣告DateFormat物件  美國日期格式 長度中型寫法Sep 30, 2008    
    try {
            date = medium.parse(ds1);
        } catch (ParseException ex) {
            Logger.getLogger(DateTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    System.out.println(date);
    //印出Tue Sep 30 00:00:00 CST 2008
    
String ds2=    medium.format(date);
//將指定日期格式化回傳字串
//格式化的格式依照DateFormat當初宣告的style
    System.out.println(ds2);
    //印出Sep 30, 2008

//    如果要印台灣style的日期格式
    //另外宣告DateFormat物件
    DateFormat df=DateFormat.getDateInstance();
String ds3=  df.format(date);//date物件格式化回傳字串
    System.out.println(ds3);
    
    }
    }



import java.io.Console;

public class StringRegex {
    public static void main(String[] args) {
  //  String regex ="\\d{4}\\-\\d{1,2}\\-\\d{1,2}";
  //  \d表示0~9的數字
//        String regex ="\\d{4}-abc\\d{1,2}-\\d{1,2}";
      //減號目前測試不加上\\也沒關係
  //意思是減號跟abc一定要出現  
  String regex="";
        
        
        Console c = System.console();
    System.out.println("please input yr burthday(1222-10-11):");
   String birthday="";
    try{
     birthday=c.readLine();
    //使用者從cmd或console軟體輸入文字
   }catch(NullPointerException e){
   
   }
    boolean isValid=birthday.matches(regex);
    //比對文字是否符合regx字串規則運算式的要求
    
    System.out.println("coreect?"+isValid);
    
    
    String book="Java 城市設計,580.0,     呵呵";
    String[] bookInfo= book.split("\\s*,");
    //book字串符合split括號中規則運算式的部分會被當作分隔符號移除
    //  \\s表示任何空白字元(\t\n\f\r之類的就是)  , *表示可以出現零次以上
    //將逗號以及包含逗號前面的空白字元當作分隔符號刪掉並存入字串陣列
    System.out.println("Infomation:");
    for(String s:bookInfo)
        System.out.println(s);
    //呵呵前面的空白字元會印出來
    
    }
}

2013年4月30日 星期二

assert

assert用來捕抓程式在商業邏輯、現實活動運作流程上的錯誤。

assert(boolean) :"assertionErrorMessage"


要讓java 執行assert測試程式
在執行class時候要跟jvm說
java -ea XXXX
ea:enable assert


當條件式為false才會觸發AssertionError

2013年4月27日 星期六

SCJP觀念筆記以及考取心得

考完之後跟網路上傳說的一樣
猛虎出閘跟教戰手冊考題背一背就可以上場了
約莫四十五題來自這兩本後面習題
其中四十題一模一樣
剩下五題只是小地方修改
感覺很像在考大學通識課的期末考



不過,準備OCJP過程感覺自己有在變強這才是最重要的
重點是過程而不是那張紙
過程補足自己忽略掉的小細節觀念
至少這樣拿這張證照不會心虛

在做練習題時候感覺很像中學考試一樣
書上教大觀念,考試一直考小細節
剛開始做題目時候挫折感真的很重




1.物件強制轉型
父類別物件不可assign給子類別變數(compile erro)



父類別物件不可強制轉型成為子類別物件(可以compile,但是會ClassCastException)


Thingy t = new Thingy();
//Thingy是父類別型態存放父類別物件
DeluxeThingy k= (DeluxeThingy)t;
//強制轉型成子類別型態的t裝不下原本父類別的物件所以發生classcastexcetpion



Thingy t = new DeluxeThingy();
//父類別型態存放子類別物件

DeluxeThingy k= (DeluxeThingy)t;
//雖然t放的是子類別物件,因為t的型態是父類別所以要強制轉型



2.
javac -d course java/Hello.java
這句話意思是編譯java/Hello.java檔案
並且將.class放在目錄course底下


3.
有個檔案Vermouth.class
放在D:Java\course\accessmode底下
檔案內容為
package course.accessmode;
public class Vermouth{   }

Java是專案跟目錄


在D任何資料夾打上底下這行指令,皆可以順利執行
java -classpath  /Java  course.accessmode.Vermouth

在D:Java目錄打上底下這行,可以順利執行
java course.accessmode.Vermouth 


注意:不可以進入accessmode目錄(類別檔所在目錄)
執行java Vermouth
會出現NoClassFound,因為accessmode沒有course\accessmode資料夾
所以找不到

4.宣告介面後不可再宣告同名的類別



5.

short a=5;
int b =6;
a=b;//不給過
a=(short)b;//給過


6.在java裡所有基本型態資料的變數,傳遞到method均已傳值呼叫(pass by value)傳值呼叫不影響原來的變數值
(編譯器將變數值拷貝一份,再將這個拷貝的一份傳遞給method引數)

傳遞陣列或物件是以傳參照(pass by reference)方式傳參照是傳遞變數的參考位置,因此在method更改變數內容原先變數內容也會隨之更改
(編譯器將物件或陣列參考位址拷貝一份 傳給method引數)
此時有兩個變數操作到同一個實體


如果有上萬的元素的陣列,採用傳值呼叫傳遞引數
那麼編譯器勢必要複製上萬的元素的值,給引數
會降低效率
如果採用傳參照 只消複製一個參考位址給引數即可

7.多載:將功能相似的method 以相同名稱命名,編譯器會根據引數的個數與型態自動值星相對應的method。一個多載化的method 引數內容都是獨一無二的。因此如果有引數相同的method,就算傳回型態不同,編譯器也會搞不清楚該呼叫誰。compile error


8.
列舉型態本身也是類別一種
每個項目預設為public final static
當建立物件時MyColor color = MyColor.RED;
會呼叫建構子,而且是每個項目都呼叫一次
以下的例子會呼叫帶有參數的建構子
因此只寫下面這樣會error
必須加上帶有參數的建構子
public enum MyColor{ RED(0xff0000),GREEN(0x00ff00),BLUE(0x0000ff); }

2013年4月8日 星期一

事件處理

Java事件處理採取"委派事件模式"(delegation event model)。
委派事件模式:當事件發生時,產生事件的物件(event source)會將此一"訊息"轉給"事件傾聽者"(event listener)處理的一種方式。

訊息:java.awt.event事件類別庫裡的事件物件。

ex:按下Button會觸發一個動作事件,java產生一個"事件物件",將事件物件傳遞給事件傾聽者,事件傾聽者再將事件物件的種類將工作指派給事件處理者。


一個程式裡面允許多個事件傾聽者,為了讓"產生事件的物件"知道要將事件訊息傳送到哪一個"事件傾聽者",我們必須先把"事件傾聽者"向產生事件的物件註冊(register)。

事件傾聽者由"包含事件來源者"的物件擔任。
該物件必須實作implements ActionListener事件處理介面



事件類別有很多種

每個事件類別都有相對應的事件傾聽者

事件處理者包在事件傾聽者介面中,事件處理者是一堆method。

2013年4月7日 星期日

Java UI

import java.awt.*;  //使用視窗物件Frame 必須Import

Frame frm = new Frame("Window Title");//建立視窗物件,附上標題
frm.setSize(100,200);
frm.setBackground(Color.blue);
frm.setLocation(200,300);//視窗的位置
frm.setVisible(true);//讓視窗印在螢幕上


或者是
class XXX extnds Frame{

XXX frm = new XXX();

frm.setTitle("");
frm.setSize(100,200);
frm.setLocation(200,300);
frm.setVisible(true);


}



import java.awt.*;

public class UITest {
    static Frame frm= new Frame("label class");
    static Label lab = new Label();
    //label亂碼問題
    //file→project property→endocing選x-windows-950或x-MS950-SCS
   //這是netBean解決方法
    static Button btn = new Button("click me");
    static Checkbox ckb1= new Checkbox("電腦",true);
    static Checkbox ckb2= new Checkbox("人腦");
    static Checkbox ckb3= new Checkbox("豬腦",true);
 
    static Checkbox ckb4= new Checkbox("劉邦");
    static Checkbox ckb5 = new Checkbox("蕭何");
 
 
    public static void main(String[] args) {
      frm.setLayout(null);//加上這行就可以看到原來視窗底色
        frm.setSize(400, 300);
        frm.setBackground(Color.pink);
        lab.setText("初出茅廬");
        lab.setBackground(Color.gray);
       //執行結果只會看到灰色占滿版面,因為awt預設版面配置
        //將物件放大到與視窗同樣大小
        lab.setAlignment(Label.CENTER);
 //       lab.setForeground(Color.red);
   lab.setForeground(new Color(0xE12A94)); //自己建立color物件 設定顏色        
        lab.setLocation(50, 60);//設定label大小 位置
        lab.setSize(100,50);//上面的frm.setLayout(null);再加上這兩行才會正確顯示label位置大小
        Font fnt = new Font("新細明體",Font.ITALIC+Font.BOLD,22);//自型、style、size
        lab.setFont(fnt);              
        frm.add(lab);
       // lab.setVisible(true);

     
        btn.setBounds(100, 120, 70, 50);
        btn.setForeground(Color.red);
        btn.setBackground(Color.green);
        frm.add(btn);
//==============複選的checkbox作法 ,個別建立checkbox物件=====//      
//        ckb1.setSize(100, 50);
//        ckb2.setSize(100,50);
//        ckb3.setSize(100, 50);
//        ckb1.setLocation(200, 160);
//        ckb2.setLocation(200,200);
//        ckb3.setLocation(200, 230);
     
        ckb1.setBounds(200, 160, 100, 50);
        ckb2.setBounds(200, 200, 100, 50);
        ckb3.setBounds(200, 230, 100, 50);
        frm.add(ckb1);
        frm.add(ckb2);
        frm.add(ckb3);
     
//=========單選的checkbox作法,建立checkbox群組物件,設定checkbox屬於群組物件      
    CheckboxGroup grp = new CheckboxGroup();
    ckb4.setBounds(300, 200, 100, 50);
    ckb5.setBounds(300, 230, 100, 50);
        ckb4.setCheckboxGroup(grp);//將ckb4設定為grp的群組物件
        ckb5.setCheckboxGroup(grp);
     
        ckb4.setState(true);//預設選取
     
        frm.add(ckb4);
        frm.add(ckb5);
     
        frm.setVisible(true);
     
    }
}


Panel物件:面板。屬於containner子類別。可以做版面配置。
可以放進Frame物件。一個Frame可容納多個Panel
Panel可放button edittext checkbox等componemt





import java.awt.*;

public class PanelTest {
    static Frame frm=new Frame("Panel class");
    static Panel pnl = new Panel(new GridLayout(3,3));
//宣告Panel物件,並帶入layout物件。3x3格的]GridLayout
    static Label lab= new Label("Hello",Label.RIGHT);//標籤文字靠右對齊

    public static void main(String[] args) {
       frm.setLayout(null);//取消Frame版面配置,否則無法正確設定frame內部元件的大小
     
        // frm.setSize(600, 500);
     
        frm.setBounds(300,50, 600, 500);
        frm.setBackground(new Color(0x00ff99));
        frm.setResizable(false);//視窗設為固定大小
   
     
        lab.setBounds(20, 40, 60, 40);
        lab.setBackground(Color.red);

        pnl.setBounds(20, 80, 300, 220);
        pnl.setBackground(Color.GRAY);
        for(int i=1;i<=9;i++){
        pnl.add(new Button(Integer.toString(i)));
     
        }
     
        frm.add(lab);
        frm.add(pnl);
        frm.setVisible(true);
    }
}











2013年4月5日 星期五

不同物件來儲存同一物件、變數


宣告一個bank類別
在main method宣告兩個Rule物件
分別是warrior,wizard
將bank帶入warrior,wizard建構子
這樣warrior wizard儲存同一物件

(應用角色扮演的走地圖與判斷腳色走地圖的位置)

class Bank{
   private  int count=0;
    public  void add(){
    count++;
    }
    public void show(){
    System.out.println(count);
    }
 
}

class Rule{
private Bank bank ;
    Rule(Bank b){
    bank=b;  
    }
public void access(){
bank.add();
}    }


public class accessObj {
     public static void main(String[] args) {
         Bank bank = new Bank();
         Rule warrior = new Rule(bank);
         Rule wizard= new Rule(bank);
         warrior.access();
         wizard.access();
         bank.show();//印出count=2
     }
}

2013年3月13日 星期三

Map

Map:跟Collection相似,屬於物件容器,一次必須放兩個物件,一個表示鍵(key),一個表示該key所對應的值(value),兩個物件合起來稱作key-value-pair。key就好比是index,value好比是物件、儲存內容。

key是set類別物件。可以當作索引。
value是collection類別或子類別的物件。

Map是介面,
由Hashtable、HashMap實作,由SortedMap繼承
TreeMap實作SortedMap

TreeMap內容會依key值順序排序。



一、HashMap實作

import java.util.*;
public class HashMapTest {
    public static void main(String[] args) {
//宣告HashMap,key為Integer型態,value是String型態
HashMap<Integer,String> hmap= new HashMap<Integer,String>();
hmap.put(1001, "Kaiba");//新增資料,put(key,value)
hmap.put(100, "Conan");
hmap.put(345, "Dorara");

System.out.println(hmap.size());//map大小
System.out.println(hmap);//列印map key以及value
System.out.println(hmap.get(100));//取得key為100的value,傳回型態:泛型

System.out.println("hmap是否有關鍵值1001:");
System.out.println(hmap.containsKey(1001));
System.out.println(hmap.containsKey(199));

System.out.println("hmap是否有對應值Conan:");
System.out.println(hmap.containsValue("Conan"));
System.out.println(hmap.containsValue("Detective"));
   
System.out.println("================");
Set<Integer> set1 = hmap.keySet();//將所有的key set轉成實作set介面的物件
System.out.println(set1);
   
//String removeStr = hmap.remove(1001);
//    System.out.println(removeStr);
hmap.put(1999, "Conan");
Collection collobj=hmap.values();
//將map所有的value轉成實作collection介面的物件
//無法塞入List
System.out.println(collobj);  
    }
}



泛型Generics

類別裡面的變數若宣告為String那麼只能儲存字串型態的值,不能儲存數字、boolean值。
,如果想要一個變數可以儲存整數型態也可以儲存字串型態,java有一種功能可以讓我們自訂變數的型態。這就是泛型(Generics)基本功能。
(本質上並非讓使用者自訂變數型態,而是將變數包裝成Object的型態)

class Book<T>{//宣告類別並且裡面的變數跟method可以宣告為T型態,這邊T可以隨意亂打
private T price;//宣告T型態的變數,表示使用泛型(不限定資料類型)
public void setPrice(T price){
this.price=price;
}
public T getPrice(){
return price;
}}

public class Generics {

public static void main(String[]arg ){
Book<Integer> book1= new Book<Integer>();//<>裡面寫Integer表示,要將T指定為Integer,也就是說Book類別內容只要有T的地方都要換成Integer。
book1.setPrice(100);//所以這裡只能傳入整數,傳入其他型態的變數會編譯失敗
System.out.println(book1.getPrice());

Book book3 = new Book();//如果不指定T的類型,那就表示price什麼類型都可以接受
book3.setPrice(true);//傳入boolean值,自動轉型為Object型態
System.out.println(book3.getPrice());

book3.setPrice(11.8);//傳入double值,自動轉型為Object型態
System.out.println(book3.getPrice());
}}


執行結果:
100
true
11.8





class Book採用泛型宣告,相當於寫完所有基本型態變數的宣告,如同寫完下面的宣告:

class Book{
private Integer price;
public void setPrice(Integer price){
this.price=price;
}
public Integer getPrice(){
return price;
}}


class Book{
private String price;
public void setPrice(String price){
this.price=price;
}
public String getPrice(){
return price;
}}

二、泛型的進階設定-----限制變數型態的範圍。
比方說Book<? extends Number>

表示Book如果使用泛型,他的資料類型必須是Number類別或Number子類別。
Number子類別有Integer,Byte,Short,Long,Float,Double。

class Book<T>{
T price;
public void show(){
System.out.println(this.price);
}
public static void show(Book<? extends Number> b){//接收資料類型為Number類別或Number子類別的Book物件。
System.out.println(b.price);
}}
public class Generics {
public static void main(String[]arg ){
Book<Integer> book = new Book<>();
book.price=100;
Book.show(book);

Book<String> book2 = new Book();
book2.price="byebyeworld";
Book.show(book2);//這行會有錯,因為bookk2的泛型採用資料類型是String,不是Nubmer類別的子類別。所以不能傳遞參數。
book2.show();
}
}
三、泛型跟Collection搭配就可以限制元素的資料類型


import java.util.*;
public class CollectionGenerics {
static void showSum(Collection<? extends Integer> c){//宣告Collection,並限定只接收儲存Integer資料類型的物件。
int sum = 0;
for(Integer i: c)//因為c裡面都是Integer,所以取出的類型都是int
sum+=i;//UnautoBoxing後與sum相加
System.out.println(sum);
}
public static void main(String[] args) {
// Collection<Long> c = new ArrayList<Long>();
Collection<Integer> c = new ArrayList<Integer>();//宣告collection c為存放Integer資料類型的ArrayList。c只能存放Integer的資料類型的物件。
c.add(1);
c.add(2);
c.add(3);
   // c.add("ddd");因為我們宣告c為Integer資料類型的arraylist,這行會加入字串會編譯錯誤,因為c只能放Interger的物件
showSum(c);//如果c宣告為Long的ArrayList,這行就會編譯錯誤
}}




2013年3月12日 星期二

Collection's'類別

位於java.util.Collections類別庫之下
提供與collection相關的static方法
ex:排序 搜尋

二分搜尋法
public static int binarySearch(List list,Object key)
使用二分搜尋法以前必須將list排序
list:List集合
key:搜尋標的物

public static void reverse(List list)
反轉List內的物件順序

public static void sort(List list)
讓list內的物件由大到小排序
若要執行排序,collection裡面的物件類型必須一致
否則會因為試圖轉型產生ClassCastException


public static void shuffle(List list)
隨機洗牌

容器物件:Collection



Collection:是一個容器物件,功能和陣列很相似。容器物件裡面可以放多個物件。也有一說collection是動態陣列,透過物件儲存物件。
clllection裡面放的東西都是物件,如果存放基本型別會先autoboxing成對應的物件,放入的物件還會自動轉型成Object類型。
Collection在java中是介面,由List、Set兩個容器物件(也是介面)所繼承。

一、Set:set裡面物件唯一不重複,存放次序由系統自己給定。set也是介面,透過底下的HashSet來實作。

import java.util.*;
//使用collection,必須import java.util.*;
class Human {

    int age = 1;
    int height = 111;

    public void speak() {
        System.out.println("hahaha");

    }
}

public class set {

    public static void main(String[] args) {
        Set set1 = new HashSet();//透過HashSet來實作Set介面
        set1.add("conan");//將""conan物件加入set裡面
        set1.add("Blue");
        set1.add(new Integer(44));//必須將基本型態boxing為物件
        set1.add(new Integer(44));
        set1.add(new Integer(99));
        set1.add(new Double(3.14));
        set1.add(new Human());
        System.out.println("set1=" + set1);
 

Iterator it = set1.iterator();//利用Iterator一一列印物件
while(it.hasNext()){
Object o = it.next();
System.out.print(o+" ");

 }
}

執行結果:可以看到物件排列順序與存放先後時間不一樣,而且物件不重複
set1=[3.14, Blue, 99, conan, collections.Human@78f77c8e, 44]


二、List
List裡面存放的物件可以重複,物件存放順序由add()先後時間來排列。List也是介面,繼承自Collection。List透過底下的ArrayList與LinkedList實作。

1.ArrayList:以陣列實作list。要實作陣列裡面的物件插入與刪除,效能不是那麼好
.remove("物件")//清除特定物件
.clear()//清空list

 List list1 = new ArrayList();//實作List介面
        list1.add("DarkMagician");
        list1.add("Blue eyses");
        list1.add("DarkMagician");
        list1.add(new Integer(33));
        list1.add(new Double(44.4));
        list1.add(new Integer(33));
        System.out.println(list1);


list1.remove("DarkMagicin"); //將物件從Arraylist移除
       for(int i=0;i<list1.size();i++){
        System.out.println(list1.get(i));//list1.get(i)根據序號,列印物件
     
        }
/*或者
        for(Object obj1:list1){//列印單筆物件的foreach寫法
        System.out.println(obj1);
        }


*/



執行結果:  可以看到存放順序以add()時間先後排列

[DarkMagician, Blue eyses, DarkMagician, 33, 44.4, 33]
Blue eyses,DarkMagician,33,44.4,33,DarkMagician

2013年3月11日 星期一

java網路


import java.net.InetAddress;
import java.net.UnknownHostException;
//必須import

 try {
       InetAddress ip = InetAddress.getByName("8.8.8.8");//取的IP,這裡不用new因為記憶體已經有。這行必須用try-catch包住。有可能因為不適當的IP造成例外
        System.out.println(ip.getHostName());//印出google-public-dns-a.google.com
         } catch (UnknownHostException ex) {
         

2013年3月7日 星期四

巢狀類別Nested Class

巢狀類別:一個類別之內再定義一個類別。
優點:可以存取外部類別的private成員



static 內部類別:
類別裡面再宣告一個static類別。依附於"外部類別"上
特性:只能存取外部類別的static成員,不能存取實體成員。
因為實體成員是物件層級的,static是類別層級的。

內部類別是外部類別的成員。

package nestedclass;
class outer{
static int x = 1;//static 變數
int y=2;
private static int k =4;
public static class inner{
private int z = 3;
public void show(){
System.out.println("outer.x="+outer.x);//存取static變數
//System.out.println("Outer.thix.y="+outer.this.y);//無法存取y
System.out.println(outer.k);//存取private static變數
System.out.println(z);
}}

}
public class staticNestedclass {
    public static void main(String[] args) {
outer.inner inner = new outer.inner();//inner依附於外部"類別",所以以外部類別.內部類別()建立物件
inner.show();
    }}




實體內部類別
類別內部再宣告non-static類別。依附在物件實體上。
內部類別是外部類別的成員。


package nestedclass;
class outer{
   private static int x = 1;
 static int y=2;
 int k= 3;
public class inner{
private int z = 3;
public void show(){
System.out.println("outer.x="+outer.x);//存取private成員,也可在x前面加上this
System.out.println("Outer.thix.y="+outer.this.y);//static成員也可用this去存,this表示outer的物件
System.out.println(this.z);//這裡this表示inner物件
System.out.println(outer.this.k);
}}}
public class staticNestedclass {
    public static void main(String[] args) {
outer.inner inner = new outer().new inner();//實體內部類別依附於物件實體上所以要先new outer()才實體化內部類別物件。
inner.show();    }}




方法內部類別
將類別宣告在外部類別的方法裡面,此時內部類別是方法裡面的類別,不是外部類別的成員。內部類別宣告規則跟方法內變數一樣,不可加static以及存取修飾詞。
方法內部類別可以存取外部類別成員,
但是方法裡面的區域變數必須冠上final修飾詞,才能被內部類別存取
(原因是加上final宣告時強制給予變數初始值)



package nestedclass;
class outerclass{
static int x =1;
int y =2;
private int k=3;
public void outermethod(final int a){
int b=5;

class inner{
 int z = 4;
public void show(){
System.out.println("x="+x);
System.out.println("y="+y);
System.out.println("k="+k);
System.out.println("z="+z);
System.out.println("a="+a);//存取外部類別的方法裡的區域變數
//System.out.println("b="+b);//

}
}
    inner inner = new inner();//物件宣告必須放在,類別宣告之後
    inner.show();  
}}

public class methodinnerclass {
    public static void main(String[] args) {
        outerclass outer = new outerclass();
        outer.outermethod(100);      
    }
}




匿名內部類別
該內部類別只有宣告類別名稱、實作內容但沒有"物件"名稱。
用於實作介面或改寫類別上
可以參考interface文章

EX:

public class anonymous_inner_class {
   public static void main(String[] args) {

//小括號包住,只有new 物件沒有給名字,主要用來補足內部類別Caaa沒有定義到的method

        (
                new Caaa(){
                void set_num(int n){
                num=n;
                System.out.println(num);
                
                }
                
                }).set_num(5);//執行匿名內部類別定義的method
                               
    }  
       
static class Caaa{

        int num;        }
           
}





匿名內部類別常用於撰寫事件(event)。

2013年3月6日 星期三

執行緒

定義:程式碼同時進行數個處理流程。

啟動執行緒:增加程式中的處理流程。

優點:讓程式更有效率進行處理,例如進行要花費N鐘頭的迴圈處理時,可以別的執行緒進行其他處理。

注意:Thread一旦run結束或中斷,就再也無法呼叫start()重新啟動thread



1.執行緒實作方法有三種:
第一、extends Thread建立Thread的子類別obj1


Thread子類別建立物件後,呼叫start()(obj1.start())由Thread繼承而來)啟動執行緒,之後跑run()裡面的程式。如此一來可以分別建立物件,每個物件可以有自己執行緒。




第二、宣告類別obj並且implement Runnable,宣告執行緒類別,以obj為引數建立執行緒物件。

class CTest implements Runnable{
public run(){.....}}

public static main(String args[]){

CTest obj = new CTest();
CTest obj2 =new CTest();

Thread t1 = new Thread(obj);//產生執行緒物件
Thread t2 =new Thread(obj2);
t1.start();
t2.start();

}

第三、使用匿名內部類別




以上必須override run() method。
run()裡面的東西就是新處理流程的起點。

可以利用sleep(1000)暫時停止執行緒,這是暫停一秒。




class multi_thread implements Runnable{//實作thread第一步,implements Runnable

    @Override
    public void run() {//第二步改寫run(),
      for(int i=1;i<=10;i++){
      System.out.print("i="+i);//執行緒在這裡可能被插隊
     System.out.println("name="+Thread.currentThread().getName());

            try {
                Thread.sleep(1500);//可以用Thread.sleep();讓執行緒進入blocked狀態(休息)
1500表示1.5秒,.sleep必須寫例外處理否則不給編譯過。
            } catch (InterruptedException ex) {            
            }            }  
}}

public class runnable {
  public static void main(String[] args)  {
     
            multi_thread obj = new multi_thread();
            Thread thread1 = new Thread(obj,"Taiwan");//建立執行緒,thread1去跑obj的程式,並且將thread1的名稱命名為Taiwan
            Thread thread2 = new Thread(obj,"Formosa");
         
            thread1.setPriority(Thread.MIN_PRIORITY);//thread權限,括號裡面是int型態
            thread2.setPriority(Thread.MAX_PRIORITY);
           
            thread1.start();//啟動thread
            thread2.start();
         
        try{  
            thread1.join();//.join()必須跟try-catch或throws InterruptedException配合
//thread1執行緒結束才會繼續執行try-catch之外的程式
            thread2.join();//thread2執行緒執行完之後才會執行下面的程式
        }catch(InterruptedException ex){}
        System.out.println("finished");
          }  
}



同步synchronized
執行緒存取變數或物件時將資料lock住,禁止其他執行緒進行存取。

使用時機:多個執行緒在同一時間存取同一個變數或物件


避免資料不一致、插隊情形,避免互相等待造成死結。

常常與notify() wait()配合
notify():通知waiting狀態的執行緒,如果有多個thread則隨意喚醒其中一個

wait():執行去進入waiting狀態,必須等待其他執行緒呼叫notify()才能將它喚醒


以下是沒有synchronized的程式碼以及執行結果
某家公司有兩個司機,位公司開車賺錢,宣告company類別管理這兩名司機賺來的錢,兩名司機賺的錢交回公司。

class Company{
    private int sum = 0;

    public void add(int a){//若要正確結果,在這邊加上synchronized修飾
    int tmp = sum;
    System.out.println("目前合計金額"+tmp+"dollars");
    System.out.println("賺到"+a);
    tmp=tmp+a;
    System.out.println("合計金額是"+tmp+"dollars");
    sum=tmp;
    }
}
class Driver implements Runnable{
    private Company comp;
    public Driver(Company c){
            comp=c;
    }
    @Override
    public void run(){
    for(int i=0;i<3;i++)
    {
     System.out.println(Thread.currentThread().getName());//列印執行緒名字
        comp.add(50);
    }
}       
}

public class synchron2 {
    public static void main(String[] args) {
        Company cmp = new Company();
        Driver drv1= new Driver(cmp);
        Thread thread1 = new Thread(drv1);
        thread1.start();
       
       
        Driver drv2=new Driver(cmp);
        Thread thread2 = new Thread(drv2);
        thread2.start();
    }
}


執行結果:

Thread-0
目前合計金額 0dollars
賺到50
合計金額是50dollars
Thread-1
Thread-0
目前合計金額 50dollars  //Thread1與Thread0幾乎同時讀取資料  
目前合計金額 50dollars //這裡可以看到Thread1讀取到Thread0改過後的資料
賺到50
賺到50
合計金額是100dollars
Thread-0
目前合計金額100dollars
合計金額是100dollars
Thread-1
賺到50
目前合計金額100dollars
賺到50
合計金額是150dollars
合計金額是150dollars
Thread-1
目前合計金額150dollars
賺到50
合計金額是200dollars             //正確金額應該是300元

2013年3月4日 星期一

資料串流、資料讀寫

what:
輸入:將檔案內容由磁碟機讀入後暫存到記憶體內
輸出:將記憶體內暫存資料寫入到檔案中或者將訊息顯示在螢幕上

在java裡面,資料的輸出與輸入皆以串流(stream)的概念進行。串流的資料是由chracters與bit組成。

在處理IO時候要說清楚資料的來源(source)與目的地(sink)

注意stream型態
分成byte stream以及 character stream

byte stream以1byte為單位(位元為主)傳輸資料,長相InputStream/OutputStream;
除了可用於文字檔輸出入之外
也可用於非文字檔(二進位檔案binary file)、圖形檔的輸入輸出

character stream以字元為單位傳輸資料,長相reader/writer
用於文字檔的輸出輸入,避免產生亂碼。


which:

以下IO類別皆放在java.io類別庫之下。
架構如下:

java.io套件:
一、File //管理目錄底下的檔案與目錄。
二、InputStream//以byte為單位輸入
       1.FileInputStream//讀取檔案可讀文字檔也可讀圖檔
       2.ObjectInputStream
三、OutputStream//以byte為單位輸出
       1.FileOutputStream//輸出成檔案
       2.ObjectOutputStream
四、Reader//以字元為單位輸入
       1.InputStreamReader
           a.FileReader
       2.BufferedReader
五、Writer//以字元為單位輸出
       1.OutputStreamWriter
           a.FileWriter
       2.BufferedWriter



一、File



查詢檔名、size、修改日期。
不可存取檔案內容。資料夾也是一種檔案。
File file1 = new File("路徑");
File file2 = new File(File 變數或String 路徑,String 檔案名稱);
list():列出資料夾內的檔名
delete():刪除檔案,如果資料夾內有檔案,必須先刪除

 

 

二、InputStream/OutputStream

1.FileInputStream/FileOutputStream
FileInputStream fis = new FileInputStream("路徑+檔名");
fis.read():以1byte為單位讀取的檔案內容,回傳整數值。
如果沒有讀到任何字元則會回傳-1。

FileOutputStream fos = new FileOutputStream("路徑檔名");
fos.write(int變數或byte陣列);//將檔案內容寫入fos
fos.close();//關閉檔案,如果不關閉會留在記憶體之中

tip:
1.
輸出到文字檔案以附加方式輸出
FileOutputStream fos = new FileOutputStream("路徑檔名",true);
不過用這樣方式輸出圖檔無法以附加方式輸出

2.
int available();//傳回所讀的檔案bytes大小。
這個method是FileInputStream僅有的
可以寫出檔案時事先知道檔案的大小。


  FileInputStream fi=new FileInputStream("D:/java/train.txt");//讀取檔案來源
        System.out.println("file size"+fi.available());//取得檔案大小
        byte ba[]=new byte[fi.available()];//宣告符合檔案大小的byte陣列
    fi.read(ba);//將檔案內容讀到ba
    System.out.println(new String(ba));//轉成字串,列印
    fi.close();


BufferedInputStream/BufferedOutputStream

在記憶體設立緩衝區,批次處理檔案的輸出與輸入,如此一來減少硬碟的讀取次數。
用法:BufferedInputStream bis = new BufferedInputStream(InputStream類別變數或者new InpuStream("路徑檔名"));




FileReader/FileWriter

用法與FileInputStream一樣
英文的文字檔傳輸沒有問題,ANSI檔案的中文字會發生亂碼,UTF8才可以正常輸出,傳輸圖檔會開不起來。


char data[] = new char[128];
    FileReader fr = new
            FileReader("D:\\java\\train.txt");
     int num=fr.read(data);   //將檔案傳入自原陣列,回傳讀的字元數目。
        //ANSI的中文字視為兩個字元(我這個字是為一個字元,UTF8檔案中文視為一個字元)
     System.out.println(num);//列印檔案讀去的字元數
     System.out.println("-------------------------");
     System.out.println(data);//列印陣列的內容
     
String str = new String(data,0,num);
//String(char[],起始點,轉換長度);

System.out.println(str);
//轉換字串後列印結果跟轉換前是一樣的
 
}
}



BufferedReader/BufferedWriter

用法跟BufferedInputStream一樣

BufferedReader除了read()方法之外也可以用
readLine()從檔案抓取文字,一次抓取一行,readLine回傳字串值。

將檔案輸出到新的文字檔並不會自動換行
要用BufferedWriter的方法newLine()才會換行


PrintWriter

官方文件說這是格式化輸出。目前不知道何謂格式化輸出?
句法跟BufferedWrtier一樣,照樣造句
PrintWriter bw1=new PrintWriter(new FileWriter(路徑));
用bw1.println(String變數)
輸出文字到檔案,會自動換行


DataInputStream/DataOutputStream



ObjectInputStream/ObjectOutputStream

以物件型式讀入、讀出資料。

原本資料是物件(ex:在程式碼裡面宣告類別建立物件),以文字型式將資料寫入檔案內,之後取出來便無法以物件方式取出。所以無法直接取得類別的屬性值。

要使用ObjectOutputStream類別將物件寫入檔案,該物件必須是可序列化(serializable)物件。該物件以及該物件內所屬的類別必須實作Serializable介面。否則會產生NotSerializableException事件。
ObjectInputStream則是用反序列化將物件從檔案讀取。
序列化:將物件內所有的屬性以及相關資料依照一定的順序轉成byte型式後寫入檔案。

如果有屬性不想被序列化那麼要在屬性前面加上transient或者static修飾詞。


(將資料輸出檔案用文字編輯器開啟是亂碼,看起來前面部分是描述物件的schema,後面部分是描述個物件的屬性值)

應用:檔案存取、網路資料傳送、影像檔案傳送


範例:
class book implements Serializable{//即將被序列化所以要實作Serializable
String name;//這個name也是物件,類別庫裡面已經實作介面所以我們不用再對他實作
double price;//同上
String author;//同上
public book(String name,double price,String author){
this.name=name;
this.price=price;
this.author=author;
}
public void show(){
System.out.println("書名"+name);
System.out.println("定價"+price);
System.out.println("作者"+author);
}}

File file = new File("D:/temp/kaiba.txt");//隨便準備一個檔案,作為輸出檔案
      book[] books = new book[2];//宣告類別陣列
      books[0]=new book("Conan",100.0,"formosa");
      books[1]=new book("Doraemon",99.9,"FFFF");
   
      FileOutputStream fos = new FileOutputStream(file);//將檔案(file)與OutputStream串接
      ObjectOutputStream oos = new ObjectOutputStream(fos);//串接
      for(Object book:books)//foreach
    oos.writeObject(book);//將物件寫入outputstream,而且被轉換成Object類型
 
      oos.close();
      fos.close();
      //-------------------以下讀取檔案--------------------//
      FileInputStream fis= new FileInputStream(file);//將剛剛的檔案與inputStream串接
      ObjectInputStream ois = new ObjectInputStream(fis);//串接
      System.out.println(file.getName()+"檔案內容如下");
      System.out.println("-----------------");
      try{
    while(true){ 
      ((book)ois.readObject()).show();
//讀取物件並轉換成book(因為讀出的是object物件),並呼叫show method
    }
      }catch(Exception e){
//處理例外,讀到沒有物件時會拋出例外,所以用try catch
      }
      ois.close();
      fis.close();
}

InputStreamReader/OutputStreamWirter

InputStreamReader是byte轉成字元的橋樑。讀取byte轉成字元。
OutputStreamWriter是字元轉成byte的橋樑
轉成什樣字元端看平台的字元預設值。用netbean執行打中文出現亂碼。
因為平台字元預設為utf8處理字元,
我們可以用System.out.println(OSWout.getEncoding());
得知目前用什麼編碼處理字串。
如果處理中文字的話,要加上"big5"指定編碼
InputStreamReader ISRkeyin = new InputStreamReader(InputStream,"big5");
OutputStreamWriter OSWout = new OutputStreamWriter(OutputStream,"big5");
以上兩個缺一不可。


how:
基本操作SOP如下:

1. 指定資料源頭(source)
InputStream keyin = System.in;//源頭來自於使用者鍵盤輸入
InputStreamReader ISRkeyin = new InputStreamReader(keyin,"big5");//byte轉字元。因為System.in是InputStream以byte為單位處理。要丟入以字元為單位處了的buffer所以要轉換。
BufferedReader input = new BufferedReader(ISRkeyin);//字元

2.指定輸出目的地sink
FileOutputStream file = new FileOutputStream("D:/temp/ooxx.txt");//byte完單位
OutputStreamWriter OSWout = new OutputStreamWriter(file,"big5");//字元轉byte
BufferedWriter output = new BufferedWriter(OSWout);

3.
//System.out.println(ISRkeyin.getEncoding());
//System.out.println(OSWout.getEncoding());
String str;
while(( str=input.readLine())!=null) //程式執行到這裡會讓使用者輸入文字,我在這邊又在while這行多打上了分號,結果沒執行下方的程式。
{
if(str.equalsIgnoreCase("Q"))//忽略大小寫,檢查輸入字串
{
input.close();
output.close();
System.exit(-1);//告訴系統結束執行程式。否則仍會繼續執行while,然後拋出例外,也可以打上return ; 也有同樣效果
}

output.write(str);
//OSWout.write(str);//不用buffer也可以將文字輸出到檔案
output.newLine();
System.out.println("你剛才打的文字是:"+str);
}
4.關閉stream
input.close();
output.close();

    }



PS:若省略BufferedReader、BufferedWriter就無法直接讀取輸入String型態的串流\
BufferedReader沒有readLine()

2013年3月3日 星期日

例外處理

what:程式在"執行階段時"發生的錯誤,之後中斷執行程式。發生這種例外時又稱為拋出例外。例外發生時JVM會自動建立例外物件,將錯誤訊息存在物件內,如果沒有使用例外處理機制,會將物件內儲存的錯誤訊息輸出



which :
1.例外是java類別庫中java.lang底下的Throwable類別之子類別的物件
2.自訂例外


when:
編譯程式碼時不會找到的bug,執行程式時才會出現

1.執行處理檔案的程式,但找不到指定的檔案(NullPointException)
2.執行將使用者輸入的文字轉換成整數的程式,
但使用者輸入整數之外的值(NumberFormatException)

3.存取陣列時,陣列的索引超過陣列範圍
(ArrayIndexOutOfBoundException)

why:
防止例外發生時程式中途結束,繼續執行完程式。


how:
利用try...catch...finally處理,當例外發生時程式會執行catch區塊的程式。


try{
..........指定檢查是否發生例外部分.......
} catch(例外的類別 變數名稱){
......例外發生時,
例外的類別變數檢查例外發生事件是否符合宣告的類別。
之後執行這裡的程式。
}finally{
.......這裡可以省略不寫,不管有沒有例外發生一定會執行這邊......
如果有不管有無發生例外都要執行的程式時,就一定要寫在這邊
否則例外發生時會讓程式中斷
}



自訂例外類別:
1.宣告自訂例外類別,必須繼承Exception。
2.在想拋出例外的方法(method)名稱後面加上"throws 自訂的例外類別"。
3.在例外可能發生之處,利用"throw 代表物件的變數;"來拋出例外(踢皮球),丟給外呼叫此方法的方法。
throw new MyException();
(如果method 後面沒加上throws 例外類別的話,method內不可以加上 throw new MyException();)
4.在外一層方法(method)裡寫try....catch(MyException e),將例外處理掉

System.out.println(e);會列印例外外名稱以及發生所在行數

class MyException extends Exception{
}



處理不了例外,就會將例外丟改該方法的呼叫者處理,如果丟到main(),仍沒處理掉那麼就會中斷程式執行








Exception分成
RuntimeException、非RuntimeException(checked exception)

RuntimeException有自動拋出(throws)例外功能,如果method內產生RuntimeException例外物件
即使不使用throws拋出也會自動拋出,不必自己寫throws也不用try catch也可以編譯成功
但是不加上try catch執行階段如果產生RuntimeException就會輸出預設發生例外訊息


CheckedException:除了RuntimeException都是此類。
IOException(FileNotFoundException) InterruptedException
這類的例外沒有自動throws的功能,
如果產生例外事件
那麼要自己撰寫throws將其拋出或使用try catch否則會編譯失敗
像是Thread.sleep();  或者FileOutputStream這些東西

介面interface

介面:
長相與抽象類別相似

宣告方式跟宣告類別很像,有屬性與方法,但是沒有建構式。
無法建立物件。
只是介面宣告以interface
interface Univers{
public static final int age = 120;
abstract void show();
}

//以下是錯誤寫法,interface宣告為public那麼表示檔名要跟interface名稱一樣
//不可加上static,static是修飾method與基本型態變數
//不可加上final,介面是要給類別實作的。
public static final interface career{
int age =20;
abstract void show();

}



特性:
1.有成員變數與方法但是沒有建構式,成員變數必須初始化;方法一律為abstract
2.成員前面一般不加修飾子
3.介面的成員變數預設加上public static final;方法則是加上abstract即抽象方法,介面只有抽象方法,而且只能宣告為public。(抽象類別的method可以宣告public protected default,不可宣告為private)
由此可知介面無法變更成員變數的值,成員變數一定要是定值。無法在介面定義方法的內容。

4.介面無法建立物件
可以宣告介面型態的變數,存取實作介面類別的物件

(抽象類別可以有建構式)



實作(implement):
介面和類別一起使用,稱為實作。類似extends。
class detective implements career{

}
上面程式碼以detective實作carrer介面,如此一來detective類別就繼承carrer介面所擁有的成員變數與方法。


如果要建立detective類別的物件,必須在detective類別中,定義介面中所有的方法,換句話說,就是在detictive類別裡面將career裡面所有的方法,改寫一遍。而成員變數可以在實作類別裡面另行宣告,或者沿用介面的。但是不可更改介面的成員變數的值。



介面解決了java的類別無法多重繼承的問題,
一個類別不可有兩個父類別,如同一個兒子不能有兩個爸爸
但是可以有多個義父、師父。
介面讓類別實現了多重繼承。


以下以神鵰俠侶主角楊過為例子:

interface 歐陽鋒{void 蛤蟆功();}
interface 洪七公{void 打狗棒法();}
interface 郭靖{void 九陰真經();}

class 楊過 implements 洪七公,歐陽鋒,郭靖{

void 打狗棒法(){
.............
}
void 蛤蟆功(){
............
}
void 九陰真經(){......}

}

類別楊過,實作洪七公 歐陽鋒 郭靖三個介面
因此必須改寫override打狗棒法、蛤蟆功、九陰真經。


介面之間可以是繼承的關係。
例如表示成這樣:
interface 郭靖 extends 江南七怪,丘處機
{
.......
}



雖然介面機制類似抽象類別。
介面贏過抽象類別的地方是,抽象類別不可多重繼承。
抽象類別終究還是類別。




也可以用匿名內部類別實作介面的方法

interface Book{
void show();
}

class AnonymouClass{
public static void main(String[] args){
Book book =new Book(){
//----匿名內部類別的內容---
public void show(){System.out.println("ByeBye World");}
};
book.show();
}}


看起來很像new一個Book的物件


我們可以book.getClass().toString得知
book是class interfaceimplement.anonymousclass$1
book是實作匿名類別