内部类,顾名思义,就是在一个类的里面定义一个类对象。下面将讲解内部类的作用。
1.成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部。
名字隐藏
public class InnerClassDemo {
class InnerClass {
private int i = 11;
public int value() {
return i;
}
}
InnerClass getInnerClass() {
return new InnerClass();
}
public static void main() {
InnerClassDemo innerClassDemo = new InnerClassDemo();
InnerClassDemo.InnerClass innerClass = innerClassDemo.getInnerClass();
}
}
链接到外部类
内部类就相当于外面多了一层作用域,只有从外部类才能访问到内部类。但是与C++不同,在java中,内部类多了一个功能,内部类拥有外部类的所有元素的访问权。这是如何做到的呢?这是因为,内部类对象会秘密的捕获一个指向外部类对象的引用。当访问外部类成员时,就是用按个引用来选择外部类的成员。
下面将进一步升级。
public class InnerClassDemo {
public int j = 12;
public void f() {
System.out.println("f()");
}
public class InnerClass {
private int i = 11;
public int value() {
return i;
}
public InnerClassDemo outer() {
return InnerClassDemo.this;
}
}
InnerClass getInnerClass() {
return new InnerClass();
}
public static void main(String[] args) {
InnerClassDemo innerClassDemo = new InnerClassDemo();
InnerClassDemo.InnerClass innerClass = innerClassDemo.getInnerClass();
innerClass.print();
innerClass.outer().f();
// InnerClassDemo.InnerClass innerClassV2 = new InnerClass();
InnerClassDemo.InnerClass innerClassV3 = innerClassDemo.new InnerClass();
System.out.println(innerClassV3.value());
}
}
------------output---------------
12
f()
11
这里要注意三个点。一是内部类可以访问外部类的成员变量j,当然也可以方法。二是外部类实例对象.new创建一个内部类和内部类使用.this返回外部类的引用; 三是创建外部类时,必须要有一个外部类的实例,原理是因为内部类需要一个外部类的引用,所以innerClassV2的创建方式是不行的。
多继承
从上面看不出内部类特别的优点,那么为什么java要为内部类增加这么多复杂的特性呢?这里引用“thinking in java"中原话:
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
其实使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,如果不需要解决多重继承问题,那么我们自然可以使用其他的编码方式,但是如果使用内部类,还可以获得其他一些特性:
1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
2、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
3、创建内部类对象的时刻并不依赖于外围类对象的创建。
4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。
2.局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
3. 匿名内部类
匿名内部类是我们平时写代码用得非常多的一个功能,没有类名字,多用于接口回调。
public class InnerClassDemo {
public class Contents {
}
public Contents contents() {
return new Contents() {
private int i = 1;
public int value() {
return i;
}
};
}
public static void main(String[] args) {
InnerClassDemo innerClassDemo = new InnerClassDemo();
Contents c = innerClassDemo.contents();
}
}
实际上述匿名类的语法是下述形式的简化形式
public class InnerClassDemo {
public class Contents {
}
public class MyContents extends Contents {
private int i = 1;
public int value() {
return i;
}
public Contents contents() {
return new MyContents();
}
}
public static void main(String[] args) {
InnerClassDemo innerClassDemo = new InnerClassDemo();
Contents c = innerClassDemo.new MyContents().contents();
}
}
这里是继承了Contexts类。使用匿名内部类时,我们必须是继承一个类或者实现一个接口。
使用匿名类要注意几点:
1.必须继承一个类或者实现一个接口;
- 匿名类名字都没有,所以构造函数式不存在的;
3.如果给匿名类传递参数,要使用fina修饰,个人认为这点是没有必要。究其原因是java中方法的参数如果是基础类型传递的是拷贝,如果是List等传递的是引用。然而内部类使用的是参数的拷贝值,并不是参数引用。所以对于基础类型来说使不使用final是没区别的, 但是对于List等来说,匿名类是不会修改参数值的,这与java中方法传参常理不符。java中没有传值和传址概念。
4.静态内部类(嵌套类)
嵌套内部类有一个static修饰符,不需要内部类对象与其外部类对象之间有联系,就如静态变量和静态方法一样,外部类只是一个作用域。
网友评论