一、 内部类
内部类的定义:大部分时候,我们把类定义成一个独立的程序单元。在某些情况下,我们把一个类放在另一个类的内部定义,这个定义在其他类内部的类被称为内部类,包含内部类的类被称为外部类。
内部类的作用:
1、内部类提供了更好的封装,可以把内部类隐藏在外部类内部。public、default、protected、private四种修饰符都能限制对内部类的访问。
2、当内部类定义在成员位置上时,内部类可以看做外部类的成员。由于同一个类的成员之间可以相互访问。
3、内部类的出现可以达到“多重继承”的效果。
4、使用内部类可以避免修改接口而实现同一个类中两种同名方法的调用。
二、 内部类的具体划分
当内部类定义在外部类的成员位置上时,内部类分为非静态内部类和静态内部类。
当内部类定义在局部(方法体中),内部类分为局部内部类和匿名内部类(匿名内部类是局部内部类的一种特殊情况。因为其特殊性,所以我划分出来)
1、非静态内部类:
代码演示:
class Outer
{
private int x = 3;
static int y = 5;
public class Inner
{
int x = 4;
int y = 7;
//static z = 7;编译失败
void function()
{
int x = 6;
System.out.println("inner:"+x);//打印6--局部变量
System.out.println("inner:"+y);//打印7--成员变量(省略this)
System.out.println("inner:"+this.x);//打印4--成员变量(因为成员与局部变量名重复,需要用this才访问成员)
System.out.println("inner:"+Outer.this.x);//打印3--外部类私有成员变量,
method1();
}
}
void method()
{
Innter in = new Inner();
System.out.println("外部类的非静态成员方法!");
}
static void method1()
{
//Inner in = new Inner();//编译失败,静态方法不能访问非静态内部类
System.out.println("外部类的静态成员方法!");
}
}
public class InnerClassDemo
{
public static void main(String[] args)
{
Outer.Inner in = new Outer().new Inner();
in.function();//在外部其他类中,访问非静态内部类的非静态成员
}
}
非静态内部类的细节:
1)、非静态内部类相当于外部类的非静态成员,遵循类中非静态成员的规则。所以非静态内部类可以访问外部类中所有成员,包括:private私有成员和static静态成员。这是由于内部类持有一个外部类的引用,该引用的写法是:外部类名.this。
2)、非静态内部类只能定义非静态成员。
3)、要在外部其他类创建一个类的非静态内部类的实例,必须要用外部类实例和new来调用该内部类构造器来创建内部类的实例对象。
4)、当内部类中局部变量、成员变量和外部类成员变量有重名时,需要指明访问的是那一个变量,如果不指明默认从最里层开始找,如果没有向外层找。为了避免这种不明确的现象,访问的时候最好指明要访问哪一个变量,用this、外部类名.this加以区分。
在外部其他类中访问非静态内部类的语法格式:
外部类名.内部类名. 变量名 = new 外部类名().内部类名();(也可拆开写)
Outer.Inner in = new Outer().new Inner();
In.function();
2、静态内部类
代码演示:
class Outer
{
private static int x = 3;
private int y = 4;
static class Inner
{
static void write()
{
System.out.println(x);//编译通过,x是静态成员变量
//System.out.println(y);编译失败,y是非静态成员变量
System.out.println("静态内部类的静态成员方法!");
}
void function()
{
method1();//编译通过,method1是静态成员方法
//method2();//编译失败,method2是非静态成员方法
System.out.println("静态内部类非静态成员方法");
}
}
public static void method1()
{
Inner in = new Inner();//编译通过
System.out.println("外部类的静态成员方法!");
}
public void method2()
{
Inner in = new Inner();//编译通过
System.out.println("外部类的非静态成员方法!");
}
}
class InnerClassDemo2
{
public static void main(String[] args)
{
Outer.Inner in = new Outer.Inner();
in.function();//在外部其他类中,访问静态内部类的非静态成员
Outer.Inner.write();//在外部其他类中,访问静态内部类的静态成员
}
}
静态内部类的细节:
1)、静态内部类相当于外部类的静态成员,遵循静态成员的规则,所以该内部类附属于类。
2)、静态内部类只能访问外部类的静态成员。
3)、静态内部类既能定义静态成员,也能定义非静态成员。并且,只要一个内部类中定义了静态成员,那么这个类一定是静态内部类。
4)、因为静态内部类附属于类,所以在外部其他类中创建一个类的静态内部类只需要外部类类名和new来调用该内部类构造器来创建内部类的实例对象。
在外部其他类中访问静态内部类的语法格式:
外部类名.内部类名.变量名 = new 外部类名.内部类名();
Outer.Inner in1= new Outer.Inner();
In.method2();
Outer.Inner.write();
总结:
1)、静态成员方法只能访问静态内部类;非静态方法既能访问静态内部类,又能访问非静态内部类。
2)、静态内部类既能定义静态成员,又能定义非静态成员;非静态内部类只能定义非静态成员。
3)、当一个内部类中定义了静态成员,那么这个类一定是一个静态内部类。
3、局部内部类
代码演示:class Outer
{
int x =3;
void method1()
{
int z = 4;
final int y = 7;
class Inner
{
//static int i = 2;//错误:内部类Inner中的静态声明非法
int i = 2;//
void function()
{
System.out.println(i);
System.out.println(Outer.this.x);
System.out.println(y);//编译通过
//System.out.println(z);//编译失败,被声明为final最终类型的局部变量才能被局部内部类访问
show();
run();
}
}
Inner in = new Inner();
in.function();
}
void show()
{
System.out.println("外部类方法");
//function();//编译失败
}
static void run()
{
System.out.println("外部类静态方法");
}
static void method2()
{
class Inner
{
void function()
{
System.out.println("我只能访问外部类的静态成员");
}
}
new Inner().function();
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
Outer ou = new Outer();
ou.method1();
Outer.method2();
//Outer.Inner in = new Outer().new Inner();编译失败,局部内部类之作用与方法体
}
}
局部内部类的细节:
1)、局部内部类相当于局部成员,遵循局部成员的规则。所以局部内部类的作用域是所在方法,它的上一级程序单元是方法而不是类。
2)、局部内部类不能被任何访问修饰符访问。因为只在方法体有效,所以访问权限就无从谈起,也就不能在外部其他类中创建局部内部类对象了。
3)、局部内部类也不能被static静态修饰,因为它的上一级是方法,static修饰没有意义。并且局部内部类不能定义任何static静态成员。
4)、局部内部类可以直接访问外部类中的成员,因为持有外部类的引用。
5)、局部内部类访问局部变量时,只能访问被final修饰过的局部变量。
6)、局部内部类可以定义在静态方法体和非静态方法体中。
4、匿名内部类
代码演示:
abstract class AbsDemo
{
String name;
AbsDemo(){}
AbsDemo(String name)
{
System.out.println(name);
}
abstract void show();
abstract void run();
}
interface InteDemo
{
void show();
void run();
}
class Outer
{
int x = 3;
public void function1()
{
AbsDemo d = new AbsDemo("HeiMa")//也可以没有实际参数
{
int num = 9;
void show()
{
System.out.println("num:"+num);
System.out.println("x:"+Outer.this.x);
}
void run()
{
System.out.println("run");
}
};
d.show();
d.run();
}
public void function2()
{
new InteDemo()//不能有参数
{
int num = 9;
public void show()
{
System.out.println("num:"+num);
System.out.println("x:"+Outer.this.x);
}
public void run()
{
System.out.println("run");
}
}.show();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
new Outer().function1();
new Outer().function2();
}
}
匿名内部类的格式:
new 父类构造器(实参列表) 或实现接口名()
{
//匿名内部类类体部分
}
匿名内部类细节:
1)、因为匿名内部类属于局部内部类,所以局部内部类的所有限制都对其生效。
2)、匿名内部类适合创建那种只需要使用一次的类。创建匿名内部类时会立即创建一个该类的实例,然后这个类定义立即消失,匿名内部类不能重复使用
3)、使用匿名内部类的前提是必须继承父类或者实现接口,并且最多只能继承一个父类或者实现一个接口。
4)、匿名内部类不能是抽象类。所以当匿名内部类继承一个抽象父类或者实现一个接口时,一定要覆盖全部抽象方法才能使用。
5)、匿名内部类可以赋给父类或者接口的引用变量,从而用这个引用调用多个方法。
匿名内部类深入:
1)、如果通过继承父类创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似指的是拥有相同的形参列表。
2)、当通过实现接口来创建匿名内部类时,匿名内部类不能是显式创建构造器,因此匿名内部类只有一个隐式的无参构造器,故new括号里不能传入任何参数值。
3)、Java通过匿名内部类加上接口,实质上弥补了Java单继承的不足。
为避免误导初学者,本博客如有错误或者不严谨的地方,请在下方给与评论,以便及时修改!谢谢... ...