2008年4月24日 星期四

time complexity for sorting algorithms

時間複雜度             最差        平均
選擇排序              O(n2)       O(n2)
氣泡排序              O(n2)       O(n2)
插入排序              O(n2)       O(n2)
快速排序              O(n2)       O(n*log(n))
樹形排序              O(n2)       O(n*log(n))
合併排序              O(n*log(n))  O(n*log(n))
堆積排序              O(n*log(n))  O(n*log(n))
謝耳排序              O(n1.5)     O(n1.25)
數元排序(限整數)      O(n)         O(n)

參考:
1.carrano-pie-05-data abstraction & problem solving with java
2.weiss-pie-04-data structures & problem solving using java
3.budd-awl-00-classic data structures in java

weka.classifiers.rules


weka.classifiers.rules
ConjunctiveRule, 連言規則
適用於類別/數值預測
利用單條連言(and)規則作預測
若規則未涵蓋新案例,傳回過去案例之類別分佈或平均值
規則前件成長法:依條件加入前後之資訊增量為指標,留大者
分類之資訊量為規則涵蓋及未涵蓋案例資訊量之加權平均值
迴歸之資訊量為規則涵蓋及未涵蓋案例均方差之加權平均值
規則前件修剪法:
若長前修剪策略,限定其前件許可之條件數;
若長後修剪策略,使用縮減錯誤修剪法
分類之指標為修剪集中,涵蓋與否案例正確率之加權平均值,變大則修剪
迴歸之指標為修剪集中,涵蓋與否案例均方差之加權平均值,變小則修剪
參數:
exclusive: [false] 名目屬性分叉時考慮排他測試條件,例如,某屬性不為某屬性值
folds: [3] 訓練集分割組數,其中1組保留作縮減錯誤修剪,其餘供長規則用
minNo: [2.0] 規則最少案例權重數
numAntds: [-1] 若>=0,表採用長前修剪策略,其許可前件之條件數;
若-1,表採用長後修剪策略,使用縮減錯誤修剪法

DecisionTable, 決策表
適用於類別/數值預測
利用最佳優先搜尋法,以交叉驗證錯誤率為指標,找出最佳屬性子集合
預測時遇決策表未涵蓋新案例,使用k最近鄰居法,或多數決法
參數:
crossVal: [1] 交叉驗證切割組數,1表只保留一測試案例,餘供訓練
maxStale: [5] 放棄搜尋前,能忍受指標無進步之試走步數
useIBk: [false] 遇未涵蓋新案例,使用k最近鄰居法,否則使用多數決法
kohavi-ecml-95-the power of decision tables

JRip,
適用於類別預測
實作ripper分裂演算法,具啟發式規則集全域優化功能
依案例由少到多類別順序,逐一產生各類別規則集,如下
1.類別C規則集建造階段
1.1.以2:1比例分割案例集為新成長集及修剪集
1.2.重複以下前件成長,修剪動作,直到以下任一條件滿足
a.類別C案例無前件未涵蓋案例剩下
b.規則集及未涵蓋案例之描述長度
比目前為止最小描述長度,還長超過64位元
c.錯誤率超過0.5
1.2.1.前件成長期
依資訊增量指標,貪婪(局部最佳)添一前件條件,直到正確率100%
條件測試形式為"若某屬性為某屬性值"
資訊增量=p(log(p/(p+n))-log(P/(P+N)))
1.2.2.前件修剪期
由後往前逐一試修剪規則前件最後一個條件
只要修剪後規則價值有提昇,就繼續修剪
規則價值=(p+1)/(p+n+2)
2.類別C規則集優化階段
2.1.逐一檢視各規則R
2.1.1.重新2:1分割案例集為新成長集及修剪集
2.1.2.剔除修剪集已由其他規則涵蓋(前件符合)之案例
2.1.3.利用成長集案例
貪婪添一前件條件,長出新規則R1
從無到有產生一條新規則R2
2.1.4.利用修剪集案例,修剪R1,R2
但規則價值=(p+N-n)/(P+N)
2.1.5.就R,R1,R2三者,挑選描述長度最短者留下,餘刪除
2.2.優化後若還有未涵蓋案例,回到1.
2.3.逐一檢視各規則,若加入會增加規則集描述長度,則刪除之
自案例集移除由規則集涵蓋之案例
註:p,n為規則涵蓋之正反案例數;P,N為類別C之正反案例數
參數:
checkErrorRate: [true] 利用錯誤率>=0.5作為終止條件
folds: [3] 訓練集分割組數,其中1組保留作縮減錯誤修剪,其餘供長規則用
minNo: [2.0] 每條規則最少案例數
optimizations: [2] 規則集全域優化次數
usePruning: [true] 縮減錯誤修剪
cohen-icml-95-fast effective rule induction

M5Rules
適用於數值預測
利用M5P線性模型樹,產生決策清單
參數:
buildRegressionTree: [false] 建迴歸樹,否則只有樹根長葉節點模型
minNumInstances: [4.0] 各葉節點最少案例數
unpruned: [false] 不修剪
useUnsmoothed: [false] 預測數值時不平滑化處理
hall-ajcai-99-generating rule sets from model trees

