讲一道java基础--什么是内部类?

内部类

定义
定义在另一个类内部的类

创建内部类

内部类是在一个类的内部嵌套定义的类,他可以是其他类的成员,也可以在一个语句块的内部定义,还可以是在表达式内部的匿名定义

public class InnerClass {
    //内部类1
    class Contents{
        private int i = 11;
        public int value(){
            return i;
        }
    }
    //内部类2
    class Destination{
        private String label;

        public Destination(String label) {
            this.label = label;
        }

        String readLabel(){
            return label;
        }
       
    }
    
     /*外部类中创建返回内部类的方法*/
    public Destination to(String s){
        return new Destination(s);
    }
    
     /*在内部类中使用定义的内部类*/
    public void ship(String dest){
        Contents contents = new Contents();
        Destination d = new Destination(dest);
        System.out.println(d.readLabel());
        System.out.println(contents.value());
    }

    public static void main(String[] args) {
        InnerClass innerClass = new InnerClass();
        innerClass.ship("HAHAHAH");
        
        InnerClass.Destination destination = innerClass.to("啦啦啦");
    }
}

内部类的获取方法
外部类中定义一个方法来获取内部类

        public Destination to(String s){
            return new Destination(s);
        }

外部使用时,由于内部类是比较特殊的类它的命名空间与当前类所在的包相同,同时,当前外部类也需要做为他的父空间,外部类名.内部类名

InnerClass.Destination destination = innerClass.to("啦啦啦");

内部类的使用

内部类可以直接引用外迁类中的任何成员
内部类的可视范围是他的直接外嵌类,也就是说内部类可以直接引用外迁类中的任何成员.因为内部类与外部类的

实例相关,所以内部类拥有两个指针,一个指向内部类的实例本身,一个指向外部类的实例.

interface Selector {
  boolean end();
  Object current();
  void next();
}	

public class Sequence {
  private Object[] items;
  private int next = 0;
  public Sequence(int size) { items = new Object[size]; }
  public void add(Object x) {
    if(next < items.length)
      items[next++] = x;
  }
    //内部类调用外部类变量
  private class SequenceSelector implements Selector {
    private int i = 0;
    public boolean end() { return i == items.length; }
    public Object current() { return items[i]; }
    public void next() { if(i < items.length) i++; }
  }
  public Selector selector() {
    return new SequenceSelector();
  }	
  public static void main(String[] args) {
    Sequence sequence = new Sequence(10);
    for(int i = 0; i < 10; i++)
      sequence.add(Integer.toString(i));
    Selector selector = sequence.selector();
    while(!selector.end()) {
      System.out.print(selector.current() + " ");
      selector.next();
    }
  }
} /* Output:
0 1 2 3 4 5 6 7 8 9

如上内部类为私有的,只有内部才能使用private修饰符,表示该类只能为当前类使用.

使用.this获取外部类的引用

public class DotThis {
    void f() {
        System.out.println("DotThis.f()");
    }

    public class Inner {
        public DotThis outer() {
            return DotThis.this;
            // A plain "this" would be Inner's "this"
        }
    }

    public Inner inner() {
        return new Inner();
    }

    public static void main(String[] args) {
        DotThis dt = new DotThis();
        Inner dti = dt.inner();
        dti.outer().f();
    }
} /* Output:
DotThis.f()
*///:~

使用外部类对象.new获取内部类的实例

要在类的外部构造一个内部类的对象,必须先创建一个外部类的实例,然后使用new创建内部类的实例或者通过调用外部类的方法获取内部类,不可直接 new 外部类.内部类()

public class DotNew {
  public class Inner {}
  public static void main(String[] args) {
    DotNew dn = new DotNew();
    Inner dni = dn.new Inner();
  }
} ///:~

在其他类中,对于添加private修饰符的内部类只能使用方法获取实例

匿名内部类

匿名内部类有多种形式,其中最常见的一种形式莫过于在方法参数中新建一个接口对象 / 类对象,并且实现这个接口声明 / 类中原有的方法了:

语法

创建一个匿名类的对象,通过默认构造器创建

new object(){
    ......
}

//匿名内部类是为了创建一个继承或者实现某一个类的具体实现

public class Parcel7 {
  public Contents contents() {//创建一个继承或者实现contents的匿名类的实例
    return 
        new Contents() { // Insert a class definition
          private int i = 11;
          public int value() { return i; }
        }; // Semicolon required in this case
  }
  public static void main(String[] args) {
    Parcel7 p = new Parcel7();
    Contents c = p.contents();
  }
} ///:~

这种 new 类名(){}形式的代码就是定义匿名内部类的语法,他没有出现class关键字,通过new指示创建一个类,并跟随{}来定义该内部类的代码

