Java Inner Class 內部類

內部類 ?Inner Class

一個內部類可以定義在另一個類里,可以定義在函數里,甚至可以作為一個表達式的一部分。

Java中的內部類共分為四種

  靜態內部類static inner class (also called nested class)

  成員內部類member inner class

  局部內部類local inner class

  匿名內部類anonymous inner class

?

1?成員內部類 ?member inner class

?

1.1 形式

成員內部類也是定義在另一個類中,但是定義時不用static修飾。形如:

1 class Outer {
2     class Inner{
3     
4     }
5 }

編譯之后會產生如下2個class文件:

?

---->這可以將相關的類組織在一起,從而降低了命名空間的混亂。

?

成員內部類的修飾符:
對于普通的類,可用的修飾符有final、abstract、strictfp、public和默認的包訪問。
但是成員內部類更像一個成員變量和方法。
可用的修飾符有:final、abstract、public、private、protected、strictfp和static。
一旦用static修飾內部類,它就變成靜態內部類了。

?

1.2 創建內部類實例

成員內部類就像一個實例變量,他依賴于外部類的實例存在 --> 必須先有外部類的實例 ?才能創建成員內部類對象

在外部類里面創建成員內部類的實例:this.new Innerclass(); 或可以用 Inner inner = new Inner(); 方法直接創建

在外部類之外創建內部類的實例:(new Outerclass()).new Innerclass(); ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 或 ??Inner inner = new Outer().new Inner()

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 或 ??Outer outer = new Outer(); Inner inner = outer.new Inner();

案例:從外部類的非靜態方法中實例化內部類對象。

 1 class Outer {
 2   private int i = 10;
 3   public void makeInner(){
 4    Inner in = new Inner();
 5    in.seeOuter();
 6   }
 7   class Inner{
 8    public void seeOuter(){
 9    System.out.print(i);
10   }
11  }
12 }

表面上,我們并沒有創建外部類的對象就實例化了內部類對象,和上面的話矛盾。
事實上,如果不創建外部類對象也就不可能調用makeInner()方法,所以到頭來還是要創建外部類對象的。
你可能試圖把makeInner()方法修飾為靜態方法,即static public void makeInner()。
這樣不創建外部類就可以實例化外部類了!但是在一個靜態方法里能訪問非靜態成員和方法嗎?顯然不能。

-->?必須先有外部類的實例 ?才能創建成員內部類對象

案例:從外部類的靜態方法中實例化內部類對象

 1     class Outer {
 2         private int i = 10;
 3         class Inner{
 4             public void seeOuter(){
 5                 System.out.print(i);
 6             }
 7         }    
 8         public static void main(String[] args) {
 9             Outer out = new Outer();
10             Outer.Inner in = out.new Inner();
11             //Outer.Inner in = new Outer().new Inner();
12             in.seeOuter();
13         }
14     }

被注釋掉的那行是它上面兩行的合并形式,一條簡潔的語句。
對比一下:在外部類的非靜態方法中實例化內部類對象是普通的new方式:Inner in = new Inner();
在外部類的靜態方法中實例化內部類對象,必須先創建外部類對象:Outer.Inner in = new Outer().new Inner();

?

1.3 成員內部類操作外部類

?

成員內部類可以訪問它的外部類的所有成員變量和方法,不管是靜態的還是非靜態的都可以

內部類就像一個實例成員一樣存在于外部類,所以內部類可以訪問外部類的所有成員就想訪問自己的成員一樣沒有限制。

?

內部類中的this指的是內部類的實例對象本身,如果要用外部類的實例對象就可以用類名.this的方式獲得。

普通的類可以用this引用當前的對象,內部類也是如此。

但是假若內部類想引用外部類當前的對象呢?用“外部類名”.this;的形式,如下例的Outer.this。

 1 class Outer {
 2    class Inner{
 3       public void seeOuter(){
 4         System.out.println(this);
 5         System.out.println(Outer.this);
 6       }
 7    }
 8 
 9    public static void main(String[] strs){
10      new Outer().new Inner().seeOuter();
11    }
12 }
13 
14 輸出:
15 Outer$Inner@61de33
16 Outer@14318bb

1.4?內部類對象中不能有靜態成員

原因很簡單,內部類的實例對象是外部類實例對象的一個成員,若沒有外部類對象,內部類就不會存在,何談靜態成員呢。

 1 class Outer {
 2    class Inner{
 3       static int i = 0;
 4       public void seeOuter(){
 5         System.out.println(this);
 6         System.out.println(Outer.this);
 7       }
 8    }
 9 
10    public static void main(String[] strs){
11      new Outer().new Inner().seeOuter();
12    }
13 }

