内部类
一个类可以有五大成员:属性、方法、构造器、代码块、内部类。
内部类作为类中五大成员的一部分,是非常重要的。内部类顾名思义就是内部的类,也就是定义在类内部的类。
public class Other{ //外部其他类
public static void main(String[] args)
}
class Outer{ //外部类
class Inner{ //内部类
}
}
内部类分为以下四种:
- 局部内部类
- 匿名内部类
- 成员内部类
- 静态内部类
1、局部内部类
1.1 局部内部类访问外部类成员(直接访问)
局部内部类定义的位置是在外部类的局部位置(一般定义在方法或者代码块里),定义在局部范围内,在外部类的眼中,它的地位也就是一个局部变量。作为外部类的局部变量,他也就属于外部类本类成员,所以内部类可以访问外部类所有的成员,包括私有成员(私有成员只能在本类中访问)
1.2 内部类的修饰符
内部类作为一个成员变量,不能添加任何访问修饰符,但是可以用final修饰,如果用final修饰,其他类不可作为它的子类。
1.3 内部类的作用域
作为一个局部变量,作用域只能在局部位置。定义在方法中作用域就是该方法,块中也一样。
1.4 外部类想要访问局部内部类的成员
必须创建对象,再访问(且只能在作用域内创建)
1.5 外部其他类访问局部内部类
不能访问,因为局部内部类是一个局部变量,作用域只能在定义他的局部范围内。
1.6 如果外部类和局部内部类成员重名了访问规则
这时会采用就近原则,如果直接在内部类调用重名成员,使用的就是内部类的,如果想要调用外部类的就要使用
外部类名.this.外部成员名。
上面的内容在如下代码中展示:
public class Other{
public static void main(String[] args){
Outer outer = new Outer();
outer.method2();
}
}
class Outer{
private int a = 100; //外部类私有变量
private void method(){ //外部类私有变量
System.out.println("这是外部类的私有方法");
}
public void method2(){ //定义内部类的方法
class Inner{
int a = 300; //内部类中定义与外部类重名的变量
public void method3(){
method(); //访问外部类私有的成员
System.out.println("这是内部类的变量" + a );
System.out.println("这是外部类的变量" + Outer.this.a);
//这里访问的是外部类的变量
}
}
Inner inner = new Inner();
inner.method3();
}
}
程序运行结果如下:
这是外部类的私有方法
这是内部类的变量300
这是外部类的变量100
2、匿名内部类
匿名内部类是一个非常重要的概念,对于接口和抽象类来说,不能直接new他们的对象,每次想要实现接口(抽象类),必须new实现类(子类)对象,当我们只实现一次该接口(抽象类)时会很浪费,所以引出了匿名内部类的概念。可以直接new接口(抽象类)的"对象"具体语法如下:
public class Main{
public static void main(String[] args){
Interface tiger = new Interface(){
@Override
public void cry(){
System.out.println("老虎嗷嗷叫");
}
};
tiger.cry();
//因为new的是一个对象,我们可以不用对象名接收直接调用方法
new Interface(){
@Override
public void cry(){
System.out.println("狗汪汪叫");
}
}.cry();
}
}
interface Interface{
void cry();
}
程序运行结果:
老虎嗷嗷叫
在上面的代码中,我们直接new的接口名,后面重写了接口中的方法,这样就是匿名内部类实现接口。
当代码运行到
new Interface(){
@Override
public void cry(){
System.out.println("老虎嗷嗷叫");
}
}
的时候,其实底层实现了这样的过程:
class XXXX implements Interface{
@Override
public void cry(){
System.out.println("老虎嗷嗷叫");
}
}
并且这个XXXX就是Main$1 。这就是匿名内部类,只出现在底层,并且只出现一次,出现之后立马new了一个该类对象,然后就回收了。所以称之为匿名内部类,并非真正的匿名,而是只用一次,一次用完就没这个类了。
当对抽象类用匿名内部类new对象时:
public class Main{
public static void main(String[] args){
Inner inner = new Inner(){
@Override
public void method(){
System.out.println("重写后的方法")
}
};
inner.method();
Inner inner = new Inner(){
@Override
public void method(){
System.out.println("重写后的方法2")
}
}.method();
}
}
abstract class Inner{
public abstract void method();
}
程序运行结果:
重写后的方法
重写后的方法2
抽象方法使用匿名内部类和接口使用匿名内部类的方式是一样的。
匿名内部类的注意事项:
- 匿名内部类也是局部内部类
- 匿名内部类可以访问外部类所有成员
- 外部类访问匿名内部类需要new对象
- 外部其他类不能访问
- 匿名内部类既可以充当内部类,new内部类对象,也可以将自身作为对象直接调用方法。
- 当内部类成员与外部类成员重名时,采用就近原则,如果非要访问外部类的,那么使用
**外部类名.this.成员
三、成员内部类
成员内部类就是在一个类的成员位置上定义一个类。这个类是不可以用static修饰的,他在类中的地位不同于局部内部类和匿名内部类,它相当于一个"成员变量"。
定义语法如下:
class Outer{ //外部类
class Inner{ //成员内部类
}
}
class Main{ //外部其他类
}
由于成员内部类就是类中的一个成员,他的访问特点可以参照成员变量,成员方法 。关于成员内部类我总结了以下几点:
-
成员内部类是成员,可以添加权限修饰符,(public、protected、default、private)四种修饰符都可以。
-
成员内部类的作用域是整个类体。
-
成员内部类访问外部成员直接访问即可。
-
外部类访问成员内部类可以直接创建对象,通过对象名访问内部类。
-
使用外部其他类访问成员内部类时,有两种方式
- 直接创建对象访问:语法如下:
外部类名.内部类名 对象名 = 外部对象名.new 内部构造;
public class Main{ public static void main(String[] args){ Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); //这就是创建成员内部类对象 inner.method(); } } class Outer{ class Inner{ public void method(){ System.out.println("内部类方法"); } } }
程序运行结果:
内部类方法
- 第二种方法就是直接在外部类中定义一个返回值为内部类对象的方法,在该方法中直接创建一个内部类对象返回即可。在外部其他类中创建外部类对象,调用该方法即可。返回值接收用外部类名.外部类对象名接收
public class Main{ public static void main(String[] args){ Outer outer = new Outer(); Outer.Inner inner = outer.method2(); inner.method(); } } class Outer{ class Inner{ public void method(){ System.out.println("内部类方法"); } } public Inner method2(){ return new Inner(); } }
程序运行结果:
内部类方法
-
最后一条就是外部类成员与内部类重名时访问规则还是就近原则,如果想在内部类中优先访问外部类成员就要使用外部类名.this.成员名
四、静态内部类
静态内部类就是一个static修饰的成员内部类,静态内部类相当于类中一个静态的成员。
结构:
class Outer{ //外部类
static class Inner{ //静态内部类
}
}
class Main{ //外部其他类
}
静态内部类大部分特点与成员内部类相同,作用域为整个类,可以加权限修饰符。
但是静态内部类只能访问外部类中的静态成员。
外部类想访问静态内部类需要创建对象,再访问。
而外部其他类想访问静态内部类有两种方式:
- 直接通过外部类对象创建内部类对象:
外部类名.内部类名 内部类对象名 = new 外部类名.内部类名();
public class StaticInnerClass {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = new Outer.Inner();
inner.showA();
}
}
class Outer{
private static int a = 100;
static class Inner{
public void showA(){
System.out.println(a);
}
}
}
程序运行结果:
100
- 通过在外部类中创建方法,方法中创建静态内部类对象调用方法。如果是非静态方法,则创建外部类对象调用,如果是静态方法,使用外部类名直接调用。
public class Main{
public static void main(String[] args){
Outer outer = new Outer();
outer.method();
System.out.println("======================");
Outer.method2();
}
}
class Outer{
private static int a = 100;
static class Inner{
public void showA(){
System.out.println(a);
}
}
public void method(){
Inner inner = new Inner();
inner.showA();
}
public static void method2(){
Inner inner = new Inner();
inner.showA();
}
}
程序运行结果:
100
======================
100
当外部类和静态内部类成员出现重名时,采用就近原则。如果想要在静态内部类中访问外部重名变量,使用外部类名.成员名。