Nnge, Nearest Neighbor GEneralization 最佳鄰居一般化
適用於類別預測
仿最近鄰居演算法,利用不相互包含之一般化範例(超矩形規則)作預測
參數:
numAttemptsOfGeneOption: [5] 一般化嚐試次數
numFoldersMIOption: [5] 計算相似資訊量之組數
roy-ucnz-02-nearest neighbor with generalization
martin-uwnz-95-instance-based learning- nearest neighbor with generalization

OneR, One Rule 單規則
適用於類別預測
只測試單屬性及值,挑選錯誤最小者,形成單規則
遇數值屬性會自動分割區間離散化,每區間多數類別案例至少minBucketSize個
holte--93-very simple classification rules perform well on most commonly used datasets". Machine Learning, Vol. 11, pp. 63-91.

Part, 零件
適用於類別預測
利用移開再征服(separate and conquer)策略,產生決策清單
每回利用c4.5產生部份決策樹,挑最好葉節點轉成規則
參數:
binarySplits: [false] 名目屬性作二元分叉
confidenceFactor: [0.25] 估錯誤率上限之信心水準,愈小修剪愈多
minNumObj: [2] 規則最少案例數
numFolds: [3] 訓練集分割組數,其中1組保留作縮減錯誤修剪,其餘供長樹用
reducedErrorPruning: [false] 縮減誤差修剪法,否則沿用c4.5修剪法
unpruned: [true] 樹不修剪
frank-icml-98-generating accurate rule sets without global optimization

Prism, 稜鏡
適用於類別預測,名目屬性,無缺值
不修剪
cendrowska-ijmms-87-prism- an algorithm for inducing modular rules

Ridor, RIpple DOwn Rule 漣漪下移規則
適用於類別預測
能產生含例外之規則集
先產生預設規則,再利用累進縮減錯誤修剪,產生錯誤率最低之最佳例外規則集.
再就每一例外規則產生最佳例外規則集,迭代直到案例變純剩單類別無例外為止.
參數:
folds: [3] 訓練集分割組數,其中1組保留作縮減錯誤修剪,其餘供長樹用
majorityClass: [false] 多數類別為預設值
minNo: [2.0] 規則最案例權重數
shuffle: [1] 每條規則產生前所需案例洗牌次數,若>1,將留下其中最準確者
wholeDataErr: [false] 依全部案例計算規則價值,否則依前件涵蓋案例計算

ZeroR, Zero Rule 零規則
適用於類別/數值預測
以案例集之眾數類別/平均值,預測類別/數值.

weka.classifiers.trees


weka.classifiers.trees
ADTree, Alternating Decision Tree 交替決策樹
適用於雙類別預測
以推進法,累進新增節點長出選項樹,具分叉及預測兩類節點
典型推進法如LogitBoost套在底層ConjunctiveRule學習器上
預設推進次數為10,每次推進若無合併,可新增一分叉節點及二預測節點
推進次數愈多,模型愈複雜,但效果不一定好,要手調適當參數
擴張路徑方法
Expand all paths (預設,所有路徑都長,最慢)
Expand the heaviest path
Expand the best z-pure path
Expand a random path
freund-icml-99-the alternating decision tree learning algorithm

DecisionStump, 決策樹根
適用於類別/數值預測,接受缺值(長第3分叉),常作為推進法之底層學習器
建立單節點雙分叉決策樹,只允許依某屬性為某值與否作二元分叉
遇缺值可再加一未知值分叉

Id3,
適用於類別預測,名目屬性,無缺值
節點分裂屬性挑法:利用資訊增益比為指標,留大者
資訊增益比=分裂前後資訊增量/分裂資訊量
無樹修剪,空案例葉節點會造成無法分類情形
quinlan-ml-86-induction of decision trees

J48, 即c4.5
適用於類別預測
節點分裂屬性挑法:利用資訊增益比為指標,留大者
遇數值屬性,限定用二元分叉,分叉點選擇利用資訊增量為指標
遇缺值,採用案例分解碎片再匯總作法
修剪策略:長後修剪,從葉至根測試子樹替換或子樹提昇之錯誤率是否下降
計算錯誤率方法,可採用縮減誤差修剪法,利用保留之修剪案例為之
參數:
binarySplits: [false] 名目屬性作二元分叉
confidenceFactor: [0.25] 估錯誤率上限之信心水準,愈小修剪愈多
minNumObj: [2] 葉節點最少案例數
numFolds: [3] 訓練集分割組數,其中1組保留作縮減錯誤修剪,其餘供長樹用
reducedErrorPruning: [false] 縮減誤差修剪
subtreeRaising: [false] 子樹提昇修剪,較費時
unpruned: [true] 樹不修剪
useLaplace: [false] 輸出葉節點之類別分佈機率時是否平滑化
quinlan-mkp-93-c4.5: programs for machine learning

LMT, Logistic Model Tree 邏輯模型樹
適用於雙/多類別預測
決策樹葉節點為各類別之線性邏輯模型
節點分裂屬性挑法:利用推進法殘差(留小者)或資訊增量(留大者)為指標
利用LogitBoost推進法,套在底層簡單線性迴歸器,
每次推進,找出一個誤差最小之屬性疊加到線性邏輯模型上
推進結束時,即得一最大概似率之多元邏輯迴歸模型
參數:
convertNominal: [false] 名目屬性轉為多個二值屬性,採二元分叉
errorOnProbabilities: [false] 交叉驗證指標依機率均方根值,否則依誤判數
fastRegression: [true] 各節點推進次數統一由一次交叉驗證決定
minNumInstances: [15] 節點要最少多少案例才考慮分裂
numBoostingIterations: [-1] 固定推進次數,-1表依各節點交叉驗證決定
splitOnResiduals: [false] 節點分裂依殘差指標,否則依資訊增量指標
landwehr-ecml-03-logistic model trees

