內部類、匿名內部類、內部介面比較
目錄
一、什麼是內部介面?
內部介面也稱為巢狀介面,即在一個介面內部定義另一個介面,Entry介面定義在Map接口裡面,如下程式碼:
public interface Map{
interface Entry{
int getKey();
}
void clear();
}
在Java標準庫中使用內部介面的一個例子就是java.util.Map和java.util.Map.Entry.
二、在說明內部介面之前先說一下什麼是內部類?
內部類顧名思義就是在一個類的內部還有一個類
Java程式碼:
class Outer{
private String name = "Hello World";
class Inner{
public void print(){
System.out.println("name="+name);
}
}
public void fun(){
new Inner().print();
}
}
public class TestInnerClass01{
public static void main(String args[]){
new Outer().fun();
}
}
內部類的生成的.class檔名為:Outer$Inner.class,從上面的結構發現內部類的缺點是“結構非常混亂”。
Java程式碼:
class Outer{
private String name = "Hello World";
class Inner{
private Outer out;
public Inner(Outer out){
this.out = out;
}
public void print(){
System.out.println("name="+this.getName());
}
}
public String getName(){
return this.name;
}
public void fun(){
new Inner(this).print();
}
}
public class TestInnerClass02{
public static void main(String[] args){
new Outer().fun();
}
}
可以看出內部類的優點是:“可以方便的訪問外部類中的私有成員”;
如果要在外部類直接使用內部類的例項化物件:
外部類.內部類 內部類物件 = 外部類例項.new 內部類例項();
Java程式碼:
class Outer{
private String name = "Hello World";
class Inner{
public void print(){
System.out.println("name="+name);
}
}
}
public class TestInnerClass03{
public static void main(String[] args){
Outer out = new Outer(); //外部類例項
Outer.Inner inner = out.new Inner();//例項化內部類物件
inner.print();
}
}
一個內部類如果使用static宣告的話,則此內部類變為外部類,可以直接通過外部類.內部類的形式訪問
Java程式碼:
class Outer{
private static String name = "Hello WOrld";
static class Inner{
public void print(){
System.out.println("name="+name);
}
}
}
public class TestInnerClass04{
public static void main(String[] args){
Outer.Inner inner = new Outer.Inner()//例項化內部類物件
inner.print();
}
}
區域性內部類(定義在方法中的內部類)“不能用public或者private宣告”,它的作用域僅限於方法內部。
區域性內部類的優勢,即對外部世界可以完全隱藏起來。除了該方法之外,沒有任何方法知道它的存在。
在方法中定義的內部類,可以直接訪問外部類中的各個成員,但是如果要訪問方法中的引數,則需要在引數上加final關鍵字宣告。
Java程式碼:
public class TestInnerClass{
public static void main(String[] args){
new Outer().fun(20);
}
}
class Outer{
private static String name = "hello world";
public void fun(final int temp){
class Inner{
public void print(){
System.out.println("temp="+temp);
System.out.println("name="+name);
}
}
new Inner().print();
}
}
三、成員內部類的繼承問題(易錯地方)
1、成員內部類的引用方式必須為 Outter.Inner.
2、構造器中必須有指向外部類物件的引用,並通過這個引用呼叫super()。
Java程式碼:
class WithInner {
class Inner{
}
}
class InheritInner extends WithInner.Inner {
// InheritInner() 是不能通過編譯的,一定要加上形參
InheritInner(WithInner wi) {
wi.super(); //必須有這句呼叫
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner obj = new InheritInner(wi);
}
}
四、再說一下什麼是匿名內部類?
簡單的說匿名內部類就是沒有名字的內部類,匿名內部類只能使用一次。
使用匿名內部類的前提條件:“必須繼承一個父類或者實現一個介面”。
Java程式碼:不使用匿名內部類來實現抽象方法
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class TestInnerClass {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
可以看到,我們用Child繼承了Person類,然後實現了Child的一個例項,將其向上轉型為Person類的引用,但是,如果此處的Child類只使用一次,那麼將其編寫為獨立的一個類豈不是很麻煩?這個時候就引入了匿名內部類。
Java程式碼:匿名內部類的基本實現
abstract class Person {
public abstract void eat();
}
public class TestInnerClass {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
可以看到,我們直接將抽象類Person中的方法在大括號中實現了,這樣便可以省略一個類的書寫並且,匿名內部類還能用於介面上。
Java程式碼:在介面上使用匿名內部類
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
最常用的情況就是在多執行緒的實現上,因為要實現多執行緒必須繼承Thread類或是繼承Runnable介面
Java程式碼:Thread類的匿名內部類實現
public class TestInnerClass {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
}
}
Java程式碼:Runnable介面的匿名內部類實現
public class TestInnerClass{
public static void main(String[] args){
Runnable r = new Runnable(){
public void run(){
for(int i=0;i<4;i++){
System.out.print(i+" ");
}
}
};
Thread t = new Thread(r);
t.start();
}
}
五、內部介面的例項
Map.java:
public interface Map{
interface Entry{
int getKey();
}
void clear();
}
MapImpl.java:
public class MapImpl implements Map{
class ImplEmtry implements Map.Entry{
public int getKey(){
return 0;
}
}
@Override
public void clear(){
//clear
}
}