在一个类的内部定义的类称为内部类。内部类属于外部类。
内部类分为:
成员内部类 静态内部类 局部内部类 匿名内部类
顶层类(正常类)只能处于public和默认访问级别,而成员内部类可以处于public, protected, private和默认这4种访问级别;
※ 内部类1. 静态内部类 (相对应类中的一个静态变量)
是成员内部类的一种,用static修饰。静态内部类具有以下特点:
1)静态内部类中访问不到外部类的非静态属性或者方法。(必须通过构建外部类实例,通过对象.属性名(方法名))。
静态内部类的对象不需要依赖于外部类的对象。
内部类 变量名字 = new 内部类();
public class A {
public static class B{
private int v;
public void say(){
System.out.println("hello");
}
}
public static void main(String[] args){
//静态内部类的对象不需要依赖于外部类的对象。
B b = new B();
}
}
2)静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,就必须通过外部类的实例去访问。
class A {
private int a1; //实例变量a1
private static int a2; //静态变量a2
public static class B {
//编译错误,不能直接访问外部类A的实例变量a1
int b1 = a1;
//合法,可以直接访问外部类A的静态变量a2
int b2 = a2;
//不合法 静态内部类中不能访问外部对象的this
int b3 = A.this.a1;
}
}
3)在静态内部类像普通类一样,可以定义静态成员和实例成员,静态代码块,匿名代码块,构造器,主方法(注:eclipse中只能一次运行一个主方法,需要手动区分你运行的是外部主方法还是内部主方法)等。静态内部类中还可继续嵌套内部类。
注:静态内部类还可以定义抽象方法,变为静态内部抽象类。继承该类时,只需要外部类名.内部类名(静态内部类不依赖外部类的实例对象)就OK了。
class A {
public static class B {
int v1; //实例变量
static int v2; //静态变量
void say(){} //非静态方法
static void say1(){} //静态方法
static{} //静态代码块
public B(){} //静态内部类构造器
//静态内部内部类
public static class C{}
public class D{}
}
public abstract static class E {
// 静态内部抽象类
public abstract void test();
}
}
public class F extends A.E{
@Override
public void test(){
}
}
4)可以通过完整的类名直接访问静态内部类的静态成员。
对于静态内部类的非静态成员,只能构建静态内部类的实例进行访问了。
class A {
public static class B {
int v1; //实例变量
static int v2; //静态变量
public static class C {
static int v3; //静态内部类
int v4;
}
}
}
public class Tester {
public void test() {
A.B b = new A.B();
A.B.C c = new A.B.C();
b.v1 = 1;
b.v2 = 1;
A.B.v1 = 1; //编译错误
A.B.v2 = 1; //合法
A.B.C.v3 = 1; //合法
}
}
注:
1)外部类操作静态内部类内部类中静态属性和方法:
外部类访问内部类的静态属性和方法:内部类.静态属性的名字/方法名
2)其他类访问内部类的静态属性和方法:
外部类.内部类.静态属性名
外部类.内部类.静态方法名();
3)访问内部类非静态的属性和方法:
构建内部类的对象,正常操作
外部类.内部类 变量名=new 外部类.内部类();
其他类访问时:
先导包(内部类的位置,import全包名.外部类.内部类)
内部类 变量名=new 内部类();
※ 内部类2. 成员内部类 (相当于类中的一个成员变量)
与静态内部类比,成员内部类有可称为非静态内部类。
. 成员内部类中不能有static的声明属性或者方法;
. 成员内部类可以由public protected default private修饰;
. 成员内部类是依赖于外部类的对象而存在的
外部类.内部类 var = new 外部类().内部类()。
成员内部类具有以下特点:
1)在创建实例内部类的实例时,外部类的实例必须已经存在。
Outer.InnerTool tool = new Outer().new InnerTool();
等价于:
Outer outer = new Outer();
Outer.InnerTool tool = outer.new InnerTool();
以下代码会导致编译错误:
Outer.InnerTool tool = new Outer.InnerTool();
2)实例内部类的实例自动持有外部类的实例的引用。在内部类中,可以直接访问外部类的所有成员,包括成员变量和成员方法。
public class A {
private int a1;1
public int a2;2
static int a3;
public A(int a1, int a2) {
this.a1 = a1;
this.a2 = a2;
}
protected int methodA() {
return a1*a2;
}
class B {
int b1 = a1; //直接访问private的a1
int b2 = a2; //直接访问public的a2
int b3 = a3; //直接访问static的a3
int b4 = A.this.a1; //访问类A的当前实例中的a1
int b5 = methodA(); //访问methodA()方法
}
public static void main(String args[]) {
A.B b = new A(1,2).new B();
System.out.println("b.b1="+b.b1); //打印b.b1=1;
System.out.println("b.b2="+b.b2); //打印b.b2=2;
System.out.println("b.b3="+b.b3); //打印b.b3=0;
System.out.println("b.b4="+b.b4); //打印b.b4=1;
System.out.println("b.b5="+b.b5); //打印b.b5=2;
}
}
3)外部类实例与内部类实例之间是一对多的关系,一个内部类实例只会引用一个外部类实例,而一个外部类实例对应零个或多个内部类实例。在外部类中不能直接访问内部类的成员,必须通过内部类的实例去访问。
class A {
class B {
private int b1 = 1;
public int b2 = 2;
class C{}
}
public void test() {
int v1 = b1; //invalid
int v2 = b2; //invalid
B.C c1 = new B().new C(); //invalid
B b = new B(); //valid
int v3 = b.b1; //valid
int v4 = b.b2; //valid
B.C c2 = b.new C(); //valid
B.C c3 = new B().new C(); //valid
}
}
4) 实例内部类中不能定义静态成员,而只能定义实例成员。不能构建抽象方法,不能构建主方法。
5) 如果实例内部类B与外部类A包含同名的成员,那么在类B中, this.v表示类B的成员, A.this.v表示类A的成员。
※ 注:成员内部类可以访问外部类的所有东西(静态的非静态的属性和方法)
1)获取外部类对象 :外部类名.this.属性名/方法名()
2)成员内部类访问外部静态方法时三种方法
外部类.this.方法名();
外部类.方法名();
方法名();
3)成员内部类访问外部类的非静态方法时两种方法
外部类.this.方法名();
方法名();
(注意当调用方法内部类和外部类同时有时不能用,会优先调用内部类)
※ 内部类3. 局部内部类(相当于一个方法中的局部变量)
. 局部内部类不能用public private等修饰符修饰;
. 写在方法当中,而且只能在方法当中使用;
. 可以访问外层类的普通成员变量和静态成员变量以及普通方法和静态方法,也可以访问该内部类所在方法当中的局部变量,但是这个局部变量必须是final修饰。
局部内部类具有以下特点:
1) 局部内部类只能在当前方法中使用。
class A {
B b = new B(); //编译错误;
public void method() {
class B{
int v1;
int v2;
class C {
int v3;
}
}
B b = new B(); //合法
B.C c = b.new C(); //合法
}
}
2) 局部内部类和实例内部类一样,不能包含静态成员。
不能有抽象方法。
class A {
public void method() {
class B{
static int v1; //编译错误
int v2; //合法
static class C { //编译错误
int v3;
}
}
}
}
3)在局部内部类中定义的内部类也不能被public、protected和private这些访问控制修饰符修饰;
4) 局部内部类和实例内部类一样,可以访问外部类的所有成员,此外,局部内部类还可以访问所在方法中的final类型的参数和变量。
※ 内部类4. 匿名内部类(和局部内部类很相似)
匿名内部类也是用的最多的内部类。
匿名内部类具有以下特点:
1)可以写成成员变量的形式,也可以写在方法当中,一般写在方法当中较多。
2)匿名内部类里可以访问外部类的普通属性和方法,已经静态属性和方法,如果要访问这个内部类所在方法中的局部变量,那么要求这个局部变量必须是final修饰的。
3)匿名内部类里面没有构造函数,因为这个类没有名字,所以在其他地方不能用。
4)不能写静态的内容,能访问全局变量的属性及方法,匿名内部类不让直接使用内部类的属性,可以给属性提供方法获取属性值。
5)抽象类也能写匿名内部类,外部类不能直接访问内部类的非抽象类的方法,但是可以借助抽象类本身的方法。抽象类的匿名内部类只能获取抽象类中定义的属性,匿名内部类中定义的属性只能在匿名内部类中的方法使用,可以通过super.属性名/方法名 调用抽象类的属性/方法。
public class Hello{
public void test(){
//假如A是同包下的一个接口,有一个抽象方法go
A a = new A(){
public void go(){
System.out.println("gogogo");
}
};
}
}
//也用于抽象类没有被继承想实例化时,重写抽象方法
Inter i=new Inter() {
@Override
public void method() {
// TODO Auto-generated method stub
System.out.println("method方法的实现");
}
};
※ 几种内部类的区别:
1)创建
a. 声明的位置:
静态内部类:类的内部,方法的外部,用static关键字修饰;
实例内部类:类的内部,方法的外部,不用static关键字修饰;
局部内部类:方法的内部;
匿名内部类:既可以在类的内部,方法的外部,也可以在方法的内部;
b. 实例化方式:
静态内部类:new Outer.Inner(); //在外部类外创建;
new Inner(); //在外部类内内部类外创建
实例内部类:new Outer().new Inner(); //在外部类外创建;
this.new Inner(); //在外部类内内部类外创建
局部内部类:new Inner(); //只能在方法内部创建;
匿名内部类:new 类名() {};
2)访问
a. 外部类访问内部类:
静态内部类:通过完整的类名直接访问静态内部类的静态成员;
实例内部类:通过内部类的实例去访问内部类的成员;
局部内部类:不能访问;
匿名内部类:不能访问;
b. 内部类访问外部类:
静态内部类:直接访问外部类的静态成员;
实例内部类:可以直接访问外部类的所有成员;
如果实例内部类B与外部类A包含同名的成员,那么在类B中, this.v表示类B的成员,
A.this.v表示类A的成员。
局部内部类:可以直接访问外部类的所有成员, 访问所在方法中的final类型的参数和变量;
匿名内部类:可以直接访问外部类的所有成员, 访问所在方法中的final类型的参数和变量;