M5P, Model 5 Prime 多元線性模型樹
適用於數值預測
決策樹葉節點為多元線性模型
節點分裂屬性挑法:利用案例之標準差降低量sdr為指標,留大者
分裂屬性時永遠採二元分叉
遇數值屬性,依數值排序,測試每個分割點,計算sdr取大者
遇k值名目屬性,先轉為k-1個合成二值屬性,依各合成屬性平均值排序,
再測試每個分割點,計算sdr取大者
遇缺值,於訓練選分裂屬性時,依缺值案例佔目前案例之比例,縮小sdr值
於訓練分配案例時,先算無缺值而歸屬左右分叉之兩案例數值平均值
再依缺值案例之數值是否大於兩平均值之平均值,而歸屬適當一方
等訓練長樹結束時,所有缺值由其所處葉節點案例平均值取代
註:此法為找出最相關屬性作代理分裂(surrogate split)之簡化版
於測試分配案例時,缺值由同時到達該內部節點之訓練案例平均值取代
修剪策略:採長後修剪,從葉至根測試子樹替換回葉節點之錯誤率是否下降
葉節點之線性迴歸模型,其自變數則取自原子樹各內部節點屬性
葉節點錯誤率為將目前案例之實際減預測的殘差平均值,再作悲觀放大
放大比例為(n+v)/(n-v),n為訓練案例數,v為悲觀度調整值
內部節點(即子樹)錯誤率為其左右兩子樹錯誤率之案例數比重加總
預測數值時,利用樹根到葉節點路徑上之所有模型作平滑化處理
參數:
buildRegressionTree: [false] 建迴歸樹,否則只有樹根長葉節點模型
minNumInstances: [4.0] 各葉節點最少案例數
unpruned: [false] 不修剪
useUnsmoothed: [false] 預測數值時不平滑化處理
wang-ecml-97-induction of model trees for predicting continuous classes
quinlan-ajcai-92-learning with continuous classes

NBTree, Naive Bayes Tree 簡單貝氏樹
適用於類別預測
混用決策樹及簡單貝氏兩學習器
決策樹葉節點為簡單貝氏分類器
利用交叉驗證判別節點要分裂成內部節點,或維持貝氏模型葉節點
kohavi-ickddm-96-scaling up the accuracy of naive-bayes classifiers- a decision tree hybrid

RandomForest, 亂數森林
適用於類別預測
利用重複取樣聚合法(bagging),建立給定顆亂數樹
參數:
numFeatures: [0] 分裂屬性自多少最佳屬性中亂數取一, 0表3
numTrees: [10] 打算長出幾顆樹
seed: [1] 挑分裂屬性之亂數種子
breiman-ml-01-random forests

RandomTree, 亂數樹
適用於類別預測
節點分裂屬性挑法:每回自給定個最佳屬性中亂數取一
不作節點修剪
參數:
KValue: [1] 分裂屬性自多少最佳屬性中亂數取一
minNum: [1.0] 葉節點最少案例權重數
seed: [1] 挑分裂屬性之亂數種子

REPTree, Reduced-Error Pruning Tree 縮減誤差修剪樹
適用於類別/數值預測
節點分裂屬性挑法:利用資訊增量/變異數,快速長出決策/迴歸樹,
修剪策略:長後修剪,利用縮減誤差修剪法
參數nFolds為訓練集分割組數,其中1組保留作縮減錯誤修剪,其餘供長樹用
數值屬性只排序一次,以加快學習速度
遇缺值同c4.5,採用案例分解碎片再匯總作法
可設定其他參數
minNum: 葉節點最小案例總權重,預設值2
minVarianceProp: 案例變異數需佔原始訓練集多少比例以上才作節點分裂
預設值:0.001,適用於預測對象為數值時
maxDepth: 長樹最大深度限制,預設值-1,代表無限制,適用於搭配推進法時

UserClassifier, 用戶分類器
適用於類別/數值預測
節點分裂屬性挑法:人工一次挑選任兩屬性之適當2維區間作節點分裂用

2008年4月23日 星期三

weka.classifiers.bayes


weka.classifiers.bayes 只適用於分類
AODE, Averaged, One-Dependence Estimator 平均單相依估算器
適用於屬性相依
建立一群允許單對屬性相依之候選貝氏模型,求其平均結果
webb-ml-05-not so naive bayes- aggregating one-dependence estimators

BayesNet,貝氏網路
適用於屬性相依,名目屬性(遇數值會先離散化),無缺值(遇缺值會補值)
估算貝氏網路條件機率表方法,weka.classifiers.bayes.net.estimate
BayesNetEstimator
BMAEstimator
MultiNominalBMAEstimator
SimpleEstimator
搜尋貝氏網路結構方法,weka.classifiers.bayes.net.search.local
GeneticSearch
HillClimber
K2 (預設選項,預設節點最大親節點數為1)
LocalScoreSearchAlgorithm
RepeatedHillClimber
SimulatedAnnealing
TabuSearch
TAN
註:搜尋指標為條件獨立性檢定值
可利用AD樹資料結構犧牲記憶體,以加快速度