1、直接 new 一个接口,并实现这个接口声明的方法,在这个过程其实会创建一个匿名内部类实现这个接口,并重写接口声明的方法,然后再创建一个这个匿名内部类的对象并赋值返回该接口类型的引用;
2、new 一个已经存在的类 / 抽象类,并且选择性的实现这个类中的一个或者多个非 final 的方法,这个过程会创建一个匿名内部类对象继承对应的类 / 抽象类,并且重写对应的方法。

同样的,在匿名内部类中可以使用外部类的属性,但是外部类却不能使用匿名内部类中定义的属性,因为是匿名内部类,因此在外部类中无法获取这个类的类名,也就无法得到属性信息

含参匿名内部类

由于匿名内部类没有名字,所以不能创建匿名内部类,但随着实例的初始化,在父类中能创建一个构造器为匿名内部类.

匿名构造函数不能修改外部传入的值.

一个调用基构造函数

public class Parcel8 {
  public Wrapping wrapping(int x) {
    // Base constructor call:
    return new Wrapping(x) { // Pass constructor argument.
      public int value() {
        return super.value() * 47;
      }
    }; // Semicolon required注意分号的使用
  }
  public static void main(String[] args) {
    Parcel8 p = new Parcel8();
    Wrapping w = p.wrapping(10);
  }
} ///:~

在内部类中 想要使用一个定义在外部的object

public class Parcel9 {
  // Argument must be final to use inside
  // anonymous inner class:
  public Destination destination(final String dest) {
    return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel9 p = new Parcel9();
    Destination d = p.destination("Tasmania");
  }
} ///:~

你定义的匿名内部类想要使用外部类的域,那么需要传递参数时将参数加上final修饰符(貌似现在不需要了?)

abstract class Base {//抽象类
  public Base(int i) {
    print("Base constructor, i = " + i);
  }
  public abstract void f();
}	

public class AnonymousConstructor {
  public static Base getBase(int i) {
    return new Base(i) {
      { print("Inside instance initializer"); }
      public void f() {
        print("In anonymous f()");
      }
    };
  }
  public static void main(String[] args) {
    Base base = getBase(47);
    base.f();
  }
} /* Output:
Base constructor, i = 47
Inside instance initializer
In anonymous f()
*///:~

匿名内部类是有许多限制的,仅仅能扩展一个类或者实现一个接口,二者不能同时存在,并且实现接口时仅能实现一个

静态内部类

我们知道,一个类的静态成员独立于这个类的任何一个对象存在,只要在具有访问权限的地方,我们就可以通过 类名.静态成员名 的形式来访问这个静态成员,同样的,静态内部类也是作为一个外部类的静态成员而存在,创建一个类的静态内部类对象不需要依赖其外部类对象。例:

public class InnerClassTest {
	public int field1 = 1;
    
	public InnerClassTest() {
		System.out.println("创建 " + this.getClass().getSimpleName() + " 对象");
        // 创建静态内部类对象
        StaticClass innerObj = new StaticClass();
        System.out.println("其内部类的 field1 字段的值为: " + innerObj.field1);
        System.out.println("其内部类的 field2 字段的值为: " + innerObj.field2);
        System.out.println("其内部类的 field3 字段的值为: " + innerObj.field3);
        System.out.println("其内部类的 field4 字段的值为: " + innerObj.field4);
    }
	
    static class StaticClass {

        public int field1 = 1;
        protected int field2 = 2;
        int field3 = 3;
        private int field4 = 4;
        // 静态内部类中可以定义 static 属性
        static int field5 = 5;

        public StaticClass() {
            System.out.println("创建 " + StaticClass.class.getSimpleName() + " 对象");
//            System.out.println("其外部类的 field1 字段的值为: " + field1); // 编译错误!!
        }
    }

    public static void main(String[] args) {
	    // 无需依赖外部类对象,直接创建内部类对象
//        InnerClassTest.StaticClass staticClassObj = new InnerClassTest.StaticClass();
		InnerClassTest outerObj = new InnerClassTest();
    }
}


可以看到,静态内部类就像外部类的一个静态成员一样,创建其对象无需依赖外部类对象(访问一个类的静态成员也无需依赖这个类的对象,因为它是独立于所有类的对象的)。但是于此同时,静态内部类中也无法访问外部类的非静态成员,因为外部类的非静态成员是属于每一个外部类对象的,而本身静态内部类就是独立外部类对象存在的,所以静态内部类不能访问外部类的非静态成员,而外部类依然可以访问静态内部类对象的所有访问权限的成员,这一点和普通内部类无异。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值