我們編譯這個類:

1  E:\>javac Outer.java
2  Outer.java:3: 內部類不能有靜態聲明
3            static int i = 0;
4                      ^
5  1 錯誤

?

2?局部內部類local inner class

?

局部內部類local inner class 也可以成為方法內部類

顧名思義,就是把類放在方法內。局部內部類定義在方法中,比方法的范圍還小。是內部類中最少用到的一種類型。

像局部變量一樣,不能被public, protected, private和static修飾。

局部內部類在方法中定義,所以只能在方法中使用,即只能在方法當中生成局部內部類的實例并且調用其方法。

 1  class Outer {
 2         public void doSomething(){
 3             class Inner{
 4                 public void seeOuter(){
 5                     System.out.println("inner class");
 6                 }
 7             } 
 8             
 9             Inner inner = new Inner();
10             inner.seeOuter();
11         }
12 
13         public static void main(String ... args){
14           new  Outer().doSomething();
15         }
16     }

輸出:

inner class

局部內部類只能在聲明的方法內是可見的,因此定義局部內部類之后,想用的話就要在方法內直接實例化,
記住這里順序不能反了,一定是要先聲明后使用,否則編譯器會說找不到。

方法內部類的修飾符:
? 與成員內部類不同,方法內部類更像一個局部變量。
? 可以用于修飾方法內部類的只有final和abstract。


注意事項:

A: 方法內部類只能在定義該內部類的方法內實例化,不可以在此方法外對其實例化
B: 方法內部類對象不能使用該內部類所在方法的非final局部變量。

原因:

? ? ?因為方法的局部變量位于棧上,只存在于該方法的生命期內。當一個方法結束,其棧結構被刪除,局部變量成為歷史。
? ? 但是該方法結束之后,在方法內創建的內部類對象可能仍然存在于堆中!例如,如果對它的引用被傳遞到其他某些代碼,并存儲在一個成員變量內。
? ? 正因為不能保證局部變量的存活期和方法內部類對象的一樣長,所以內部類對象不能使用它們。下面是完整的例子:

 1 class Outer {
 2 public void doSomething(){
 3   final int a =10;
 4   class Inner{
 5     public void seeOuter(){
 6       System.out.println(a);
 7     }
 8   } 
 9   Inner in = new Inner();
10   in.seeOuter(); 
11    }
12   public static void main(String[] args) {
13     Outer out = new Outer();
14     out.doSomething();
15    }
16 }

? C:靜態方法內的方法內部類。

? ? ?靜態方法是沒有this引用的,因此在靜態方法內的內部類遭受同樣的待遇,即:只能訪問外部類的靜態成員。

?

3?匿名內部類Anonymous Inner Class

顧名思義,沒有名字的內部類。

匿名內部類就是沒有名字的局部內部類,不使用關鍵字class, extends, implements, 沒有構造方法。

匿名內部類隱式地繼承了一個父類或者實現了一個接口

匿名內部類使用得比較多,通常是作為一個方法參數。

?

A、繼承式的匿名內部類。

 1 class Car {
 2      public void drive(){
 3          System.out.println("Driving a car!");
 4      }
 5  }
 6 
 7 
 8     class Test{
 9         public static void main(String[] args) {
10             Car car = new Car(){
11                 public void drive(){
12                     System.out.println("Driving another car!");
13                 }
14             };
15             car.drive();
16         }
17     }

?

結果輸出了:Driving another car!


建立匿名內部類的關鍵點是重寫父類的一個或多個方法。再強調一下,是重寫父類的方法,而不是創建新的方法。
因為用父類的引用不可能調用父類本身沒有的方法!創建新的方法是多余的。簡言之,參考多態。

?

