java里的内部类通常能帮我们隐藏一些具体实现,体现良好的封装效果。
内部类又分几种:
1.普通内部类
2.局部内部类
3.匿名内部类
4.静态内部类
普通内部类
先来看第一种普通的内部类,这种内部类就非常简单了,就是将一个类的声明放在另一个类的内部
class Outer{
//外部类
class Inner{
//内部类
}
}
这样的话就可以声明出一个普通的内部类
但是在内部类声明的同时,该内部类会追踪到外部类的引用,因此,内部类可以访问到外部类的所有的域和方法,包括private声明的域和方法,换个说法来说也就是外部类里的所有的域和方法对于内部类来说都是可见的。
class Outer{
//外部类
private int i = 1;
class Inner{
//内部类
public void func(){
System.out.println(i);
}
}
}
这样的写法是不会有任何的编译时报错的
这样恰巧证明了内部类是可以访问到外部类所有的域和方法
那么,我们怎样去创建一个内部类的对象呢?
废话不多说我们直接代码说话
public class Main {
public static void main(String[] args){
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
}
}
由于 Inner是内嵌在Outer里的,所以我们必须要声明整个Outer才能加载inner的这块内存,因此我们必须先创建Outer的对象,再来使用Outer的引用new出inner的对象。这样的话我们就持有inner对象的引用了
静态内部类
普通内部类介绍完了再来看静态内部类,这个内部类和普通内部类没什么区别,区别只是多了一个static关键字,为表明它是静态的,加上这个关键字以后,它不能持有外部类的引用了,并且不能访问到外部类的非静态方法和域。 我们将上面的代码加做修改 ``` class Outer{ //外部类 private int i = 1; static class Inner{ //内部类 public void func(){ System.out.println(i); } } } ``` 我们把它声明为static之后,会发现编译器报了一个错 ![](http://images2015.cnblogs.com/blog/1014798/201609/1014798-20160924161309856-643970765.png) 不能访问到非静态的域。 这样的情况出现,我们就更清晰明了了,因为我们会发现它和static修饰字段和方法的作用是差不多的。除此之外,它和普通的内部类就没有什么区别了。 下面我们来看一下静态内部类怎样去创建一个对象 ``` public class Main { public static void main(String[] args){ Outer.Inner inner = new Outer.Inner(); } } ``` 由于静态内部类是一块独立的静态内存,因此我们可以直接这样去声明它,并且不用依靠外部类的对象局部内部类
所谓的局部内部类就是声明在方法体里的内部类,或者声明在某个作用域里的内部类 ``` class Outer{ //外部类 private int i = 1; public void func(){ class Inner{ public Inner innerFunc(){ System.out.println(i); return new Inner(); } } } } ``` 或者你也可以将类定义在随意的一个作用域里,比如if语句 ``` class Outer{ //外部类 private int i = 1; public void func(){ if(true){ class Inner{ public Inner innerFunc(){ System.out.println(i); return new Inner(); } } } else{ // } } } ```匿名内部类
在讲解这个之前,试问你们有没有见过new 一个接口,相信大家已经见过很多次了吧,但是java里明确的规定接口是不能被创建对象的,但是下面这个例子却能够正常的运行 ``` public class Main { public static void main(String[] args){ Temp temp = new Temp(){ public void func(){ System.out.println("hello world"); } }; } }interface Temp{
void func();
}
然后我们调用func();
temp.func();
接下来我们可以明确的看到控制台上打印出来的"hello world",那么这又是怎么回事呢,这就要涉及到我们要讲解的匿名内部类
首先这根本不是我们看到的那样new了接口,而是用了一个匿名的内部类去实现了这个接口,然后重写了func方法,最后将整个内部类向上转型为Temp,赋值给它的引用。
这样的话,能够轻松的帮助我们实现接口,但是有一个问题也接踵而来,那就是限制了代码的复用。