Java內部類的四種分類以及作用
阿新 • • 發佈:2020-03-22
# 內部類內容解析
### 內部類的區分
內部類分別有成員內部類、區域性內部類、匿名內部類、靜態內部類,接下來將分別介紹。
### 成員內部類
- 就是位於外部類成員位置的類。與外部類的屬性、方法並列。
- 成員內部類作為外部類的成員,可以訪問外部類的私有成員或屬性。(即使將外部類宣告為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();
}
}
```
2. 作用
資料安全。如果我們的內部類不想輕易被任何人訪問,可以選擇使用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("我是靜態內部類");
}
}
}
```
2. 作用
提供除錯作用。我將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");
}
};
```
上述程式碼①和②的作用是相同的。由此也可以解釋一下匿名內部類的作用。
2. 作用
我們在開發的時候,會看到抽象類,或者介面作為引數。而這個時候,實際需要的是一個子類物件。如果該方法僅僅呼叫一次,我們就可以使用匿名內部類的格式簡化。
# 為什麼使用內部類
### 一、封裝性
作為一個類的編寫者,我們很顯然需要對這個類的使用訪問者的訪問許可權做出一定的限制,我們需要將一些我們不願意讓別人看到的操作隱藏起來,如果我們的內部類不想輕易被任何人訪問,可以選擇使用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 class Demo1 {
public String name() {
return "BWH_Steven";
}
}
public class Demo2 {
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中,通常就是編寫一個介面,然後你來實現這個介面,然後把這個介面的一個物件作以引數的形式傳到另一個程式方法中, 然後通過介面呼叫你的方法,匿名內部類就可以很好的展現了這一種回撥功能。
```
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("具體實現介面")
}
}
}
}
```
### 四、 解決繼承及實現接口出現同名方法的問題
編寫一個介面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方法
```