在一个类的内部定义的类称为内部类。
1、内部类的基本语法
顶层类只能处于public和默认访问级别,而内部类可以是public,protected,默认,private这四种访问级别。
package visitcontrol;
public class Outer {
public class Inner {
public int add(int a, int b) {
return (a + b);
}
}
Inner inner = new Inner();
public int add(int a, int b, int c) {
return inner.add(inner.add(a, b), c);
}
}
public class Tester {
public static void main(String[] args) {
Outer outer = new Outer();
System.out.println(outer.add(1, 2, 3));
Outer.Inner inner = new Outer().new Inner();
System.out.println(inner.add(1, 2));
}
}
输出结果:
6
3
1.1、实例内部类
实例内部类具有以下特点:
●在创建实例内部类的实例时,外部类的实例必须已经存在。
Outer.Inner inner=new Outer.new Inner();
等价于:
Outer outer=new Outer();
Outer.Inner inner=outer.new Inner();
●实例内部类的实例自动持有外部类的实例的引用。在内部类中可以直接访问外部类的所有成员。
package outerref;
public class A {
public int a1;
protected int a2;
static int a3;
public A(int a1, int a2) {
this.a1 = a1;
this.a2 = a2;
}
protected int method() {
return a1 * a2;
}
class B {
int b1 = a1;
int b2 = a2;
int b3 = a3;
int b4 = new A(3, 4).a1;
int b5 = method();
}
public static void main(String[] args) {
A.B b = new A(1, 2).new B();
System.out.println("b.b1=" + b.b1);
System.out.println("b.b2=" + b.b2);
System.out.println("b.b3=" + b.b3);
System.out.println("b.b4=" + b.b4);
System.out.println("b.b5=" + b.b5);
}
}
输出结果:
b.b1=1
b.b2=2
b.b3=0
b.b4=3
b.b5=2
●外部类实例与内部类实例之间是一对多的关系,一个内部类实例只会引用一个外部类实例,而一个外部类实例对应零个或多个外部类实例。在外部类中不能直接访问内部类的成员,必须通过内部类的实例去访问。
●在实例内部类中不能定义静态成员,而只能定义实例成员。
●如果实例内部类B与外部类A包含同名的成员(比如成员变量v),那么在类B中,this.v表示类B的成员,A.this.v表示类A的成员。
package differnames;
public class A {
int v = 1;
public class B {
int v = 2;
public void test() {
System.out.println("v=" + v);
System.out.println("this.v=" + this.v);
System.out.println("A.this.v=" + A.this.v);
}
}
public static void main(String[] args) {
new A().new B().test();
}
}
输出结果:
v=2
this.v=2
A.this.v=1
1.1.2、静态内部类
静态内部类具有以下特点:
●静态内部类的实例不会自动持有外部类的特定实例的引用,在创建外部类的实例时,不用创建外部类的实例。
public class A{
public static class B{
int v;
}
}
class Tester{
public void test(){
A.B b=new A.B();
b.v=1;
}
}
●静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,就必须通过外部类的实例来访问。
●在静态内部类中可以定义静态成员和实例成员。
●客户类可以通过完整的类名直接访问静态内部类的静态成员。
1.1.3、局部内部类
局部内部类是在一个方法中定义的内部类,它的可见范围是当前方法,和局部变量一样,局部内部类不能用访问控制符修饰(public ,private,protected)及static修饰符修饰。局部内部类具有以下特点:
●局部内部类只能在当前方法中使用
●局部内部类和实例内部类一样,不能包含静态成员。
●在局部内部类中定义的内部类也不能被public,protected和private这些控制修饰符修饰。
●局部内部类和实例内部类一样,可以访问外部类的所有成员,此外局部内部类还可以访问所在方法中的final类型的参数和变量。
2、内部类的继承
package inherit;
public class Outer {
public int a ;//外部类的实例变量
public Outer(int a) {
this.a = a;
}
public class Inner {
public Inner() {
};
public void print() {
System.out.println("a=" + a);// 访问外部类的实例变量
}
}
}
public class Sample extends Outer.Inner {
public Sample(Outer o) {
o.super();
}
public static void main(String[] args) {
Outer outer1 = new Outer(1);
Outer outer2 = new Outer(2);
Outer.Inner in = outer1.new Inner();
in.print();
Sample sample1 = new Sample(outer1);
Sample sample2 = new Sample(outer2);
sample1.print();
sample2.print();
}
}
输出结果:
a=1
a=1
a=2
3、子类与父类中的内部类同名
package nooverride;
public class Outer {
Inner in;
public Outer() {
in = new Inner();
};
public class Inner {
public Inner() {
System.out.println("Inner of Outer");
}
}
}
public class SubOuter extends Outer {
public class Inner {
public Inner() {
System.out.println("Inner of SubOuter");
};
}
public static void main(String[] args) {
SubOuter.Inner subin = new SubOuter().new Inner();
Outer.Inner in = new Outer().new Inner();
}
}
输出结果:
Inner of Outer
Inner of SubOuter
Inner of Outer
Inner of Outer
4、匿名类
package noname;
public class A {
public A(int v) {
System.out.println("another constructor");
}
public A() {
System.out.println("default constructor");
}
void method() {
System.out.println("from A");
}
public static void main(String[] args) {
new A().method();
// 定义了一个继承类A的匿名类
A a = new A() {
void method() {
System.out.println("from anonymous");
}
};
a.method();
}
}
输出结果:
default constructor
from A
default constructor
from anonymous
匿名类的特点:
●匿名类本身没有构造方法,但是会调用父类的构造方法
●匿名类虽然没有构造方法,但是可以在匿名类中提供一段实例初始化代码,Java虚拟机会在调用了父类的构造方法后执行这段代码。实例化初始化代码不允许被重载,匿名类的实例只能有一种初始化方式。
public static void main(String[] args) {
int v=1;
// 定义了一个继承类A的匿名类
A a = new A(v) {
{System.out.println("initialize instance");}
void method() {
System.out.println("from anonymous");
}
};
a.method();
}
输出结果:
another constructor
initialize instance
from anonymous
●除了可以在外部类的方法内定义匿名类外,还可以在声明一个成员变量时定义匿名类
●匿名类除了可以继承之外,还可以实现接口
●匿名类和局部内部类一样,可以访问外部类的所有成员,如果匿名类位于一个方法中,还能访问所在方法的final类型的参数和变量。
●局部内部类的名字在方法外是不可见的,因此和匿名类一样,可以起到封装类型名字的作用。局部内部类与匿名类的区别:
①匿名类的程序代码比较简洁
②一个局部内部类可以有多个重载的构造方法,并且客户类可以多次创建局部内部类的实例。而匿名类没有重载构造方法,并且只能创建一次实例。
5、内部接口及接口中的内部类
6、内部类的用途
①封装类型
②直接访问外部类的成员
③回调外部类的方法
。。。未完待续