ComplementNaiveBayes,互補簡單貝氏
適用於屬性獨立,屬性表示關鍵詞TFIDF值之文件分類
rennie-aaai-03-tackling the poor assumptions of naive bayes text classifiers

NaiveBayes,簡單貝氏
適用於屬性獨立,數值屬性不符合常態分配情形
數值屬性支援核心密度估算子推估機率及監督式離散化

NaiveBayesMultinomial,簡單貝氏多項版
適用於屬性獨立,屬性表示關鍵詞出現次數之文件分類

NaiveBayesSimple,簡單貝氏簡化版
適用於屬性獨立,數值屬性符合常態分配情形
數值屬性採用常態分配模型推估機率

NaiveBayesUpdateable,簡單貝氏累進版
適用於累進學習場合
數值屬性支援核心密度估算子,不支援離散化

2008年4月16日 星期三

jpanel.requestFocus on mouseEntered

Java Swing元件中,無法敲字進入JPanel畫板,理由主要在畫板尚未取得鍵盤焦點。 一個視窗收到鍵盤事件要送給誰,是由處於鍵盤焦點之元件來決定。 這樣的鍵盤焦點一個視窗一次只能存在一個接收元件。 故想要畫板隨著滑鼠移入即可接收鍵盤事件,作法為 設定畫板監聽mouseEntered事件,一旦發現滑鼠移入, 立即利用jpanel.requestFocus()方法,設定畫板自己為鍵盤焦點。 範例如下。

