天天看點

Java内部類的四種分類以及作用

Java内部類的四種分類以及作用

内部類内容解析

内部類的區分

内部類分别有成員内部類、局部内部類、匿名内部類、靜态内部類,接下來将分别介紹。

成員内部類

就是位于外部類成員位置的類。與外部類的屬性、方法并列。

成員内部類作為外部類的成員,可以通路外部類的私有成員或屬性。(即使将外部類聲明為private,但是對于處于其内部的内部類還是可見的。)

用成員内部類定義在外部類中不可通路的屬性。這樣就在外部類中實作了比外部類的private還要小的通路權限。

注意:内部類是一個編譯時的概念,一旦編譯成功,就會成為完全不同的兩類。對于一個名為outer的外部類和其内部定義的名為inner的内部類。編譯完成後出現outer.class和outer$inner.class兩類。

代碼例子

public class Demo1 {

innerclass in=new innerclass(); //在成員内部類所在的外類中執行個體化成員内部類
public void outf() {
    in.inf();  //因為in是成員内部類的執行個體化,是以才可以調用
}
class innerclass{//成員内部類
    int y=0;
    public innerclass() {//成員内部類的構造方法
        
    }
    public void inf() {
        System.out.println("内部類方法y="+y);
    }
}
public static void main(String[] args) {
    Demo1 iDemo1=new Demo1();
    iDemo1.outf();
    
    Demo1.innerclass j= iDemo1.new innerclass();  //非外部類位置成員内部類執行個體化的方法(即首先要執行個體化一個外部類)
    Demo1.innerclass k=new Demo1().new innerclass(); //執行個體化外部類和構造内部類一起寫
    j.inf();
}           

}

作用

資料安全。如果我們的内部類不想輕易被任何人通路,可以選擇使用private修飾内部類,這樣我們就無法通過建立對象的途徑來通路,想要通路隻需要在外部類中定義一個public修飾的方法,間接調用。這樣做的好處就是,我們可以在這個public方法中增加一些判斷語句,起到資料安全的作用。

局部内部類

定義在一個方法或者一個作用域裡面的類。

局部内部類中不可定義靜态變量,可以通路外部類的局部變量(即方法内的變量),但是變量必須是final的。

public class Demo2 {

public outinterface action(String x) {//要把這個類傳回出去,就需要通過接口,因為内部類在外部作用域中不存在
    class innerclass2 implements outinterface{
        public innerclass2(String s) {
            s = x;
            System.out.println(s);
        }
    }
    return new innerclass2("do");    
}
public static void main(String[] args) {
    Demo2 demo2=new Demo2();
    demo2.action("局部内部類");
}           

interface outinterface{ //專門用來給局部内部類做向上轉型的父接口的操作

局部内部類隻能在所在的方法體作用域内進行執行個體化,而如果要在所在方法體傳回該類,就要通過接口向上轉型的操作。(如同上處代碼)

  1. 在某些情況下,某些業務邏輯需要臨時處理,這些業務邏輯隻在這裡使用又可以封裝成一個類的話,而又沒必要重建立個檔案,是以可以這寫一個局部内部類來處理。然後,在我的記憶中,java代理模式中有用到局部内部類,在方法中直接實作接口,傳回代理對象,簡單而又友善。

靜态内部類

靜态字段的内部類,和靜态方法并列。

public class Demo3 {

static int x=100; 
static class innerclass3 {
    void action() {
        x=1;  //x必須是靜态字段
    }
    public static void main(String[] args) {
        System.out.println("我是靜态内部類");
    }
}           

提供調試作用。我将main方法寫在靜态内部類中,生成.class檔案後,調試代碼在靜态内部類當中,當我删除靜态内部類後,其他人仍然可以使用我的外部類。

匿名内部類

一個沒有名字的類,是内部類的簡化寫法。

本質:其實是繼承該類或者實作接口的子類匿名對象。

//代碼示例一

public class Demo4 {

public Outinterface2 action() {
    //return new innerclass2(); ①
    return new Outinterface2() {   //②
        private int i = 0;
        public int getvalue() {
            return i;
        }
    };
}           

interface Outinterface2 {

class innerclass2 implements Outinterface2{//①

private int i = 0;
public int getvalue() {
    return i;
}           

//代碼示例二

interface Inner {

public abstract void show();           

class Outer {

public void method(){
      new Inner() {
          public void show() {
              System.out.println("HelloWorld");
          }
      }.show();
  }           

class Test {

public static void main(String[] args)  {
      Outer o = new Outer();
      o.method();
  }           

//如果匿名内部類中有多個方法又該如何調用呢?

Inter i = new Inner() { //多态,因為new Inner(){}代表的是接口的子類對象

public void show() {
  System.out.println("HelloWorld");
  }           

};

上述代碼①和②的作用是相同的。由此也可以解釋一下匿名内部類的作用。

​我們在開發的時候,會看到抽象類,或者接口作為參數。而這個時候,實際需要的是一個子類對象。如果該方法僅僅調用一次,我們就可以使用匿名内部類的格式簡化。

為什麼使用内部類(本部分為轉載,文章底部見作者及原連結)

一、封裝性

作為一個類的編寫者,我們很顯然需要對這個類的使用通路者的通路權限做出一定的限制,我們需要将一些我們不願意讓别人看到的操作隐藏起來,如果我們的内部類不想輕易被任何人通路,可以選擇使用private修飾内部類,這樣我們就無法通過建立對象的方法來通路,想要通路隻需要在外部類中定義一個public修飾的方法,間接調用。

public interface Demo {

void show();           

class Outer {

private class test implements Demo {
      public void show() {
          System.out.println("密碼備份檔案");
      }
  }
  
