Java编程思想——细话Java内部类(上)

  • 置于其他类内部的类就是内部类
  • 内部类了解外部类并能与外部类进行通信
  • 内部类和组合并不是一个概念

一、内部类的创建

内部类小例子:

class A{
  class B{  //内部类的方法体与普通类相同
     private int num=0;
     B(){}
     void f(){}
  }
  private String name="Hello";
  public void setName(String name){
    this.name=name;
  }
}

外部类调用内部类:

class A{
   class B{  //内部类(内部构造和普通类一样)
      private String name;
      B(String name){
	this.name=name;
      }
     public String getName(){
        return name;
     }
   }
   public B getB(String name){
     return new B(name);
   }
}
public class C{
  public static void main(String[] args)
  { 
     A a=new A();
     A.B b=a.getB("Hello Java!");
     System.out.print(b.getName());
  }
}

将上述例子反编译可以看到经过编译器编译后的代码样式:


可以看出内部类同样会被编译到一个单独的.class文件中,但在其所在的类的编译文件中同样含有内部类。

二、与外部类的通信

当生成一个内部类的对象时,此对象与构造它的外围对象之间就有一中联系,所以它能访问外围对象的所有成员(包括private私有成员),而不需要任何特殊条件。(C++中的内部类只是单纯的名字隐藏机制而不能和外围对象进行联系,也没有隐含的访问权)。

一个小例子:

public class Test{
   private static Object[] obj;
   private static int i=0;
   private void add(int i){
	  obj[this.i]=i;
	  this.i++;
   }
   class RunTest{
     public void insertValues(){
	obj=new Object[10];//使用外围类的私有成员
	for(int ind=0;ind<10;ind++){
	    add(ind);//使用外围类的私有方法
	} 
      }
   } 
   public RunTest getRunTest(){
	   return new RunTest();
   }
    public static void main(String[] args){
	   Test test=new Test();
	   Test.RunTest t=test.getRunTest();
	   t.insertValues();
       for(int i=0;i<obj.length;i++){
          System.out.print(obj[i]+" ");
       }
    }
}

反编译后的内部类如下:

class Test$RunTest
{
  Test$RunTest(Test paramTest) {}
  public void insertValues()
  {
    Test.access$002(new Object[10]);
    for (int i = 0; i < 10; i++) {
      Test.access$100(this.this$0, i);
    }
  }
}
可以看到当内部类访问外围类中成员以及私有方法时会自动获取外围类的引用并通过引用访问成员和方法。

**如何用其他方式获取内部类和外围类的引用对象?**

  • 内部类获取外围类对象——通过".this"
  • 外围类获取内部类对象——通过“.new”
public class A{
   class B{
      public A getA(){
         //获取A的引用
         return A.this;
      }
   }
    public B getB(){
       //通过方法获取B的对象
       return new B();
    }
   public static void main(String[] args){
      //通过构造器获取A的对象引用
      A a=new A();
      //通关方法调用获取内部类对象
      A.B b=a.getB(); 
      //通过“.new”获取内部类对象
      A.B b2=a.new B();
      //通过调用内部类方法获取A的引用
      A a2=b2.getA();
   }
}

*我们来看看这些创建方法的经过编译后是什么样的:

//".this"——this.this$0 
public A getA()
{
  return this.this$0;
}     
//".new"——
{
  tmp18_17 = localA1;
  tmp18_17.getClass();
  A.B localB2 = new A.B(tmp18_17);
  localB2.g();
}
”this$0“——特指该内部类所在的外部类的引用

通过这些可知:

      要想直接创建内部类的对象,不能脱离外部类,而必须使用外部类的对象创建内部类对象,这是因为内部类对象会暗暗地连接到创建它的外部类对象上。但是有一种特殊情况就是静态内部类,它是不需要对外部类对象的引用的,直接通过new创建对象。

三、各个域中的内部类

     以上内部类都是定义在外部类中与方法和成员变量地位相同,其实内部类可以放在外部类的任意作用域中,具体可见如下例子:

public class A{
  //在与方法平行的位置定义内部类
  class class B{}
  public void show(){
     //在方法内部定义内部类
     class C{
        System.out.print("Hello");
     }
  }
  public void isShow(){
     if(true){
        //在判断语句的域中创建内部类
        class D{}
     }
  }
}

注意:

      无论我们将内部类定义在哪个域中,其都是与所有类同时被编译器编译的,所以条件if下的类D也并不是在满足条件的情况下才创建的。唯一有区别的是这些内部类只在自己所在的域内有效,其他位置均不可用。

public class A{
   public void show(){
      if(true){
          class B{
              public void isShow(){
                 System.out.print("is if class");
              }
          }
        B b=new B();
        b.isShow();
      }
        //在if域外使用B报错找不到符号B
        //B b=new B();
        //b.isShow();
   }
}

另外,对于内部类的向上转型和其他普通类是一样的。

未完待续。。。。。。


猜你喜欢

转载自blog.csdn.net/goodli199309/article/details/79969297
今日推荐