一、爲什麼需要內部類?
java內部類有什麼好處?爲什麼需要內部類?
首先舉一個簡單的例子,如果你想實現一個接口,但是這個接口中的一個方法和你構想的這個類中的一個方法的名稱,參數相同,你應該怎麼辦?這時候,你可以建一個內部類實現這個接口。由於內部類對外部類的所有內容都是可訪問的,所以這
樣做可以完成所有你直接實現這個接口的功能。
不過你可能要質疑,更改一下方法的不就行了嗎?
的確,以此作爲設計內部類的理由,實在沒有說服力。
真正的原因是這樣的,java中的內部類和接口加在一起,可以的解決常被C++程序員抱怨java中存在的一個問題 沒有多繼承。實際上,C++的多繼承設計起來很複雜,而java通過內部類加上接口,可以很好的實現多繼承的效果。
二、內部類的基本定義
在類的內部可以定義成員變量和方法,而且在類的內部也可以定義另一個類,如果類Outer的內部在定義一個類Inner,此時Inner就成爲內部類,而Outer則稱爲外部類。
內部類可以聲明爲public或private。當內部類聲明爲public或private,對其訪問權限於成員變量和成員方法完全相同。
代碼如下:
package com.se.innerclass;
class Outer {
private String info = "我愛你中國";
class Inner{
public void print() {
System.out.println(info);
}
}
public void fun() {
new Inner().print();
}
}
public class InnerClassDemo1 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
輸出結果:
以上的程序中可以清楚的發現,Inner類作爲Outer類的內部類存在,並且外部類的fun()方法中直接實例化內部類的對象調用方法print(),但是從代碼中可以明顯發現,內部類的存在實際上破壞了一個類的基本結構,因爲類是由屬性及方法組成的,所以這是內部類的一個缺點,那麼內部類有哪些優點呢,如果把內部類拿到外面來就能發現內部類的優點了。
如下面的代碼:
package com.se.innerclass;
class Outer {
private String info = "我愛你中國";
public void fun() {
new Inner(this).print();
}
public String getInfo(){
return info;
}
}
class Inner{
private Outer outer;
public Inner(Outer outer){
this.outer = outer;
}
public void print() {
System.out.println(outer.getInfo());
}
}
public class InnerClassDemo2 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun();
}
}
- 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
以上程序完成了內部類同樣的功能,但是但是代碼明顯比之前的更加複雜,所以內部類的唯一好處就是可以方便的訪問外部類的私有屬性。
三、使用static定義外部類
使用static可以聲明屬性或方法,而使用static也可以聲明內部類,用static聲明內部類變成了外部類,但是用static聲明的內部類不能訪問非static的外部類屬性。
package com.se.innerclass;
class Outer{
private static String info = "我愛你中國";
static class Inner{
public void print() {
System.out.println(info);
}
}
}
public class InnerClassDemo3{
public static void main(String[] args) {
new Outer.Inner().print();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
以上程序將info屬性定義成了static類型,這樣程序中就可以通過static聲明的內部類直接訪問此static屬性,當然,如果此時info屬性不是static類型,則編譯時將出現以下錯誤:
’
四、在外部類訪問內部類
一個內部類除了可以通過外部類訪問,也可以直接在其他類當中調用,調用的基本格式爲:
外部類.內部類 內部類對象 = 外部類實例.new 內部類()
以上的操作格式中,首先要找到外部類的實例化對象之後纔可以通過外部類的實例化對象去實例化內部類對象。
這裏我們可以觀察到編譯之後的內部類的.class文件。
內部類定義之後,生成的.class文件是以Outer$Inner的形式存在的,在Java中只要文件存在$,則在程序中應將其替換爲”.”。
在外部訪問內部類代碼如下:
package com.se.innerclass;
class Outer{
private String info = "我愛你中國";
class Inner{
public void print() {
System.out.println(info);
}
}
}
public class InnerClassDemo4 {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.print();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
五、在方法中定義內部類
也可以在方法類定義一個內部類,但是在方法中定義的內部類不能直接訪問方法中的參數,如果方法中的參數要想被內部類所訪問,則參數前必須加上final關鍵字。
在方法中定義內部類:
package com.se.innerclass;
class Outer{
private String info = "我愛你中國";
public void fun(final String temp){
class Inner{
public void print(){
System.out.println(info);
System.out.println(temp);
}
}
new Inner().print();
}
}
public class InnerClassDemo5 {
public static void main(String[] args) {
Outer outer = new Outer();
outer.fun("123");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
六、匿名內部類
在java中處理內部類之外,還有一種匿名內部類。匿名內部類就是指沒有一個具體名稱的類,此概念是在接口和抽象類的應用上發展起來的,那麼匿名內部類有哪些作用呢?
一個簡單的操作:
package com.se.innerclass;
/**
* 普通實現
* @author wzy
*
*/
interface A {
public void printInfo();
}
class B implements A{
@Override
public void printInfo() {
System.out.println("Hello world!!!");
}
}
class X{
public void fun1(){
this.fun2(new B());
}
public void fun2(A a){
a.printInfo();
}
}
public class NoInnerClassDemo6 {
public static void main(String[] args) {
new X().fun1();
}
}
- 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
通過以上的方法可以實現相應的功能,但是現在如果接口實現類只使用一次,那麼還有必要單獨定義一個子類B嗎?很顯然是沒有必要的,所以此時就可以使用匿名內部類完成,代碼修改如下:
package com.se.innerclass;
interface A{
public void printInfo();
}
class X{
public void fun1() {
this.fun2(new A(){
@Override
public void printInfo() {
System.out.println("hello world");
}});
}
public void fun2(A a) {
a.printInfo();
}
}
public class NoInnerClassDemo7 {
public static void main(String[] args) {
new X().fun1();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
七、內部類的擴展
在接口內部可以添加抽象類,在抽象類內部可以添加接口,由於使用較少,不做過多介紹。