B、接口式的匿名內部類。

 1  interface  Vehicle {
 2         public void drive();
 3  }
 4 
 5 
 6  class Test{
 7         public static void main(String[] args) {
 8             Vehicle v = new Vehicle(){
 9                 public void drive(){
10                     System.out.println("Driving a car!");
11                 }
12             };
13             v.drive();
14  }

這種形式的代碼我們一定寫過,這也是內部類的存在的一個重要作用:便于編寫 線程和事件驅動的代碼

 1 public class ThreadDemo {
 2     public static void main(String[] args) {
 3         
 4         new Thread(new Runnable(){
 5             public void run(){
 6                 System.out.println("Hello World!");
 7             }
 8         }).start();
 9     }
10 }
11 
12 
13 E:\>javac ThreadDemo.java
14 E:\>java ThreadDemo
15 Hello World!
 1 public class SwingTest
 2 {
 3     public static void main(String[] args)
 4     {
 5         JFrame frame = new JFrame("JFrame");
 6         JButton button = new JButton("JButton");
 7 
 8         button.addActionListener(new ActionListener(){
 9 
10             @Override
11             public void actionPerformed(ActionEvent arg0){
12                 System.out.println("Hello World");
13 
14             }
15         });
16 
17         frame.getContentPane().add(button);
18         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
19         frame.setSize(200, 200);
20   
21         frame.addWindowListener(new WindowAdapter() {
22             
23             @Override
24             public void windowClosing(WindowEvent e){
25                 System.out.println("Closing");
26                 System.exit(0);
27             }
28         });
29 
30         frame.setVisible(true);
31     }
32 }

若你了解安卓的話 ?會發現這樣的代碼編寫方式有著很多的應用

好處就是簡化我們的代碼。

?

C、參數式的匿名內部類。

 1 class Bar{
 2     void doStuff(Foo f){}
 3 }
 4 
 5 inteface Foo{
 6     void foo();
 7 }
 8 
 9 class Test{
10     static void go(){
11         Bar b = new Bar();
12         b.doStuff(new Foo(){
13             public void foo(){
14                 System.out.println("foofy");
15             }
16         });
17     }
18 }
19                             

?

4?靜態內部類static inner class?

?

在定義成員內部類的時候,可以在其前面加上一個權限修飾符static。此時這個內部類就變為了靜態內部類。

同樣會被編譯成一個完全獨立的.class文件,名稱為OuterClass$InnerClass.class的形式。

只可以訪問外部類的靜態成員和靜態方法,包括了私有的靜態成員和方法。

生成靜態內部類對象的方式為:OuterClass.InnerClass inner = new OuterClass.InnerClass();

?

靜態內部類使用代碼:

 1 package com.learnjava.innerclass;
 2 
 3 class StaticInner
 4 {
 5     private static int a = 4;
 6 
 7     // 靜態內部類
 8     public static class Inner
 9     {
10         public void test()
11         {
12             // 靜態內部類可以訪問外部類的靜態成員
13             // 并且它只能訪問靜態的
14             System.out.println(a);
15         }
16 
17     }
18 }
19 
20 public class StaticInnerClassTest
21 {
22 
23     public static void main(String[] args)
24     {
25         StaticInner.Inner inner = new StaticInner.Inner();
26         inner.test();
27     }
28 }

?

與一般內部類不同,在靜態代碼中不能夠使用this操作,所以在靜態內部類中只可以訪問外部類的靜態變量和靜態方法。
使用靜態內部類的目的和使用內部類相同。如果一個內部類不依賴于其外部類的實例變量,或與實例變量無關,則選擇應用靜態內部類。

可以在靜態內部類的方法中,直接訪問外部類的靜態變量和調用靜態方法。但不允許訪問外部類的實例變量以及實例方法。
靜態內部類的實例方法中亦只允許訪問外部類的靜態成員。

?

靜態內部類不同于其他3種內部類,他有著自己特殊的特性,參看:解析靜態內部類的使用目的與限制

?

5 小結

?

5.1?幾種內部類的共性:

A、內部類仍然是一個獨立的類,在編譯之后會內部類會被編譯成獨立的.class文件,但是前面冠以外部類的類命和$符號。
B、內部類不能用普通的方式訪問。內部類是外部類的一個成員,因此內部類可以自由地訪問外部類的成員變量,無論是否是private的。

?

5.2?java中為什么要引入內部類?還有匿名內部類?

?

1)可以是單繼承的一種補充解決方案 inner classes能有效實際地允許“多重實現繼承(multiple implementation)”

? ?Java中一個類只能繼承一個類 可以通過內部類達到繼承多個類的效果

? ?:每個inner class都能夠各自繼承某一實現類(implementation),因此,inner class不受限于outer class是否已繼承自某一實現類。?

2)針對具體的問題提供具體的解決方案,同時又能對外隱藏實現細節 ? ?看具體的案例

?

案例1

在集合中可以使用Iterator遍歷 但每一種集合的數據結構不同 ?導致遍歷的方法必然也不同
所以Java在每個具體的集合里定義了一個內部類Itr ?他實現了Iterator接口 ? 從而根據所在類的具體情況進行遍歷

 1 public interface Iterator {//迭代器的功能
 2     boolean hasNext();
 3     Object next(); 
 4 }
 5 
 6 public interface Iterable {//返回迭代器的能力
 7     Iterator iterator();
 8 }
 9 
