Java內部類的四種分類以及做用

內部類內容解析

內部類的區分

內部類分別有成員內部類、局部內部類、匿名內部類、靜態內部類,接下來將分別介紹。java

成員內部類

  • 就是位於外部類成員位置的類。與外部類的屬性、方法並列。
  • 成員內部類做爲外部類的成員,能夠訪問外部類的私有成員或屬性。(即便將外部類聲明爲private,可是對於處於其內部的內部類仍是可見的。)
  • 用成員內部類定義在外部類中不可訪問的屬性。這樣就在外部類中實現了比外部類的private還要小的訪問權限。
    注意:內部類是一個編譯時的概念,一旦編譯成功,就會成爲徹底不一樣的兩類。對於一個名爲outer的外部類和其內部定義的名爲inner的內部類。編譯完成後出現outer.class和outer$inner.class兩類。
  1. 代碼例子
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();
	}
}
  1. 做用
    數據安全。若是咱們的內部類不想輕易被任何人訪問,能夠選擇使用private修飾內部類,這樣咱們就沒法經過建立對象的途徑來訪問,想要訪問只須要在外部類中定義一個public修飾的方法,間接調用。這樣作的好處就是,咱們能夠在這個public方法中增長一些判斷語句,起到數據安全的做用。

局部內部類

  • 定義在一個方法或者一個做用域裏面的類。
  • 局部內部類中不可定義靜態變量,能夠訪問外部類的局部變量(即方法內的變量),可是變量必須是final的。
  1. 代碼例子
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{  //專門用來給局部內部類作向上轉型的父接口的操做
	
}

局部內部類只能在所在的方法體做用域內進行實例化,而若是要在所在方法體返回該類,就要經過接口向上轉型的操做。(如同上處代碼)
2. 做用
在某些狀況下,某些業務邏輯須要臨時處理,這些業務邏輯只在這裏使用又能夠封裝成一個類的話,而又不必從新建個文件,因此能夠這寫一個局部內部類來處理。而後,在個人記憶中,java代理模式中有用到局部內部類,在方法中直接實現接口,返回代理對象,簡單而又方便。安全

靜態內部類

靜態字段的內部類,和靜態方法並列。學習

  1. 代碼例子
public class Demo3 {
	static int x=100; 
	static class innerclass3 {
		void action() {
			x=1;  //x必須是靜態字段
		}
		public static void main(String[] args) {
			System.out.println("我是靜態內部類");
		}
	}
}
  1. 做用
    提供調試做用。我將main方法寫在靜態內部類中,生成.class文件後,調試代碼在靜態內部類當中,當我刪除靜態內部類後,其餘人仍然可使用個人外部類。

匿名內部類

  • 一個沒有名字的類,是內部類的簡化寫法。
  • 本質:實際上是繼承該類或者實現接口的子類匿名對象。
  1. 代碼例子
//代碼示例一
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");
      }
  };

上述代碼①和②的做用是相同的。由此也能夠解釋一下匿名內部類的做用。測試

  1. 做用
    ​咱們在開發的時候,會看到抽象類,或者接口做爲參數。而這個時候,實際須要的是一個子類對象。若是該方法僅僅調用一次,咱們就可使用匿名內部類的格式簡化。

爲何使用內部類

1、封裝性

做爲一個類的編寫者,咱們很顯然須要對這個類的使用訪問者的訪問權限作出必定的限制,咱們須要將一些咱們不肯意讓別人看到的操做隱藏起來,若是咱們的內部類不想輕易被任何人訪問,能夠選擇使用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();
      }
      
  }

2、實現多繼承

咱們以前的學習知道,java是不能夠實現多繼承的,一次只能繼承一個類,咱們學習接口的時候,有提到能夠用接口來實現多繼承的效果,即一個接口有多個實現,可是這裏也是有一點弊端的,那就是,一旦實現一個接口就必須實現裏面的全部方法,有時候就會出現一些累贅,可是使用內部類能夠很好的解決這些問題。調試

public class Demo1 {
      public String name() {
          return "BWH_Steven";
      }
  }
  
  public class Demo2 {
      public String email() {
          return "xxx.@163.com";
      }
  }
  
  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中就間接的實現了多繼承。code

3、用匿名內部類實現回調功能

咱們用通俗講解就是說在Java中,一般就是編寫一個接口,而後你來實現這個接口,而後把這個接口的一個對象做以參數的形式傳到另外一個程序方法中, 而後經過接口調用你的方法,匿名內部類就能夠很好的展示了這一種回調功能。對象

public interface Demo {
      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("具體實現接口")
              }
          }
      }
  }

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

編寫一個接口Demo繼承

public interface Demo {
      void test();   
  }

編寫一個類 MyDemo接口

public class 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方法
相關文章
相關標籤/搜索