所谓的内部类,就是将一个类定义到另一个类的定义内部。这里引入一个词——嵌套类,嵌套类包括静态嵌套类和非静态嵌套类(内部类),这里的非静态嵌套类就是内部类,而嵌套类呢在接下来的介绍中会讲到。
对于内部类(非静态嵌套类),可以分为三种:
(1) 局部内部类
(2) 匿名内部类
(3) 成员内部类
接下来看看内部类的创建方式:
一、创建局部内部类。
public class LocalInnerClass {
private static final String LABEL = "LocalInnerClass";
class LocalClass{
public LocalClass(){
System.out.println("LocalClass()");
}
public String getLabel(){
return LABEL;
}
}
public LocalClass getLocalClass(){
return new LocalClass();
}
public static void main(String[] args){
LocalInnerClass lic = new LocalInnerClass();
/*
* 创建内部类对象的格式为:外部类.内部类 内部类的引用 = 外部类实例化对象的引用.返回内部类引用的方发(或者).new 内部类;
* */
LocalInnerClass.LocalClass localclass = lic.getLocalClass();
// LocalInnerClass.LocalClass localclass2 = lic.new LocalClass();
System.out.println(localclass.getLabel());
}
}
运行结果:LocalClass() LocalInnerClass
局部内部类的特点:局部内部类不能有访问说明符,如public、protected、private等,这是因为局部内部类不是外围类的一部分;但是它可以访问当前代码块内的常亮以及此外围类的所有成员。
二、创建匿名内部类。
package Inner;
/*
* 定义的一个接口
* */
public interface Ainterface {
String readString();
int value();
}
package Inner;
public class Anonymousinnerclass {
public Ainterface getAinterface(){
/*
* 匿名内部类的定义
* */
return new Ainterface(){
private int i = 100;
private String string = "Anonymousinnerclass";
public String readString(){
return string;
}
public int value(){
return i;
}
};
}
public static void main(String[] args){
Anonymousinnerclass aic = new Anonymousinnerclass();
Ainterface ai = aic.getAinterface();
System.out.println(ai.readString()+","+ai.value());
}
}
运行结果:Anonymousinnerclass,100
对于上面的例子,很多刚学Java的人都会奇怪,getAinterface()方法将返回值的生成与表示这个返回值的类的定义结合了在一起!而这就是匿名内部类。下面我们就简化一下上面的匿名内部类,通过语法的简化形式,相信大家能更理解。
上面例子的简化形式:
public class TestAnonymous {
class MyAnonymous implements Ainterface{
private int i = 100;
private String string = "Anonymousinnerclass";
public String readString(){
return string;
}
public int value(){
return i;
}
}
/*
* 向上转型为Ainterface
* */
public Ainterface getAinterface(){
return new MyAnonymous();
}
public static void main(String[] args){
TestAnonymous ta = new TestAnonymous();
Ainterface atf = ta.getAinterface();
System.out.println(atf.readString()+","+atf.value());
}
}
运行结果:Anonymousinnerclass,100
三、创建成员内部类。
/*
* 成员内部类都有访问说明符,如public、private、protected等修饰
* 成员内部类是可以访问外部类的静态与非静态的方法和成员变量的。
* */
public class MemberInnerClass {
private int x = 10;
public void value(){
}
/*
* 成员内部类的创建
* */
public class MemberClass{
/*
* 可以在内部类中定义于外部类同名的成员变量于方法
* */
private int x = 100;
public void value(){
System.out.println("内部类_x:"+this.x);
System.out.println("外部类_x:"+MemberInnerClass.this.x);
}
}
public static void main(String[] args){
MemberInnerClass mic = new MemberInnerClass();
MemberInnerClass.MemberClass mc = mic.new MemberClass();
mc.value();
}
}
运行结果:
内部类_x:100
外部类_x:10
四、创建嵌套类
将内部类声明为static,从而不需要内部类对象与外围类对象之间存在联系,就称之为嵌套类。嵌套类的static有何含义?对于普通内部类,其对象隐式地保存了一个引用,并指向了创建他的外围类的对象,而嵌套类则不是这样。
对嵌套类:
1.要创建嵌套类的对象,并不需要其外围类的对象。
2.不能从嵌套类的对象中访问非静态类的外围类对象。
嵌套类和普通内部类还有一个区别。普通内部类的字段和方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和字段,也不能包含嵌套类。而嵌套类则可以包含所有这些东西。内部类会通过一个特殊的this引用可以链接到其外围类的对象,嵌套类就没有这个特殊的this引用,这就使得它类似于一个static方法。
示例:
public interface Destination {
String readLabel();
}
public class Parcel11 {
/*
* 嵌套类不同于内部类,嵌套类可以包含static,但内部类则不能
* */
private static class ParcelDestination implements Destination{
private String label;
private ParcelDestination(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
public static void f(){}
static int x = 10;
/*
* 嵌套类内部再定义一个嵌套类
* */
static class AnotherLevel{
public static void f(){}
static int x = 10;
}
}
public static Destination destination(String s){
return new ParcelDestination(s);
}
public static void main(String[] args){
Destination d = destination("This insertinnerclass ");
System.out.print(d.readLabel());
}
}
运行结果:This insertinnerclass
接下来,深入总结一下内部类的一些重要知识点:
(1)使用.this与.new
如果要在内部类中生成对外部类对象的引用,可以使用外部类的名字后面紧跟着圆点和this。这样产生的引用自动地具有正确的类型,这一点在编译期就被知晓并受到检查,因此没有任何运行时的开销。
下面示例展示了如何使用.this:
/*
* 使用内部类的.this
* */
public class DoThis {
void fun(){
System.out.print("DoThis.fun()");
}
class Inner{
public DoThis outer(){
return DoThis.this;
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args){
DoThis dothis = new DoThis();
DoThis.Inner inner = dothis.inner();
inner.outer().fun();
}
}
结果:DoThis.fun()
而.new,之前已经介绍过了,是用于创建内部类对象的方法之一,也就是外部类引用.new 内部类()。
2)定义匿名内部类的条件
内部类必须继承一个父类或者实现一个接口,其中父类又包括普通类与抽象类。
下面就来展示这三种情况:
继承普通类
public class Wrapping { //定义的普通类
private int i;
public Wrapping(int x){
i = x;
}
public int value(){
return i;
}
}
public class SympleClass {
public Wrapping wrapping(int x){
return new Wrapping(x){
public int value(){
return x;
}
};
}
public static void main(String[] args){
SympleClass sc = new SympleClass();
Wrapping w = sc.wrapping(100);
System.out.println(w.value());
}
}
结果:100
public abstract class Wrapping2 {
public abstract int value();
}
public class SympleClass {
private int x = 100;
public Wrapping2 wrapping2(){
return new Wrapping2(){
public int value(){
return x;
}
};
}
public static void main(String[] args){
SympleClass sc = new SympleClass();
Wrapping2 w = sc.wrapping2();
System.out.println(w.value());
}
}
结果:100
package Inner;
/*
* 定义的一个接口
* */
public interface Ainterface {
String readString();
int value();
}
package Inner;
public class Anonymousinnerclass {
public Ainterface getAinterface(){
/*
* 匿名内部类的定义
* */
return new Ainterface(){
private int i = 100;
private String string = "Anonymousinnerclass";
public String readString(){
return string;
}
public int value(){
return i;
}
};
}
public static void main(String[] args){
Anonymousinnerclass aic = new Anonymousinnerclass();
Ainterface ai = aic.getAinterface();
System.out.println(ai.readString()+","+ai.value());
}
}
运行结果:Anonymousinnerclass,100
(3)那为什么需要内部类呢?
在《Think in Java》中,每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的、可继承多个具体的或抽象的类的能力,一些设计与编程问题就难以解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效的实现了“多重继承”。也就是说,内部类允许继承多个非接口类型(类与抽象类)。
总结一下节点:
(1)解决了多继承的问题
(2)多个内部类可以以不同的方式实现同一接口,继承同一个类。
(3)创建内部类对象的时刻并不依赖于对外围类对象的创建。
(4)内部类并没有“is-a”关系,它就是一个独立的实体。
(5)内部类提供了更好的封装,除了外围类,其他类都不能访问。
但对于内部类的使用,我们必须要清楚什么时候能用,什么时候不能用。相信随着对Java的深入学习,我们能够更好的识别什么情况下应该使用接口,什么情况下使用内部类,或者同时使用二者。