  public Demo getInner() {
      return new test();
  }
             

二、實作多繼承

我們之前的學習知道,java是不可以實作多繼承的,一次隻能繼承一個類,我們學習接口的時候,有提到可以用接口來實作多繼承的效果,即一個接口有多個實作,但是這裡也是有一點弊端的,那就是,一旦實作一個接口就必須實作裡面的所有方法,有時候就會出現一些累贅,但是使用内部類可以很好的解決這些問題。

public String name() {
      return "BWH_Steven";
  }           
public String email() {
      return "[email protected]";
  }           

public class MyDemo {

private class test1 extends Demo1 {
      public String name() {
          return super.name();
      }
  }           

private class test2 extends Demo2  {
      public String email() {
          return super.email();
      }
  }           
public String name() {
      return new test1().name();
  }           
public String email() {
      return new test2().email();
  }           
public static void main(String args[]) {
      MyDemo md = new MyDemo();
      System.out.println("我的姓名:" + md.name());
      System.out.println("我的郵箱:" + md.email());
  }           

我們編寫了兩個待繼承的類Demo1和Demo2,在MyDemo類中書寫了兩個内部類,test1和test2兩者分别繼承了Demo1和Demo2類,這樣MyDemo中就間接的實作了多繼承。

三、用匿名内部類實作回調功能

我們用通俗講解就是說在Java中,通常就是編寫一個接口,然後你來實作這個接口,然後把這個接口的一個對象作以參數的形式傳到另一個程式方法中, 然後通過接口調用你的方法,匿名内部類就可以很好的展現了這一種回調功能。

void demoMethod();           

public class MyDemo{

public test(Demo demo){
      System.out.println("test method");
  }
  
  public static void main(String[] args) {
      MyDemo md = new MyDemo();
      //這裡我們使用匿名内部類的方式将接口對象作為參數傳遞到test方法中去了
      md.test(new Demo){
          public void demoMethod(){
              System.out.println("具體實作接口")
          }
      }
  }           

四、 解決繼承及實作接口出現同名方法的問題

編寫一個接口Demo

void test();              

編寫一個類 MyDemo

public void test() {
      System.out.println("父類的test方法");
  }
             

兩者的方法名字都是test,下面編寫一個測試類;

public class DemoTest extends MyDemo implements Demo {

public void test() {
  }           

這樣的話我就有點懵了,這樣如何區分這個方法是接口的還是繼承的,是以我們使用内部類解決這個問題

public class DemoTest extends MyDemo {

private class inner implements Demo {
      public void test() {
          System.out.println("接口的test方法");
      }
  }
  
  public Demo getIn() {
      return new inner();
  }
  
  
  public static void main(String[] args) {
      //調用接口而來的test()方法
      DemoTest dt = new DemoTest();
      Demo d = dt.getIn();
      d.test();
      
      //調用繼承而來的test()方法
      dt.test();
  }           

//運作結果

接口的test方法

父類的test方法

注:本文章中“為什麼使用内部類”部分為轉載,下面是原出處。

作者:BWH.Steven

連結:

https://www.zhihu.com/question/26954130/answer/708467570

來源:知乎

著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。