什么是内部类
把一个类的定义在另一个类定义的内部,即叫内部类,内部类有几种类型,内部类可以访问外部的所有成员(因为内部类会保存一个外部类的引用,这是编译器帮我们做的事情)
内部类可以定义外部内中,与外部类成员变量同级,这是见得比较多的。也可以定义在方法中,你几乎可以在任意的位置中定义内部类,只是对内部类的可见性会有影响。这个后面我会举例具体说明。
内部类种类
普通内部类:
嵌套类:
匿名内部类
为什么要使用内部类
1.可重命名和隐藏性:当一个类,一般不需要被别的类(除该外部类之外)引用时,可以考虑将其定义为内部类。如果内部类有有一个名字相同的外部类也是不会影响的。
2.多继承我们知道java中是单继承,多实现的。现在如果需要一个类去继承2个抽象类或者具体类,这对与一般的类是无法做到的,但是如果借助于内部类就可以做到了,即外部类实现继承一个类,在定义一个内部类继承一个类。由于外部类可以实例化内部类。虽然不是类似与c++那种多继承,但是通过内部类,还是可以使其具有继承带来的部分特性。另外外部类可以和内部类实现同样的接口,基于多肽的特性,可以设计出非常精妙的结构。
内部类
一般的内部类定义在于字段同级,内部类的创建必须先创建其外部类的对象,方可由外部类通过外部类名.new 内部类名(),进行实例化。内部类可以访问外部类所有的成员变量,即使外部类成员变量时私有的*内部类中不允许定义静态变量*,允许嵌套定义内部类。具体用法如下
package com.innerclass;
interface Increment{
void increment();
}
public class OuterClass implements Increment{
private int value;
private class InnerClass implements Increment{
//在普通的内部类中不可定义静态变量
private int i;
//嵌套定义内部类
class NestDefineInnerClass implements Increment{
public NestDefineInnerClass() {
System.out.println(" i am a nest Innerclass");
}
@Override
public void increment() {
System.out.println(++i);
System.out.println(++value);
}
}
public InnerClass() {
System.out.println("i am innerClass");
}
public InnerClass(int i) {
super();
this.i = i;
}
@Override
public void increment() {
System.out.println(++value);
}
/**
* 在内部类中返回外部类的引用
* @return
*/
public Increment getOuterClass(){
return OuterClass.this;
}
}
@Override
public void increment() {
System.out.println(++value);
}
/**
* 在外部类中提供一个获取内部类的方法
* @return
*/
public Increment getInnerClass(){
return new InnerClass();
}
public static void main(String[] args){
OuterClass oc = new OuterClass();
OuterClass.InnerClass ic = oc.new InnerClass();
OuterClass.InnerClass.NestInnerClass oin = ic.new NestInnerClass();
}
}
内部类定义在方法中:定义在方法中的内部类可以访问其外部类和方法中的变量。但是该类的作用于仅限在在方法中,意思是在方法外面无法实例化该内部类类型的对象,在方法外,该对象不可见,但不意味这不可以,例如这里下面的例子还是可以利用多肽使其发挥作用的。
public Increment functionInnerClass(int j){
class FunctionInnerClass implements Increment{
@Override
public void increment() {
System.out.println(j);
}
}
return new FunctionInnerClass();
}
匿名内部类
匿名内部类:对象的创建和定义结合在一起。
其实创建的是一个父类类型的引用,匿名内部类重新定义自己的构造方法。因为它没有名字,下面我们看下如何使用匿名内部类
public Increment anonymousInnerClass(){
return new Increment() {
@Override
public void increment() {
System.out.println("i am a anonymous inner class");
}
};
}
这里返回的是Increment类型的对象,Increment类型是一个接口,这里定义的即是一个匿名内部类,无论是实现的接口,还是普通的类。都是向上转型。如果在匿名内部类中使用外部函数或外部类中变量,必须声明为final,或者不可再给其重新赋值。否则无法通过编译。
嵌套类
不需要和外部类有联系,嵌套类使用static修饰,
创建嵌套类不需要其先创建其外部类对象,
不能访问外部内中非静态的成员。
嵌套类可以定义静态的成员。
public static class NestInnerClass implements Increment{
static int i=1;
@Override
public void increment() {
System.out.println(i++);
}
}
实例化对象
OuterClass.NestInnerClass nc = new NestInnerClass();
内部类和外部类之间生成的class文件时通过$符号分隔的。
内部类使用中会出现的问题
内部类使用不当很容易引起内存泄露,原因是内部类持有外部类的引用,如果内部类没被回收,外部内也无法回收。