1. 程式人生 > >Java內部類及內部介面

Java內部類及內部介面

文章目錄

 

內部類

package Learn.com.seven;

public class ParcellA {//外部類
    
    private int pMember;//宣告一個私有成員
    private static int pstMember;//宣告一個私有靜態成員
    private final int pfMember=9;//常量值
    private final static int pfsMember=0;//常量靜態成員
    
    /**
     * 
     *  -#  普通內部類可以訪問外部類的所有成員和方法,
     *  -#  如何在其他的類訪問此內部類呢
     *  -#  必須使用外部類的物件來建立內部類物件
     *  -#  ParcellA parcel = new ParcellA(); 見Entry.java
     *      ParcellA.Contents content = parcel.new Contents();
     */
    public class Contents{//巢狀定義一個內部類
        private int i = 11;
        
        public int value(){//給內部類,定義的一個方法
            System.out.println(pMember);//所有成員
            System.out.println(pstMember);
            System.out.println(pfMember);
            System.out.println(pfsMember);
            outClassMethod();//可以訪問外部類的普通方法
            outClassStaticMehtod();//及靜態方法
            return i;
        }    
      
        /**
         * @see 但是若Contesnts是靜態的,則可以宣告靜態成員和靜態方法
         */
//        private static int j=0;//非靜態內部類,不能宣告[靜態成員]
//        private static int  out(){//非靜態內部類,不能宣告[靜態方法]        
//        }
    
    }
    /**
     * 
     *    - 定義一個巢狀靜態內部類
     *    -# 不能訪問外部內的【非靜態成員】,只能訪問外部類的【靜態成員】。同理也不能訪問外部類的非靜態方法
     *      
     */
    public static class InnerStaticClass{
        private static int memberOfStatic;//可以定義靜態成員        
        private static int Out(){//可以定義靜態方法
            //outClassMethod();//不能訪問外部類的非靜態方法
            //System.out.println(pMember);//由於ParcellA,是靜態內部類,所以不能訪問外部內的非靜態成員
              //因為靜態類,是在載入類時,就初始化了。而非靜態成員,是在建立物件時才初始化,分配記憶體
              //因此,在靜態類初始化時訪問外部類的非靜態成員時,非靜態成員還不存在,所以不能訪問
            System.out.println(pstMember);//可以訪問靜態成員
            System.out.println(pfsMember);//可以訪問常量成員.由於final int是不可變的成員,即在程式執行中它的值不可以修改。因此
                          //final成員的值,就可以在載入類時就確定下來。所以在靜態內部類訪問它時,它是已知的,所以就 
                          //可以訪問
            System.out.println(pfsMember);//同上原因,所以可以訪問        
            outClassStaticMehtod();//可以訪問靜態方法            
            return memberOfStatic;
        }    
        
        public void Myout(){
            Out();
        }
    }
   
    class Destination{//定義另一個內部類,注意預設訪問許可權為包訪問許可權,不能在另一個包訪問
        private String label;
        Destination(String WhereTo){//內部類的構造方法
            label =WhereTo;
        }
        String ReadLabel(){//給內部類,定義的一個方法
            return label;
        }
    }
    
    
    public void outClassMethod(){
        System.out.println("outClass Non_Static Method");
    }
    public static void outClassStaticMehtod(){
        System.out.println("outClass Static Method");
    }
}



package Learn.com.test;
import Learn.com.seven.ParcellA;

public class Entry {

