您的位置:首页 > 编程语言 > Java开发

Java内部类总结

2017-03-18 13:01 211 查看
关于Java中的内部类(Inner Classes),咱们可得好好说道说道。

概述

  面向对象程序设计(OOP)中,可以在一个类的内部定义一个新类,即为我们平时口中说的嵌套类。Java是一种面向对象程序设计语言,自然也包含了这样的特性。

  在Java中,嵌套类又分为以下两种:

静态嵌套类(static nested classes

非静态嵌套类(non-static nested classes),亦称为内部类(Inner classes

  嵌套类可以声明在外部类中的任何位置,一般情况下Java中类的修饰符必须是public或者是默认的package private,但是无论是静态还是非静态内部类,其修饰符可以为 public,private,protected,package private 中的任意一种,这也体现出了内部类与普通外部类的不同。

class OuterClass {
//...
static class StaticNestedClass {
//...
}
class InnerClass {
//...
}
}


静态嵌套类(静态内部类)

  静态嵌套类(static),与非静态嵌套类(non-static)相比,缺少了对外部类的引用,由修饰符(static)可以看出,静态嵌套类不属于外部类,缺少了对外部类的引用(这就实现了将一个类隐藏在另一个类的内部,却消除了对外部类的引用),也就有了如下性质:

可以直接通过外部类类名.静态内部类类名的方式直接访问,这一点上与static修饰的类变量性质相同。

OuterClass.StaticNestedClass


不需要通过外部类的对象创建静态内部类对象。可以直接使用new 外部类类名.静态内部类类构造器的方式直接创建。:

OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();


与static修饰的类方法相似,静态内部类不可以访问外部类的非静态成员(non-static member)。而外部类若想访问静态内部类的非静态成员,只需实例化内部类即可,访问静态成员,则只需

StaticNestedClass.StaticMember


非静态嵌套类(内部类)

局部内部类

public class OuterClass {
//...
public void method() {
class LocalClass1 { /*...*/ }//定义在方法体中
if (true) {
class LocalClass2 { /*...*/ }//定义在if嵌套中
}
for(;;;) {
class LocalClass3 { /*...*/ }//定义在循环体中
}
}


  局部内部类(Local Classes),Java官方文档中将其与给出的解释是:

  “You can define a local class inside any block.”

  即,局部内部类可以定义在任何的语句块中,比如说方法体(method),循环体(loop),甚至是分支执行的if子句中。

  但由于局部内部类是定义在块( Block)内的类,不是外部类的一部分,并且只在当前的块内有效(可以访问当前块内的final常量,以及外部类的所有成员),所以其不能有任何的访问控制符。

  说到这里,可能会有些疑问,不是外部类的一部分,怎么还能访问外部类的内容呢?

  虽然局部内部类不是外部类的一部分,但是他还是外部类的内容,想想Java中的方法,也能直接访问外部类的所有成员就知道了。

  为什么只能访问块内的final变量(在SE 8中可以访问effectively final变量,一种无final修饰的,但在初始化之后值不再更改的类final变量)?

  解释起来很麻烦,简言之就是作用域的问题,因为局部变量的生命周期与局部内部类的生命周期不一致导致编译技术上无法实现或是实现代价极高。而之所以能够访问final变量,则是因为Java采用了一种copy local variable的方式实现,篇幅原因,这里不做过多的解释,如有兴趣,可以参考http://blog.csdn.net/salahg/article/details/7529091

只能在局部内部类的作用域范围内创建局部内部类的对象,超出作用域创建其对象视为无效。

不可以在局部内部类中声明静态成员,这一点上与一般内部类的性质相似。

匿名内部类

  匿名内部类(Anonymous Classes),官方文档中简单说明:

  “an inner class within the body of a method without naming the class. “

  并且表示匿名内部类可以使代码更加简洁(现在有了lambda表达式之后,代码可以更加简洁)。

  匿名内部类是扩展自超类,或者是实现了某一个接口。

  这一性质决定了必须先声明一个类或者是接口,然后以下方式创建:

new SuperClass() { ... }


或者是

new InterfaceName() { ... }


匿名内部类不能有任何的构造函数,我们讲过构造函数是与类同名的函数,而匿名内部类是没有名字的内部类,所以不能匿名内部类中不能出现任何的构造函数。(但是可以通过构造块来实现初始化的操作)

匿名内部类可以直接调用超类的构造方法实现初始化,前提是超类的构造方法存在(超类无显式构造,Java自动生成缺省构造)。在内部类的实现过程中可以通过super关键字调用相应内容。

向匿名内部类中传入参数需要参数被声明为final,这一点和局部内部类相似。

public class OuterClass {
class InnerClass {
private int in = 3;
public InnerClass(int i) { ... }
public int getIn() {  return in;  }
}
public InnerClass newInstance(int x) {
return new InnerClass(int x) {//这里调用超类的构造方法
public int getIn
4000
() {//这里使用super关键字调用超类的getIn()方法
return super.getIn() * 10;
}
}
}


内部类与外部类之间的关系

Java生成的class文件中,外部类文件名为“OuterClassName.class”,内部类则为“OuterClassName$InnerClassName.class”,匿名内部类稍有不同:“OuterClassName$InnerClassName#.class”,其中符号”#”为匿名类的序号。

外部类成员对内部类透明,上文已经提及,这是由于非静态内部类(non-static nested class)隐式的含有一个指向外部类的引用。

.this与.new可以的到对外部类的一个引用。

内部类可以通过外部类的方法生成,并且可以向上转型生成超类实现的接口对象

除了上述所说,内部类还具有普通类的被继承的性质(但是比较麻烦),甚至可以像方法一样被重载(虽然感觉并没有用处)。

public class OuterClass {
private int i = 3;
public class InnerClass {
private int i = 1;
public void print() {
System.out.println("i = " + i);
System.out.println("this.i = " + this.i);
System.out.println("OuterClass.this.i = " + OuterClass.this.i);
}
}
public InnerClass newInstance() {
return new InnerClass() {};
}

public static void main(String[] args) {
new OuterClass().newInstance().print();
}
}


总结

  Java将嵌套类划分成静态与非静态嵌套类两种类型。

  嵌套类的存在提高了类的封装性(encapsulation),以及代码的可读性(readable)。

  之所以需要使用内部类,原因如下:

内部类可以对同一个包的其他类隐藏起来。

无视内部类定义所在的作用域数据访问限制,即,可以访问该类定义所在的作用域中的数据,包括私有数据。

匿名内部类简化了代码,Anonymous classes enable you to make your code more concise.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java