目录
前言:
内部类
什么是内部类?
内部类的分类
1、静态内部类
1、静态内部类,不能直接被实例化
2、 静态内部类当中,不能直接访问外部类的非静态成员,但是可以直接访问外部类的静态成员。
3、外部类可以访问静态内部类当中的所有成员
4、外部类以外的其他类需要通过完整的类名访问静态内部类的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类来实例。
2、非静态内部类/实例内部类
1、在实例内部类当中不能定义静态的成员变量
2、在外部类的静态方法和外部类以外的其他类中,在对实例内部类(InnerClass)经行实例化时,必须先要实例化外部类(OuterClass)
3、在外部类的普通方法中调用实例内部类的非静态成员变量,需要先实例化实例内部类,再通过内部类的引用调用非静态成员变量
4、在外部类的普通方法中调用实例内部类中的静态成员变量时,可以不用实例化实例内部类,可以直接用实例内部类的类名来调用。
5、如果实例内部类InnerClass和外部类OuterClass有同名的成员(data1),则在实例内部类InnerClass中data1和this.data1都表示实例内部类InnerClass的成员data1,而OutClass.this.data1表示外部类OutClass中的成员data1.
3、局部内部类
4、匿名内部类
前言:
内部类(Inner Class),是Java中对类的一种定义方式,是嵌套类的一个分类,即非静态嵌套类(Non-Static Nested Class)。内部类(非静态嵌套类)分为静态内部类,局部内部类、实例内部类和匿名内部类四种。
内部类
什么是内部类?
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整结构有值为外部事物提供服务,那么这个内部的完整结构最好使用内部类,在Java中,可以将一个类定义在另一个类或者一个方法的内部,前者称为内部类,后者称为外部类,内部类也是封装的一种体现。
可以这样理解:
将内部类和外部类可以想象成火车和车厢的关系:车厢内部可以构成一个类,火车可以构成一个类,车厢存在于火车里,所以可以理解为,内部类存在于外部内当中,为外部事物提供服务。
内部类的分类
1、静态内部类
被static修饰的内部成员类称为静态内部类。
1、静态内部类,不能直接被实例化
因为InnerClass内部类是属于OuterClass外部类的,所以在实例化的时候,需要用外部类OuterClass来调用。
public class Test {
public static void main(String[] args) {
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
}
}
2、 静态内部类当中,不能直接访问外部类的非静态成员,但是可以直接访问外部类的静态成员。
想要访问外部类当中的非静态成员,这需要通过对象的引用来访问。
public void func(){
OuterClass outerclass = new OuterClass();
System.out.println(outerclass.data1);
System.out.println(outerclass.data2);
}
3、外部类可以访问静态内部类当中的所有成员
原因就是外部类可以访问静态内部类当中的所有成员。
4、外部类以外的其他类需要通过完整的类名访问静态内部类的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类来实例。
package demo1;
//外部类
class OuterClass{
//内部类
static class InnerClass{
public int data4 = 4;
private int data5 = 5;
public static int data6 = 6;
}
}
public class Test {
public static void main(String[] args) {
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
//这里的语法规则和之前学习的语法相同
int a = innerClass.data4;//非静态成员在访问时,要通过对象的引用,因为非静态成员属于对象
int b = OuterClass.InnerClass.data6;//静态的成员在访问时,通过类名来访问,静态成员是属于类的
}
}
2、非静态内部类/实例内部类
即未被static修饰的成员内部类
1、在实例内部类当中不能定义静态的成员变量
如果非要定义,则可以加final关键字,将static修饰的变量改为常量。
package demo1;
class OuterClass2{
public int data1 = 1;
private int data2 = 2;
public static int data3 =3;
class InnerClass2{
public int data4 = 4;
private int data5 = 5;
//常量是在程序编译的时候 就能确定的
public static final int data6 = 6;
}
}
2、在外部类的静态方法和外部类以外的其他类中,在对实例内部类(InnerClass)经行实例化时,必须先要实例化外部类(OuterClass)
1、在外部类以外的其他类。
这里是通过外部类的对象调用"成员变量 (new InnerClass2();)",可以理解为:在创建外部类的对象时,内部类已经被创建,这里用外部类的引用来调用。
2、在内部类的静态方法中
3、在外部类的普通方法中调用实例内部类的非静态成员变量,需要先实例化实例内部类,再通过内部类的引用调用非静态成员变量
package demo1;
class OuterClass2{
public int data1 = 1;
private int data2 = 2;
public static int data3 =3;
class InnerClass2{
public int data4 = 4;
private int data5 = 5;
//常量是在程序编译的时候 就能确定的
public static final int data6 = 6;
}
public void func() {
InnerClass2 innerClass2 = new InnerClass2();
System.out.println(data1);
System.out.println(data2);
System.out.println(data3);
//通过实例化实例内部类来调用,InnerClass2类的对象的非静态成员变量
System.out.println(innerClass2.data4);
System.out.println(innerClass2.data5);
}
}
4、在外部类的普通方法中调用实例内部类中的静态成员变量时,可以不用实例化实例内部类,可以直接用实例内部类的类名来调用。
5、如果实例内部类InnerClass和外部类OuterClass有同名的成员(data1),则在实例内部类InnerClass中data1和this.data1都表示实例内部类InnerClass的成员data1,而OutClass.this.data1表示外部类OutClass中的成员data1.
ckage demo1;
//外部类
class OuterClass2{
public int data1 = 1;
private int data2 = 2;
public static int data3 =3;
//实例内部类
class InnerClass2{
public int data1 = 1111;
public int data4 = 4;
private int data5 = 5;
//常量是在程序编译的时候 就能确定的
public static final int data6 = 6;
public void func1(){
System.out.println(data1);
System.out.println("====="+this.data1);
System.out.println(data2);
System.out.println(data3);
System.out.println(data4);
System.out.println(data5);
System.out.println(data6);
}
}
public class Test2 {
public static void main(String[] args) {
OuterClass2 outerClass2 = new OuterClass2();
OuterClass2.InnerClass2 innerClass2 = outerClass2.new InnerClass2();
innerClass2.func1();
}
}
package demo1;
//外部类
class OuterClass2{
public int data1 = 1;
private int data2 = 2;
public static int data3 =3;
//实例内部类
class InnerClass2{
public int data1 = 1111;
public int data4 = 4;
private int data5 = 5;
//常量是在程序编译的时候 就能确定的
public static final int data6 = 6;
public void func1(){
System.out.println(data1);
//输出外部类当中的data1
System.out.println("===="+OuterClass2.this.data1);
System.out.println(data2);
System.out.println(data3);
System.out.println(data4);
System.out.println(data5);
System.out.println(data6);
}
}
【注意事项】
1、外部类中的任何成员都可以在实例内部类方法中直接访问
2、实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
3、在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名称.this.同名成员 来访问
4、实例内部类对象必须在现有外部类对象前提下才能创建
5、实例内部类的非静态方法中包含了一个指向外部类对象的引用
6、外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。
7、实例内部类中不能定义静态成员,只能定义实例成员,否则编译无法通过
8、实例内部类的class文件名为:外部类名$内部类名.class
3、局部内部类
也称为方法中的内部类,定义在方法中。
class OutClass3{
public void func(){
class InnerClass3{
public int a = 1;
public void test() {
System.out.println("hello!");
}
}
InnerClass3 innerClass3 = new InnerClass3();
innerClass3.test();
}
}
public class Test2 {
public static void main(String[] args) {
OutClass3 outClass3 = new OutClass3();
outClass3.func();
【注意事项】
1、由于外部完全不能访问局部内部类,因而他们不能被访问权限修饰符修饰、也不能定义为static
2、定义局部内部类的好处时可以访问外部类中的成员,还可以访问所在方法中的局部变量,如方法的形式参数,方法体中的局部变量,但是不能修改这些局部变量
3、在方法中定义的局部变量在方法结束之后,生命周期结束,不能再被访问
4、方法中的内部类class文件名为:外部类$.编号内部类名.class
4、匿名内部类
正常情况下,我们写代码是这样的
interface IA{
public void func();
}
class AA implements IA{
@Override
public void func() {
System.out.println("hello!");
}
}
public class Test2 {
public static void main(String[] args) {
IA ia = new AA();
ia.func();
}
}
但是匿名内部类是这样写的
interface IA{
public void func();
}
public class Test2 {
public static void main(String[] args) {
new IA(){
@Override
public void func() {
System.out.println("hello::");
}
}.func();//想要调用func方法,要这样写new IA(){}.func();
}
//main方法中表示的意思是:有一个类实现了IA这个接口,并且重写了接口中的方法,但是这个类没有名字,所以就叫做匿名内部类
结果
但是main方法中的写法,和我们用类实现接口的方法效果是一样的。
【注意事项】:
1、匿名内部类必须继承一个父类,或者实现一个接口,但最多只能实现一个接口。
2、匿名内部类由于没有名字,因而无法定义构造方法,编译程序会自动生成它的构造方法,并在其中自动调用其父类的构造方法
3、匿名内部类访问局部变量只能读取不能修改
4、匿名内部类可以访问外部类的所有成员
5、匿名内部类的class文件名为:外部类名$编号.class