/*
  KeyPanel.java
  
    Demo for receiving key events in a jpanel
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class KeyPanel extends JFrame
{
  JPanel centerPanel; // 打算敲字之畫板
  JTextField txtField; // 顯示所敲字之文字盒

  public KeyPanel()
  {
    centerPanel = new JPanel();
    centerPanel.setBackground(Color.pink);
    centerPanel.addKeyListener(new KeyAdapter()
    {
      public void keyTyped(KeyEvent ke)
      {
        char k = ke.getKeyChar();

        txtField.setText("keyTyped=" + k); // 顯示接收鍵盤字元
      }
    });

    centerPanel.addMouseListener(new MouseAdapter()
    {
      public void mouseEntered(MouseEvent me)
      {
        centerPanel.requestFocus(); // 滑鼠移入時自動取得鍵盤焦點
      }
    });

    this.add(centerPanel, BorderLayout.CENTER);

    txtField = new JTextField();
    this.add(txtField, BorderLayout.NORTH);
  }

  public static void main(String args[]) // 主程式
  {
    KeyPanel df = new KeyPanel();
    df.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    df.setSize(600, 400);
    df.setVisible(true);
  }
}

2008年4月14日 星期一

inner.java, a sample code for 6 kinds of java classes inside classes/methods

/*

  Inner.java

    Demo for a variety of inner classes which include

1. static nested classes: 類別內具名靜態類別 InClassStaticClass
 no associated outer class instance.

2. inner nested classes: 類別內具名非靜態類別 InClassInstanceClass
 with an associated outer class instance.

3. anonymous classes: 方法內匿名類別 adapted from InMethodUnnamedClass
 unnamed inner class defined in the middle of a method.

4. local classes: 方法內具名類別 InMethodStaticClass, InMethodInstanceClass
 named inner class defined in the middle of a method.

實際展示6種內部類別(inner class)寫法:
 1.類別內具名靜態類別,InClassStaticClass
 2.類別內具名非靜態類別,InClassInstanceClass
 3.類別方法內具名靜態類別,InMethodStaticClass
 4.物件方法內具名非靜態類別,InMethodInstanceClass
 5.類別方法內匿名靜態類別,adapted from InMethodUnnamedClass
 6.物件方法內匿名非靜態類別,adapted from InMethodUnnamedClass

Note:
 1.StaticClass can directly instantiate without an instance.
   An inner InstanceClass can have static and instance members,
   but can only access outer class static members.
   Members include attributes and methods.
   Most classes are named StaticClass.
 2.InstanceClass must instantiate from an instance.
   An inner InstanceClass can only have instance members,
   but can access outer class static and instance members.
 3.Methods provide a non-static context and
   do not allow static declarations inside.
   All intra method inner classes can add
   new instance but not static members.
 4.Unnamed inner classes are adapted inline from known classes,
   and must be in a method, not in a class.
   They can add new instance but not static members and
   access old public but not private members of known classes.

Ref:
  http://www.blogjava.net/blackbat/archive/2006/10/04/73352.html

 執行方法及結果

> javac Inner.java
> java Inner
我是<外部類別OuterClass>物件,擁有
    類別屬性outerStaticAttribute
    物件屬性outerInstanceAttribute
    類別方法outerStaticMethod
    物件方法outerInstanceMethod

1.使用類別內具名靜態類別...
我是<類別內具名靜態類別InClassStaticClass>物件,擁有
    類別屬性innerStaticAttribute
    物件屬性innerInstanceAttribute
    類別方法innerStaticMethod
    物件方法innerInstanceMethod
 從類別方法innerStaticMethod,我可以:
  存取 外部類別之類別屬性outerStaticAttribute
  存取 內部類別之類別屬性innerStaticAttribute
  呼叫 外部類別之類別方法outerStaticMethod
 從物件方法innerInstanceMethod,我可以:
  存取 外部類別之類別屬性outerStaticAttribute
  存取 內部類別之類別屬性innerStaticAttribute
  存取 內部類別之物件屬性innerInstanceAttribute
  呼叫 外部類別之類別方法outerStaticMethod

2.使用類別內具名非靜態類別...
我是<類別內具名非靜態類別InClassInstanceClass>物件,擁有
    x類別屬性
    物件屬性innerInstanceAttribute
    x類別方法
    物件方法innerInstanceMethod
 從物件方法innerInstanceMethod,我可以:
  存取 外部類別之類別屬性outerStaticAttribute
  存取 外部類別之物件屬性outerInstanceAttribute
  存取 內部類別之物件屬性innerInstanceAttribute
  呼叫 外部類別之類別方法outerStaticMethod
  呼叫 外部類別之物件方法outerInstanceMethod

3.使用類別方法內具名靜態類別...
我是<方法內具名靜態類別InMethodStaticClass>物件,擁有
    x類別屬性
    物件屬性innerInstanceAttribute
    x類別方法
    物件方法innerInstanceMethod
 從物件方法innerInstanceMethod,我可以:
  存取 外部類別之類別屬性outerStaticAttribute
  存取 內部類別之物件屬性innerInstanceAttribute
  呼叫 外部類別之類別方法outerStaticMethod

4.使用物件方法內具名非靜態類別...
我是<方法內具名非靜態類別InMethodInstanceClass>物件,擁有
    x類別屬性
    物件屬性innerInstanceAttribute
    x類別方法
    物件方法innerInstanceMethod
 從物件方法innerInstanceMethod,我可以:
  存取 外部類別之類別屬性outerStaticAttribute
  存取 外部類別之物件屬性outerInstanceAttribute
  存取 內部類別之物件屬性innerInstanceAttribute
  呼叫 外部類別之類別方法outerStaticMethod
  呼叫 外部類別之物件方法outerInstanceMethod

5.使用類別方法內匿名靜態類別...
我是<方法內匿名靜態類別 adapted from InMethodUnnamedClass>物件,擁有
    類別屬性innerStaticAttribute.2
    物件屬性innerInstanceAttribute,2,3
    類別方法innerStaticMethod
    物件方法innerInstanceMethod
 從類別方法innerStaticMethod,我可以:
  存取 私密 內部類別之類別屬性innerStaticAttribute
  存取 公開 內部類別之類別屬性innerStaticAttribute2
 從 覆寫的 物件方法innerInstanceMethod,我可以:
  存取 外部類別之類別屬性outerStaticAttribute
  存取 舊有公開 內部類別之類別屬性innerStaticAttribute2
  存取 舊有公開 內部類別之物件屬性innerInstanceAttribute2
  存取 添加私密 內部類別之物件屬性innerInstanceAttribute3
  呼叫 外部類別之類別方法outerStaticMethod

6.使用物件方法內匿名非靜態類別...
我是<方法內匿名非靜態類別 adapted from InMethodUnnamedClass>物件,擁有
    類別屬性innerStaticAttribute,2
    物件屬性innerInstanceAttribute,2,3
    類別方法innerStaticMethod
    物件方法innerInstanceMethod
 從類別方法innerStaticMethod,我可以:
  存取 私密 內部類別之類別屬性innerStaticAttribute
  存取 公開 內部類別之類別屬性innerStaticAttribute2
 從 覆寫的 物件方法innerInstanceMethod,我可以:
  存取 外部類別之類別屬性outerStaticAttribute
  存取 外部類別之物件屬性outerInstanceAttribute
  存取 舊有公開 內部類別之類別屬性innerStaticAttribute2
  存取 舊有公開 內部類別之物件屬性innerInstanceAttribute2
  存取 添加私密 內部類別之物件屬性innerInstanceAttribute3
  呼叫 外部類別之類別方法outerStaticMethod
  呼叫 外部類別之物件方法outerInstanceMethod
*/
class OuterClass {
  private static String outerStaticAttribute = "外部類別之類別屬性outerStaticAttribute";
  private String outerInstanceAttribute = "外部類別之物件屬性outerInstanceAttribute";

  public OuterClass() {
    System.out.println(this);
  }

  public String toString() {
    String text = "";

    text = text + "我是<外部類別OuterClass>物件,擁有\n";
    text = text + "\t類別屬性outerStaticAttribute\n";
    text = text + "\t物件屬性outerInstanceAttribute\n";
    text = text + "\t類別方法outerStaticMethod\n";
    text = text + "\t物件方法outerInstanceMethod";

    return text;
  }

  // 外部類別靜態方法
  public static void outerStaticMethod() {
    System.out.println("  呼叫 外部類別之類別方法outerStaticMethod");
  }