    public static void main(String[] args) {
        ParcellA parcel = new ParcellA();
        //由於Contests這個內部類,是public許可權,所以可以訪問,
        //但注意必須是用外部類ParcellA的物件來parcel.new 來建立內部類的物件.
        //並且宣告內部類的物件時,需要使用ParcellA.Contents 這種"外部類.內部類"的方式
        
        ParcellA.Contents content = parcel.new Contents();
        content.value();
                
        
        //由於Destination,是包訪問許可權,所以下面的訪問錯誤 
        //ParcellA.Destination desten = parcel.new Destination("china");
        
        //注意,由於InnerStaticClass是ParcellA的靜態內部類,所以可以直接用它來建立物件
        //對於這種用法,在android中的佈局中用到,比如
        //LinearLayout.LayoutParams params =  new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT);
        //LinearLayout.LayoutParams 類就是LinearLayout中的靜態內部類,可以通過android的LinearLayout.java原始碼檢視        
        ParcellA.InnerStaticClass obj = new ParcellA.InnerStaticClass();
        obj.Myout();//可以呼叫public方法    ,只能訪問自己的方法,在這裡不能直接訪問外部類的方法,外部方法對它不可見                    
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113

普通內部類

常規內部類:常規內部類沒有用static修飾且定義在在外部類類體中。

  1. 常規內部類中的方法可以直接使用外部類的例項變數和例項方法。
  2. 在常規內部類中可以直接用內部類建立物件
public class MyOuter {
    private int x = 100;
     
    class MyInner{
        private String y="Hello!";
        public void innerMethod(){
            System.out.println("內部類中 String ="+y);
            System.out.println("外部類中的x ="+x);
            outerMethod();
            System.out.println("x is "+MyOuter.this.x);
        }
    }
     
    public void outerMethod(){
        x++;
    }
     
    public void makeInner(){
        //在外部類方法中建立內部類例項
        MyInner in = new MyInner();
    }
     
    public static void main(String[] args){
        MyOuter mo = new MyOuter();
        //使用外部類構造方法建立 mo 常規內部類需要通過外部類例項來new
        MyOuter.MyInner inner = mo.new MyInner();
        inner.innerMethod();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

應用

@Service("brandShopUgcExecutor")
@Slf4j
public class BrandShopUgcExecutor implements JobExecutor {
   
    private List<Integer> sortReviews(List<ReviewData> reviewDataList) {
        BrandShopUgcExecutor brandShopUgcExecutor = new BrandShopUgcExecutor();
        //使用內部類
        OrderByWeight orderByWeight = brandShopUgcExecutor.new OrderByWeight();
        OrderByFollowNote orderByFollowNote = brandShopUgcExecutor.new OrderByFollowNote();
        Ordering<ReviewData> ordering = Ordering.from(orderByWeight).compound(orderByFollowNote);
        //使用匿名內部類更合適,因為只有這一個地方使用
     Ordering.from(new Comparator<ReviewData>() {

            @Override
            public int compare(ReviewData o1, ReviewData o2) {
                return Doubles.compare(getReviewWeight(o2), getReviewWeight(o1));
            }
        }).compound(new Comparator<ReviewData>() {

            @Override
            public int compare(ReviewData o1, ReviewData o2) {
                return Ints.compare(o1.getFollowNoteNo(), o2.getFollowNoteNo());
            }
        });
        Collections.sort(reviewDataList, ordering);
        List<Integer> reviewIdList = Lists.newArrayList();
        for (ReviewData reviewData : reviewDataList) {
            reviewIdList.add(reviewData.getReviewId());
        }
        return reviewIdList;
    }

    /**
     * 按權重排序
     */
    public class OrderByWeight implements Comparator<ReviewData> {
        @Override
        public int compare(ReviewData r1, ReviewData r2) {
            return Doubles.compare(getReviewWeight(r2), getReviewWeight(r1));
        }
    }

    /**
     * 按回複數排序
     */
    public class OrderByFollowNote implements Comparator<ReviewData> {
        @Override
        public int compare(ReviewData r1, ReviewData r2) {
            return Ints.compare(r1.getFollowNoteNo(), r2.getFollowNoteNo());
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

靜態內部類

靜態內部類:與類的其他成員相似,可以用static修飾內部類,這樣的類稱為靜態內類。靜態內部類與靜態內部方法相似,只能訪問外部類的static成員,不能直接訪問外部類的例項變數,與例項方法,只有通過物件引用才能訪問。

public class MyOuter2 {
     
    public static int x=100;
     
    public static class Myinner{
        private String y="Hello!";
        /**
         * 由於static內部類不具有任何對外部類例項的引用,
         * 因此static內部類中不能使用this關鍵字來訪問外部類中的例項成員,
         * 但是可以訪問外部類中的static成員。這與一般類的static方法相通
         */
        public void innerMethod(){
            System.out.println("x="+x);
            System.out.println("y="+y);
        }
    }
     
    public static void main(String[] args){
        MyOuter2.Myinner si = new MyOuter2.Myinner();
        si.innerMethod();
    }
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

區域性內部類

區域性內部類:在方法體或語句塊(包括方法、構造方法、區域性塊或靜態初始化塊)內部定義的類成為區域性內部類。
區域性內部類不能加任何訪問修飾符,因為它只對區域性塊有效。

  1. 區域性內部類只在方法體中有效,就想定義的區域性變數一樣,在定義的方法體外不能建立區域性內部類的物件
  2. 在方法內部定義類時,應注意以下問題:
    2.1 方法定義區域性內部類同方法定義區域性變數一樣,不能使用private、protected、public等訪問修飾說明符修飾,也不能使用static修飾,但可以使用final和 abstract修飾
    2.2方法中的內部類可以訪問外部類成員。對於方法的引數和區域性變數,必須有final修飾才可以訪問。
    2.3static方法中定義的內部類可以訪問外部類定義的static成員
public class MyOuter3 {
    private int size=5,y=7;
     
    public Object makeInner(int localVar){
        final int finalLocalVar = localVar;
         
        //建立內部類,該類只在makeInner()方法有效,就像區域性變數一樣。
        //在方法體外部不能建立MyInner類的物件
        class Myinner{
            int y=4;
            public String toString(){
                return "OuterSize:"+size+" localVar:"+finalLocalVar+"\nthis.y="+this.y;
            }
        }
         
        return new Myinner();
    }
     
    public static void main(String[] args){
        Object obj = new MyOuter3().makeInner(47);
        System.out.println(obj.toString());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

匿名內部類

定義類的最終目的是建立一個類的例項,但是如果某個類的例項只是用一次,則可以將類的定義與類的建立,放到與一起完成,或者說在定義類的同時就建立一個類以這種方法定義的沒有名字的類成為匿名內部類。
宣告和構造匿名內部類的一般格式如下:

   new ClassOrInterfaceName(){
    類體 }
  • 1
  • 2
  1. 匿名內部類可以繼承一個類或實現一個介面,這裡的ClassOrInterfaceName是匿名內部類所繼承的類名或實現的介面名。但匿名內部類不能同時實現一個介面和繼承一個類也不能實現多個介面。如果實現了一個介面,該類是Object類的直接子類,匿名類繼承一個類或實現一個介面,不需要extends和implements關鍵字。
  2. 由於匿名內部類沒有名稱,所以類體中不能定義構造方法,由於不知道類名也不能使用關鍵字來建立該類的例項。實際上匿名內部類的定義、構造、和第一次使用都發生在同樣一個地方。此外,上式是一個表示式,返回的是一個物件的引用,所以可以直接使用或將其複製給一個物件變數。例:
   TypeName obj=new Name(){
   此處為類體
      }
  同樣,也可以將構造的物件作為呼叫的引數。例:
    
   someMethod(new Name(){
   此處為類體  });*/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

內部介面

為了弄清楚內部介面是如何工作的,我們可以拿它與內部類作比較。內部類可以被認為是一個外部類內部定義的一個常規方法。因為一個方法可以被宣告為靜態和非靜態,類似的內部類也可以被宣告為靜態和非靜態。靜態類類似於靜態方法,它只能訪問外部類的靜態成員屬性。非靜態方法可以訪問外部類的所有成員屬性。

  • 一種對那些在同一個地方使用的介面進行邏輯上分組;
  • 封裝思想的體現;
  • 因為介面是不能例項化的,內部介面只有當它是靜態的才有意義。因此,預設情況下,內部介面是靜態的,不管你是否手動加了static關鍵字。
public class MyOuter4 {
    private int size=5;
    private int id;
     
    public interface OnClickListener{
        void onClick(int id);
    }
     
    public void onClick(OnClickListener obj){
        obj.onClick(this.id);
    }
     
    public Object makeInner(int localvar){
        final int finallocalvar = localvar;
        return new Object(){
            public String toString(){
                return "OuterSize="+size+"\nfinalLocalvar="+finallocalvar;
            }
        };
    }
     
    public static void main(String args[]){
        Object obj=new MyOuter4().makeInner(67);
        System.out.println(obj.toString());
         
        MyOuter4 m = new MyOuter4();
        m.onClick(new OnClickListener() {
             
            @Override
            public void onClick(int id) {
                System.out.println(id);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
public class Util {
    public interface Worker {
        void work();
    }
}
  
package com.dao.util;
 
import com.dao.util.Util.Worker;
 
public class Demo implements Worker {
    public void work() {
        System.out.println("Is working");
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在這個util類裡面封裝了會改變的Worker,也就是說,util類裡面有自己的演算法:一部分是固定,另外一部分是可變的,而這個可變的部分就變成了一個介面(介面是特殊的抽象類其實的意思大概的這個worker可能在不同的工作環境有不同的工作方式,例如work(),onvaction())所以在類裡面放一個介面不是什麼新的設計,而是一種思想方式,讓程式碼擴充套件性更高。

參考:
https://www.cnblogs.com/activity-life/p/3622850.html
https://www.cnblogs.com/as3lib/p/6107915.html(java 四種內部類和內部介面)