10 public interface Collection extends Iterable {
11     Iterator iterator();
12 }
13 
14 public interface List extends Collection {
15     Iterator iterator();
16 }
17 
18 public class ArrayList implements List {
19     public Iterator iterator() {
20        return new Itr();
21     }
22     
23 private class Itr implements Iterator {
24     //每種集合的具體實現采用了不同的數據結構
25         public boolean hasNext() {......}
26         public Object next(){......} 
27     }
28 }
29 
30 Collection c = new ArrayList();
31 c.add("hello");
32 c.add("world");
33 c.add("java");
34 Iterator it = c.iterator();     //new Itr();
35 while(it.hasNext()) {
36     String s = (String)it.next();
37     System.out.println(s);
38 }

Itr是private的類 對外并不可見 因為我的遍歷方法我自己知道就可以了 別人并不需要了解

集合類有實現了Tterable接口 通過里面的iterator方法獲取該內部類實例 外部不能直接創建該內部類的實例

?

案例2

為某個類提供特定的數據結構 :? 為了共同解決一個具體的問題 但又可以對外部保持透明

如HashMap中有Entry ? ConcurrentHashMap有HashEntry 和Segment ?

看HashMap中的內部類:

 1 public class HashMap<K,V>
 2     extends AbstractMap<K,V>
 3     implements Map<K,V>, Cloneable, Serializable
 4 {
 5 
 6     static final Entry<?,?>[] EMPTY_TABLE = {};
 7     transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE;
 8 
 9     static class Entry<K,V> implements Map.Entry<K,V> {
10         final K key;
11         V value;
12         Entry<K,V> next;
13         int hash;
14         // ... ...
15     } 
16 }

關于HashMap 可以參考:HashMap源碼解析

關于ConcurrentHashMap:ConcurrentHashMap??ConcurrentHashMap原理分析

轉載于:https://www.cnblogs.com/wihainan/p/4773090.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/256776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/256776.shtml
英文地址,請注明出處:http://en.pswp.cn/news/256776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SLAM系統工程,常用數據集下載鏈接(TUM KITTI DSO Mono EuRoC)

TUM 鏈接&#xff1a;https://pan.baidu.com/s/1nwXtGqH 密碼&#xff1a;lsgr KITTI 鏈接&#xff1a;https://pan.baidu.com/s/1htFmXDE 密碼&#xff1a;uu20 DSO 鏈接&#xff1a;https://pan.baidu.com/s/1eSRmeZK 密碼&#xff1a;6x5b Mono 鏈接&#xff1a;http…

uva1331三角剖分

題意&#xff1a;輸入一個簡單m&#xff08;2<m<50)邊形&#xff0c;找到一個最大三角形最小的三角剖分&#xff08;用不相交的對角線把一個多邊形分成若干個三角形&#xff09;。輸出最大的三角形面積。 分析&#xff1a;每條對角線都是無序的&#xff0c;因此&#xff…

Halcon算子翻譯——default

名稱 default - switch段中的備用分支。 用法 default( : : : ) 描述 default在switch段中開放備用分支。 如果switch語句的控制表達式的計算結果不匹配前面的case語句的任何整數常量&#xff0c;則訪問該分支。 結果 default&#xff08;作為算子&#xff09;總是返回2&#x…

現代制造工程筆記01:課程安排

電子教材&#xff1a;http://www.bookask.com/read/4588.html

(轉).gitignore詳解

本文轉自http://sentsin.com/web/666.html 今天講講Git中非常重要的一個文件——.gitignore。 首先要強調一點&#xff0c;這個文件的完整文件名就是“.gitignore”&#xff0c;注意最前面有個“.”。這樣沒有擴展名的文件在Windows下不太好創建&#xff0c;這里給出win7的創建…

Effective Java 英文 第二版 讀書筆記 Item 14:In public classes,use accessor methods,not public fields...

本章主要分析 公開屬性與私有屬性提供公開get、set方法兩種方式對比 // Degenerate classes like this should not be public! class Point { public double x; public double y; } // Public class with exposed immutable fields - questionable public final class Time { …

22個值得收藏的android開源碼-UI篇

本文介紹了android開發人員中比較熱門的開源碼&#xff0c;這些代碼絕大多數能夠直接應用到項目中。FileBrowserView 一個強大的文件選擇控件。界面比較美麗&#xff0c;使用也非常easy。 特點&#xff1a;能夠自己定義UI&#xff1b;支持復制、剪切、刪除、移動文件&#xff1…

現代制造工程02:第一部分——刀具(含2個易考點)