  public static void outerStaticMethod2() {
    class InMethodStaticClass {
      //private static String innerStaticAttribute = "內部類別之類別屬性innerStaticAttribute";
      //  inner classes cannot have static declarations
      private String innerInstanceAttribute = "內部類別之物件屬性innerInstanceAttribute";

      public InMethodStaticClass() {
        System.out.println("我是<方法內具名靜態類別InMethodStaticClass>物件,擁有");
        System.out.println("\tx類別屬性");
        System.out.println("\t物件屬性innerInstanceAttribute");
        System.out.println("\tx類別方法");
        System.out.println("\t物件方法innerInstanceMethod");
      }

      public String toString() {
        return "我是<方法內具名靜態類別>物件";
      }

      //public static void innerStaticMethod()
      //  inner classes cannot have static declarations
      /*
      {
        System.out.println( " 從類別方法innerStaticMethod,我可以:");
        System.out.println( "  存取 " + outerStaticAttribute);
        //System.out.println( "  存取 " + outerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        System.out.println( "  存取 " + innerStaticAttribute);
        //System.out.println( "  存取 " + innerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        outerStaticMethod();
        //outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
      */

      public void innerInstanceMethod() {
        System.out.println(" 從物件方法innerInstanceMethod,我可以:");
        System.out.println("  存取 " + outerStaticAttribute);
        //System.out.println( "  存取 " + outerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        //System.out.println( "  存取 " + innerStaticAttribute);
        //  non-static variable cannot be referenced from a static context
        System.out.println("  存取 " + innerInstanceAttribute);
        outerStaticMethod();
        //outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
    }

    InMethodStaticClass imsc = new InMethodStaticClass();
    //imnic.innerStaticMethod();
    imsc.innerInstanceMethod();
  }

  public static void outerStaticMethod3() {
    InMethodUnnamedClass imuc = new InMethodUnnamedClass() {
      //private static String innerStaticAttribute3 = "內部類別之類別屬性innerStaticAttribute";
      //  inner classes cannot have static declarations
      private String innerInstanceAttribute3 = "內部類別之物件屬性innerInstanceAttribute3";

      public String toString() {
        String text = "";

        text = text + "我是<方法內匿名靜態類別 adapted from InMethodUnnamedClass>物件,擁有\n";
        text = text + "\t類別屬性innerStaticAttribute.2\n";
        text = text + "\t物件屬性innerInstanceAttribute,2,3\n";
        text = text + "\t類別方法innerStaticMethod\n";
        text = text + "\t物件方法innerInstanceMethod";

        return text;
      }

      //cannot overwrite constructor
      //  invalid method declaration; return type required
      //public InMethodUnnamedClass()
      /*{
        System.out.println( "我是<方法內匿名非靜態類別>物件,擁有" );
        System.out.println( "\tx類別屬性" );
        System.out.println( "\t物件屬性innerInstanceAttribute" );
        System.out.println( "\tx類別方法" );
        System.out.println( "\t物件方法innerInstanceMethod" );
      }*/

      //public static void innerStaticMethod()
      //  inner classes cannot have static declarations
      /*
      {
        System.out.println( " 從類別方法innerStaticMethod,我可以:");
        System.out.println( "  存取 " + outerStaticAttribute);
        //System.out.println( "  存取 " + outerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        System.out.println( "  存取 " + innerStaticAttribute);
        //System.out.println( "  存取 " + innerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        outerStaticMethod();
        //outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
      */

      //  overwriting method must exist in prototype class
      public void innerInstanceMethod() {
        System.out.println(" 從 覆寫的 物件方法innerInstanceMethod,我可以:");
        System.out.println("  存取 " + outerStaticAttribute);
        //System.out.println( "  存取 " + outerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        //System.out.println( "  存取 舊有私密 " + innerStaticAttribute);
        //  innerStaticAttribute has private access in InMethodUnnamedClass
        System.out.println("  存取 舊有公開 " + innerStaticAttribute2);
        //System.out.println( "  存取 添加私密 " + innerStaticAttribute3);
        //System.out.println( "  存取 " + innerInstanceAttribute);
        //  innerInstanceAttribute has private access in InMethodUnnamedClass
        System.out.println("  存取 舊有公開 " + innerInstanceAttribute2);
        System.out.println("  存取 添加私密 " + innerInstanceAttribute3);
        outerStaticMethod();
        //outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
    };

    imuc.innerStaticMethod();
    imuc.innerInstanceMethod();
  }

  // 外部類別物件方法
  public void outerInstanceMethod() {
    System.out.println("  呼叫 外部類別之物件方法outerInstanceMethod");
  }

  public void outerInstanceMethod2() {
    class InMethodInstanceClass {
      //private static String innerStaticAttribute = "內部類別之類別屬性innerStaticAttribute";
      //  inner classes cannot have static declarations
      private String innerInstanceAttribute = "內部類別之物件屬性innerInstanceAttribute";

      public InMethodInstanceClass() {
        System.out.println(this.toString());
      }

      public String toString() {
        String text = "";

        text = text + "我是<方法內具名非靜態類別InMethodInstanceClass>物件,擁有\n";
        text = text + "\tx類別屬性\n";
        text = text + "\t物件屬性innerInstanceAttribute\n";
        text = text + "\tx類別方法\n";
        text = text + "\t物件方法innerInstanceMethod";

        return text;
      }

      //public static void innerStaticMethod()
      //  inner classes cannot have static declarations
      /*
      {
        System.out.println( " 從類別方法innerStaticMethod,我可以:");
        System.out.println( "  存取 " + outerStaticAttribute);
        //System.out.println( "  存取 " + outerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        System.out.println( "  存取 " + innerStaticAttribute);
        //System.out.println( "  存取 " + innerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        outerStaticMethod();
        outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
      */

      public void innerInstanceMethod() {
        System.out.println(" 從物件方法innerInstanceMethod,我可以:");
        System.out.println("  存取 " + outerStaticAttribute);
        System.out.println("  存取 " + outerInstanceAttribute);
        //System.out.println( "  存取 " + innerStaticAttribute);
        //  non-static variable cannot be referenced from a static context
        System.out.println("  存取 " + innerInstanceAttribute);
        outerStaticMethod();
        outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
    }

    InMethodInstanceClass imic = new InMethodInstanceClass();
    //imic.innerStaticMethod();
    imic.innerInstanceMethod();
  }

  public void outerInstanceMethod3() {
    InMethodUnnamedClass imuc = new InMethodUnnamedClass() {
      //private static String innerStaticAttribute3 = "內部類別之類別屬性innerStaticAttribute";
      //  inner classes cannot have static declarations
      private String innerInstanceAttribute3 = "內部類別之物件屬性innerInstanceAttribute3";

      public String toString() {
        String text = "";

        text = text + "我是<方法內匿名非靜態類別 adapted from InMethodUnnamedClass>物件,擁有\n";
        text = text + "\t類別屬性innerStaticAttribute,2\n";
        text = text + "\t物件屬性innerInstanceAttribute,2,3\n";
        text = text + "\t類別方法innerStaticMethod\n";
        text = text + "\t物件方法innerInstanceMethod";

        return text;
      }

      //cannot overwrite constructor
      //  invalid method declaration; return type required
      //public InMethodUnnamedClass()
      /*{
        System.out.println( "我是<方法內匿名非靜態類別>物件,擁有" );
        System.out.println( "\tx類別屬性" );
        System.out.println( "\t物件屬性innerInstanceAttribute" );
        System.out.println( "\tx類別方法" );
        System.out.println( "\t物件方法innerInstanceMethod" );
      }*/

      //public static void innerStaticMethod()
      //  inner classes cannot have static declarations
      /*
      {
        System.out.println( " 從類別方法innerStaticMethod,我可以:");
        System.out.println( "  存取 " + outerStaticAttribute);
        //System.out.println( "  存取 " + outerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        System.out.println( "  存取 " + innerStaticAttribute);
        //System.out.println( "  存取 " + innerInstanceAttribute);
        //  non-static variable cannot be referenced from a static context
        outerStaticMethod();
        //outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
      */

      //  overwriting method must exist in prototype class
      public void innerInstanceMethod() {
        System.out.println(" 從 覆寫的 物件方法innerInstanceMethod,我可以:");
        System.out.println("  存取 " + outerStaticAttribute);
        System.out.println("  存取 " + outerInstanceAttribute);
        //System.out.println( "  存取 舊有私密 " + innerStaticAttribute);
        //  innerStaticAttribute has private access in InMethodUnnamedClass
        System.out.println("  存取 舊有公開 " + innerStaticAttribute2);
        //System.out.println( "  存取 添加私密 " + innerStaticAttribute3);
        //System.out.println( "  存取 " + innerInstanceAttribute);
        //  innerInstanceAttribute has private access in InMethodUnnamedClass
        System.out.println("  存取 舊有公開 " + innerInstanceAttribute2);
        System.out.println("  存取 添加私密 " + innerInstanceAttribute3);
        outerStaticMethod();
        outerInstanceMethod();
        //  non-static method cannot be referenced from a static context
      }
    };

    imuc.innerStaticMethod();
    imuc.innerInstanceMethod();
  }

  // 類別內具名靜態類別
  public static class InClassStaticClass {
    private static String innerStaticAttribute = "內部類別之類別屬性innerStaticAttribute";
    private String innerInstanceAttribute = "內部類別之物件屬性innerInstanceAttribute";

    public InClassStaticClass() {
      System.out.println("我是<類別內具名靜態類別InClassStaticClass>物件,擁有");
      System.out.println("\t類別屬性innerStaticAttribute");
      System.out.println("\t物件屬性innerInstanceAttribute");
      System.out.println("\t類別方法innerStaticMethod");
      System.out.println("\t物件方法innerInstanceMethod");
    }

    public static void innerStaticMethod() {
      System.out.println(" 從類別方法innerStaticMethod,我可以:");
      System.out.println("  存取 " + outerStaticAttribute);
      //System.out.println( "  存取 " + outerInstanceAttribute);
      //  non-static variable cannot be referenced from a static context
      System.out.println("  存取 " + innerStaticAttribute);
      //System.out.println( "  存取 " + innerInstanceAttribute);
      //  non-static variable cannot be referenced from a static context
      outerStaticMethod();
      //outerInstanceMethod();
      //  non-static method cannot be referenced from a static context
    }

    public void innerInstanceMethod() {
      System.out.println(" 從物件方法innerInstanceMethod,我可以:");
      System.out.println("  存取 " + outerStaticAttribute);
      //System.out.println( "  存取 " + outerInstanceAttribute);
      //  non-static variable cannot be referenced from a static context
      System.out.println("  存取 " + innerStaticAttribute);
      System.out.println("  存取 " + innerInstanceAttribute);
      outerStaticMethod();
      //outerInstanceMethod();
      //  non-static method cannot be referenced from a static context
    }
  }

  // 類別內具名非靜態類別
  public class InClassInstanceClass {
    //private static String innerStaticAttribute = "內部類別之類別屬性";
    //  inner classes cannot have static declarations
    private String innerInstanceAttribute = "內部類別之物件屬性innerInstanceAttribute";

    public InClassInstanceClass() {
      System.out.println("我是<類別內具名非靜態類別InClassInstanceClass>物件,擁有");
      System.out.println("\tx類別屬性");
      System.out.println("\t物件屬性innerInstanceAttribute");
      System.out.println("\tx類別方法");
      System.out.println("\t物件方法innerInstanceMethod");
    }

    //public static void innerStaticMethod()
    //  inner classes cannot have static declarations
    /*
    {
      System.out.println( "從類別方法,我可以:");
      System.out.println( " 存取 " + outerStaticAttribute);
      //System.out.println( " 存取 " + outerInstanceAttribute);
      //   non-static variable cannot be referenced from a static context
      //System.out.println( " 存取 " + innerStaticAttribute);
      System.out.println( " 存取 " + innerInstanceAttribute);
      outerStaticMethod();
      //outerInstanceMethod();
      //  non-static method cannot be referenced from a static context
    }
    */

    public void innerInstanceMethod() {
      System.out.println(" 從物件方法innerInstanceMethod,我可以:");
      System.out.println("  存取 " + outerStaticAttribute);
      System.out.println("  存取 " + outerInstanceAttribute);
      //System.out.println( "  存取 " + innerStaticAttribute);
      System.out.println("  存取 " + innerInstanceAttribute);
      outerStaticMethod();
      outerInstanceMethod();
    }
  }
}

class InMethodUnnamedClass {
  private static String innerStaticAttribute = "內部類別之類別屬性innerStaticAttribute";
  public static String innerStaticAttribute2 = "內部類別之類別屬性innerStaticAttribute2";
  //  inner classes cannot have static declarations
  private String innerInstanceAttribute = "內部類別之物件屬性innerInstanceAttribute";
  public String innerInstanceAttribute2 = "內部類別之物件屬性innerInstanceAttribute2";

  public InMethodUnnamedClass() {
    System.out.println(this.toString());
  }

  public String toString() {
    String text = "";

    text = text + "我是<方法內匿名類別InMethodUnnamedClass>物件,擁有\n";
    text = text + "\t類別屬性innerStaticAttribute,2\n";
    text = text + "\t物件屬性innerInstanceAttribute,2\n";
    text = text + "\t類別方法innerStaticMethod\n";
    text = text + "\t物件方法innerInstanceMethod";

    return text;
  }

  public static void innerStaticMethod() {
    System.out.println(" 從類別方法innerStaticMethod,我可以:");
    //System.out.println( "  存取 " + outerStaticAttribute);
    //System.out.println( "  存取 " + outerInstanceAttribute);
    //  non-static variable cannot be referenced from a static context
    System.out.println("  存取 私密 " + innerStaticAttribute);
    System.out.println("  存取 公開 " + innerStaticAttribute2);
    //outerStaticMethod();
    //outerInstanceMethod();
    //  non-static method cannot be referenced from a static context
  }

  public void innerInstanceMethod() {
    System.out.println(" 從物件方法innerInstanceMethod,我可以:");
    //System.out.println( "  存取 " + outerStaticAttribute);
    //System.out.println( "  存取 " + outerInstanceAttribute);
    //  non-static variable cannot be referenced from a static context
    System.out.println("  存取 私密 " + innerStaticAttribute);
    System.out.println("  存取 公開 " + innerStaticAttribute2);
    System.out.println("  存取 私密 " + innerInstanceAttribute);
    System.out.println("  存取 公開 " + innerInstanceAttribute2);
    //outerStaticMethod();
    //outerInstanceMethod();
    //  non-static method cannot be referenced from a static context
  }
}

public class Inner {
  public static void main(String args[]) {
    OuterClass oc = new OuterClass();

    // 使用類別內具名靜態類別
    System.out.println("\n1.使用類別內具名靜態類別...");
    // 建立<類別內具名靜態類別>之物件
    OuterClass.InClassStaticClass oc_icsc = new OuterClass.InClassStaticClass();

    OuterClass.InClassStaticClass.innerStaticMethod();
    oc_icsc.innerInstanceMethod();


    // 使用類別內具名非靜態類別
    //   要使用類別內具名靜態類別,需先建立其外部類別之物件
    System.out.println("\n2.使用類別內具名非靜態類別...");
    OuterClass.InClassInstanceClass oc_icic = oc.new InClassInstanceClass();
    //oc_icic.innerStaticMethod();
    oc_icic.innerInstanceMethod();

    // 使用方法內具名類別
    System.out.println("\n3.使用類別方法內具名靜態類別...");
    OuterClass.outerStaticMethod2();

    System.out.println("\n4.使用物件方法內具名非靜態類別...");
    oc.outerInstanceMethod2();

    // 使用方法內具匿名類別
    System.out.println("\n5.使用類別方法內匿名靜態類別...");
    OuterClass.outerStaticMethod3();

    System.out.println("\n6.使用物件方法內匿名非靜態類別...");
    oc.outerInstanceMethod3();
  }
}