关于java内部类(Inner Class) 不断更新中

来源:互联网 发布:空气净化器哪个好 知乎 编辑:程序博客网 时间:2024/05/18 12:29

java内部类(Inner Class) 

Inner Class 即嵌套类,也即C++和C#中的Nested Class。但Java 的Inner Class 与 C++和C#最大的不同之处在于,嵌套类包含一个指向其容器类的引用,可以访问容器类的成员。以下代码演示了这一点:public class Container {
String Name;
class InnerClass
{
InnerClass(){};
public void func()
{
System.out.println(Name);
}
}
public Container(String name){ Name=name;
InnerClass a=new InnerClass();
}
public static void main(String [] arg)
{
Container a=new Container(“ContainerA");
InnerClass b=a.new InnerClass(); //注意此处
b.func();
InnerClass c=(new Container(“ContainerB")).new InnerClass();
c.func();
}
}
注意其中独特的new语法,在静态函数要创建一个Inner Class,必须有一个其容器类的实例。如果直接创建
InnerClass b=new InnerClass();则会导致编译出错。而在Container的构造函数中,创建InnerClass时,自动将this作为InnerClass的引用。在Inner Class 中使用容器类的成员,不需指定实例,自动指向创建它的容器类。 这是一个很有用的语法特征,编译器替我们省了许多事。 本例的输出是: ContainerA ContainerB 还可以看到,Inner Class 可以访问容器类的任何成员,不管是public、private或protected的成员全是透明的。反之则不然,容器类只能访问Inner Class的public成员。

===================

匿名的内部类是没有名字的内部类。不能extends(继承) 其它类,但一个内部类可以作为一个接口,由另一个内部类实现。

===================

3类inner class
1、一般的inner class
class aaaa{
  class InnerClass {
    // Write Codes Here
  }
}

2、Method local Inner Class
local class 是定义在method內的class,其 scope 在该method 內

3、Anonymous Inner Class
 一种形式:return new Destination{ //inner class };
另一种形式:someMethod(new SomeClass( ) { //code } );
[注意]
(1)anonymous nested class 必须implement 某个 interface 或是 extend 某个 class,但是不使用         implements 或 extends 关键字
(2)anonymous class 內不能宣告 constructor
(3)可宣告 instance initializer 做初值設定

==================

class Out{

class Inner1{}

static class Inner2{}

Inner1 需要通过 Out 的实例构造。

Out out = new Out();
Out.Inner1 oi1 = out.new Inner1();

Inner2 可以通过 Out 的类名构造。

Out.Inner2 oi2 = new Out.Inner2();

例如上面的实例:添加静态内部类
static class Inner2{
   public void f2(){System.out.println("pppp");}
  }
main函数的调用时用Container类:Container.Inner2 i2 = new Container.Inner2();   i2.f2();

 

===============

总结:当前的外部类中,内部类的public或者private属性可以被访问
class InnerClass
 {
  private int x = 5;
  public int y = 10;
 InnerClass(){};
 public void func()
 {
 System.out.println(Name+"-x-"+x+"-y-"+y);
 }
 }
 class Inner1{
  public void f1(){
   InnerClass ic = new InnerClass();
   System.out.println(ic.y+"|||"+ic.x);
   System.out.println(Name);
   }
 }

============================

1. 嵌套类

首先必须要注意,内部类和嵌套类的区别。嵌套类拥有访问宿主类任意成员的权限。嵌套类除了访问权限外,并不会获得宿主类实例的引用,也不会随宿主类自动产生实例。

C#

class Class1
{
  private int x = 13;

  public void Test()
  {
    new Class1Sub(this).Test();
  }

  public class Class1Sub
  {
    private Class1 o;

    public Class1Sub(Class1 o)
    {
      this.o = o;
    }

    public void Test()
    {
      Console.WriteLine(o.x);
    }
  }
}

class Program
{
  static void Main()
  {
    // 1.
    new Class1().Test();

    // 2.
    Class1 o = new Class1();
    Class1.Class1Sub s = new Class1.Class1Sub(o);
    s.Test();
  }
}


Java

class Class1 {
  private int x = 13;
  
  public void test() {
    new Class1Sub(this).test();
  }
  
  public static class Class1Sub {
    private Class1 o;
    
    public Class1Sub(Class1 o){
      this.o = o;
    }
    
    public void test() {
      System.out.println(o.x);
    }
  }
}

public class program {
  public static void main(String[] args) {
    // 1.
    new Class1().test();
    
    // 2.
    Class1 o = new Class1();
    Class1.Class1Sub s = new Class1.Class1Sub(o);
    s.test();
  }
}


Java 的例子和 C# 基本类似,不过要注意的是 Java Class1.Class1Sub 被申明为 "static class"。
另外,C# 嵌套类缺省是 private 方式的,也就是说不能被外界访问。可以被赋予 private/internal/protected/internal protected/public中的任一种权限。Java 的嵌套类缺省是 friendly 方式,可以被赋予 private/protected/public/friendly中的一种。

2. 内部类

内部类和嵌套类比较相似,但没有static修饰,不能像嵌套类那样在外部创建内部类的实例对象。它虽然不会自动随宿主类生成实例,但却能自动获取宿主类的引用,从而访问宿主类的实例成员。

我们修改上面的例子,将其改成内部类,我们发现Class1Sub可以直接访问宿主实例的任意字段,并不需要使用宿主引用。这其实是Java编译器做的一些“魔法”,当在宿主实例内生成内部类时会自动将宿主引用隐性传递给内部类实例。当然,在内部类也可以使用"宿主名.this"获取宿主引用。

class Class1 {
  private int x = 13;
  
  public void test() {
    new Class1Sub().test();
  }
  
  class Class1Sub {  
    public void test() {
      System.out.println(Class1.this.toString());
      System.out.println(x);
    }
  }
}

public class program {
  public static void main(String[] args) {
    new Class1().test();
  }
}


内部类可以跨越多重嵌套,访问任意级别的嵌套类成员。

class Class1 {
  void doSomething(){};
  
  class Class1Sub {
    class class1Sub2 {
      void test() { doSomething(); }
    }
  }
}


3. 本地内部类

我们还可以在方法内部创建内部类,这种内部类被称之为“本地内部类(local inner class)”。本地内部类不能有权限修饰符,和下面的匿名内部类非常相似。如果本地内部类需要使用方法参数,则必须为该参数添加final关键字。

class Class1 {
  private int x = 13;
  
  void test() {
    class Sub {
      Sub() { System.out.println(x); }
    }
    
    new Sub();
  }
  
  void test2(final String s) {
    class Sub {
      Sub() { System.out.println(s); }
    }
    
    new Sub();    
  }
}

public class program {
  public static void main(String[] args) {
    new Class1().test();
    new Class1().test2("abc");
  }
}


3. 匿名内部类

我们可以在方法内部创建一个实现某个接口或者继承某个类的匿名类,它具备内部类的全部功能,只不过因为没有“名字”,我们不能在外面实例化它,也不能创建构造方法,而只能使用实例初始化代码段。如果匿名类需要使用外部方法参数,必须为该参数加上final关键字。

abstract class Base {
  abstract void test();
}

interface IBase {
  void test();
}

class Class1 {
  private int x = 13;
  
  public Base makeBase() {
    return new Base(){
      {
        System.out.println("new Base...");
      }
      
      public void test() {
        System.out.println(x);
      }
    };
  }
  
  public IBase makeIBase(final String s) {
    return new IBase(){
      public void test() {
        System.out.println(s);
      }
    };
  }
}

public class program {
  public static void main(String[] args) {
    new Class1().makeBase().test();
    new Class1().makeIBase("abc").test();
  }
}


一般情况下,匿名内部类和本地内部类都可以实现相同的功能。选择本地内部类的额外理由是:

1. 需要或者覆写构造方法。
2. 创建多个本地内部类实例。
3. 没有可用的基类或接口。(匿名内部类必须实现某个接口和继承自某个基类。)

匿名内部类和本地内部类还可以放在任意的代码范畴(scope)内。

interface I1 {}

class ClassX
{
  void print(final int i) {
    if (i > 0) {
      class Sub {
        Sub() { System.out.println(i); }
      }
      
      new Sub();
    }
    else {
      new I1() {
        {
          System.out.println("i <= 0");
        }
      };
    }
  }
}

public class program {
  public static void main(String[] args) {
    new ClassX().print(1);
    new ClassX().print(0);
  }
}


4. 继承内部类

在宿主类内部继承内部类,和正常情况下没什么区别。

class Class1 {
  
  private int x = 10;
  public Class1() { new Sub2(); }
  
  class Sub {
    Sub(){ System.out.println("Sub:" + x); }
  }
  
  class Sub2 extends Sub {
    Sub2(){ System.out.println("Sub2:" + x); }
  }
}


而为了在外部继承内部类,就必须:
1. 包含有宿主类引用参数的构造方法。
2. 在构造方法内部调用 super() 方法。

class Class1 {
  class Class1Sub {
  }
}

class Class1SubX extends Class1.Class1Sub {
  public Class1SubX(Class1 o) {
    o.super();
  }
}

public class program {
  public static void main(String[] args) {
    new Class1SubX(new Class1());
  }
}


虽然在外部继承内部类以后,我们可以在外部创建内部类实例,但同时也失去了隐性访问宿主类成员的权利。

5. 覆写内部类

继承含有内部类的宿主类,并不会同时继承其内部类,即便在继承类内部有相同名称的内部类,也完全是两个不同的类型。

class Class1 {
  void test() { new Sub(); }
  
  class Sub {
    Sub() { System.out.println("Class1.Sub"); }
  }
}

class Class2 extends Class1 {

  void test() { new Sub(); }
  
  class Sub {
    Sub() { System.out.println("Class2.Sub"); }
  }  
}

public class program {
  public static void main(String[] args) {
    Class1 o = new Class2();
    o.test();
  }
}


输出
Class2.Sub

由于编译器并不会因为 Class2.Sub 是 Class1.Sub 的继承类,因此并没有自动调用 Class1.Sub 构造方法。我们修改一下,使得 Class2.Sub extends Class1.Sub,OK!这回对了。

class Class1 {
  void test() { new Sub(); }
  
  class Sub {
    Sub() { System.out.println("Class1.Sub"); }
  }
}

class Class2 extends Class1 {

  void test() { new Sub(); }
  
  class Sub extends Class1.Sub {
    Sub() { System.out.println("Class2.Sub"); }
  }  
}

public class program {
  public static void main(String[] args) {
    Class1 o = new Class2();
    o.test();
  }
}


输出:
Class1.Sub
Class2.Sub

原创粉丝点击