一、金屬切削原理 可以看出哪些性能參數是同向性得&#xff0c;并且知道性能參數與三要素有什么關系 易考點&#xff1a;三個變形區 易考點&#xff1a;磨損種類以及磨損階段、磨頓標準

Fortran向C傳遞NULL值

在很多C或C的頭文件定義中&#xff0c;NULL被指定定義為0&#xff0c;這里不再具體展開 gfortran的手冊關于iso c binding的章節&#xff0c;定義NULL如下 Moreover, the following two named constants are defined: NameType C_NULL_PTRC_PTRC_NULL_FUNPTRC_FUNPTRBoth are e…

視覺slam重點知識筆記

1、除了基本矩陣和本質矩陣&#xff0c;我們還有一種稱為單應矩陣&#xff08;Homography&#xff09;H 的東西&#xff0c;它 描述了兩個平面之間的映射關系。若場景中的特征點都落在同一平面上&#xff08;比如墻&#xff0c;地面等&#xff09;&#xff0c;則可以通過單應性…

iOS開發之share第三方登錄以及分享

&#xff08;1&#xff09;官方下載ShareSDK iOS 2.8.8&#xff0c;地址&#xff1a;http://sharesdk.cn/ &#xff08;2&#xff09;根據實際情況&#xff0c;引入相關的庫&#xff0c;參考官方文檔。 &#xff08;3&#xff09;在項目的AppDelegate中一般情況下有三個操作&am…

Linux磁盤的劃分

磁盤的組成&#xff1a; 磁道&#xff1a;track 扇區&#xff1a;sector (512字節) 磁頭&#xff1a;head 柱面&#xff1a;cylinder MBR/msdos 分區模式 1--4個主分區&#xff0c;或者0--3個主分區加1個擴展分區&#xff08;n個邏輯分區&#xff09; 最大支持容量為2.2TB的磁…

opencv的pnp()算法接口是相對于3D點,輸出的是相機與3D點之間的R和T

1、情況一&#xff1a; 兩幀圖像 -》 提取特征-》特征匹配-》通過2d-2d計算 F基礎矩陣、E 本質矩陣 、H 單一性矩陣 -》解析出 相機自身的運動R和T -》再通過三角化&#xff0c;將2d點轉為相機的3d點&#xff08;每個空間點在兩個相機坐標系下的投影3D坐標與像素2D坐標&#…

有限元課堂筆記03:鋼架(Frame)

1.平面鋼架(Frame)&#xff1a;是桁架(Truss)和梁(Beam)的合成&#xff0c;兩節點六自由度 2.空間鋼架&#xff1a;兩節點12自由度 相對于平面鋼架來說每一個節點增加了z軸線性變形、繞x軸扭矩&#xff0c;繞y軸扭矩 剛度矩陣

關于系統性能檢測的一些使用

1.安裝sysstat&#xff1a;yum install sysstat---------- iostat -x 1 10 如果 %util 接近 100%&#xff0c;說明產生的I/O請求太多&#xff0c;I/O系統已經滿負荷&#xff0c;該磁盤可能存在瓶頸。 idle小于70% IO壓力就較大了,一般讀取速度有較多的wait. 2.如果想對硬盤…

Python tab 補全

1. 先準備一個tab.py的腳本 shell> cat tab.py 12345678910111213141516171819#!/usr/bin/python# python tab fileimport sys import readline import rlcompleter import atexit import os # tab completionreadline.parse_and_bind(tab: complete) # history filehistfil…

Docker新手入門:基本用法

Docker新手入門&#xff1a;基本用法 1.Docker簡介 1.1 第一本Docker書 工作中不斷碰到Docker&#xff0c;今天終于算是正式開始學習了。在挑選系統學習Docker以及虛擬化技術的書籍時還碰到了不少麻煩&#xff0c;主要就是沒有特別經典的書&#xff01;Docker的《第一版Docker書…

有限元筆記04:二維實體單元

1.二維實體即平面問題 創建單元的步驟&#xff1a; 型函數&#xff08;插值函數&#xff09;>>>應變矩陣>>>剛度矩陣>>>質量矩陣>>>力的分量 1&#xff09;三角形單元 2&#xff09;面坐標 3&#xff09;線性矩形單元 4)高斯積分 6)任意…

oracle中的常用函數

一、運算符算術運算符&#xff1a; - * / 可以在select 語句中使用連接運算符&#xff1a;|| select deptno|| dname from dept; 比較運算符&#xff1a;> > ! < < like between is null in邏輯運算符&#xff1a;not and or 集合運算符&#xff1a; 集合操作不適…