Java内部类(详细版)

1.内部类的概念

将一个类定义在另一个类的里面或者定义在一个方法的内部,把该类就称之为内部类;内部类也是对封装的一种体现。

public class A {
    // A 就称为外部类
    // B 就称为内部类
    class B{
    }
}

需要注意的是

(1)定义在class 类名{}花括号外部的,即使是在一个文件里,也不能称为内部类;

// 同一个Java源文件中可以有多个类
// 但这种方式不能被称为内部类
// 最多只有一个被public修饰
public class Test{

}
class B{

}

就如同 TestB 就是两个独立的类,彼此之前并没有关系;
(2) 内部类和外部类共用同一个java的源文件,但是经过编译之后,内部类会形成自己单独的字节码文件;

就如同定义里面的类A类B,在经过编译之后,就会产生两个字节码文件。

如下所示
在这里插入图片描述

2.内部类的分类及范例

根据内部类定义位置的不同,可以将内部类分为成员内部类局部内部类匿名内部类,而成员内部类又根据是否被static修饰分为普通内部类静态内部类

2.1 成员内部类

2.1.1 普通内部类

未被static修饰的成员内部类就称为普通内部类;

      // 测试普通内部类
public class TestInnerClass {
  //外部类的成员变量:a,b
    int a;
    int b;
    public void methodA(){
    //methodB() ; 编译失败 原因:外部类不能直接访问内部类成员
        //外部类若要访问内部类成员,
        //1)先创建内部类对象;2)通过该对象访问内部成员
        InnerClass ic=new InnerClass();
        ic.methodB();

    }
    //成员内部类:普通内部类
    class InnerClass{
    //内部类的成员变量:b,this&0(编译器添加的),将来指向外部类对象
        int b;
        void methodB(){
            a=10;
            methodA();

            b=20;   //给内部类自己的成员变量赋值(就近原则)
    // 当内部类成员变量与外部类成员变量相同名字时,
     //如何给外部的b赋值?
            TestInnerClass.this.b=200;
        }
    }

    public static void main(String[] args) {
        // 如何使用普通内部类
        //先创建对象ti,通过对象访问内部成员
        TestInnerClass ti=new TestInnerClass();
        ti.methodA();

        // InnerClass ic=new InnerClass(); 编译失败
        // 只能通过借助外部类的对象来创建内部类的对象
        InnerClass ic=ti.new InnerClass();
        ic.methodB();
    }
}

当打断点运行时,就可以看见如下所示界面,有创建的两个对象tiic,在程序的外部类中,我们定义了两个成员变量ab,在内部类中,我们自己只定义了一个b,但我们却看到了两个,多的那个this&0就是编译给我们自动添加的,用来指向外部类的对象(即:编译器会给内部类维护一个外部类对象的引用)(可能有点绕)


从上面可得到以下:
(1)外部类中的任何成员都可以在普通内部类方法中直接被访问

(2)普通内部类所处的成员与外部类成员位置相同,因此也受public、private等访问限定符的约束

(3) 在内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员需采用

外部类名称.this.同名成员名 

(4)普通内部类对象必须在先有外部类对象前提下才能被创建

(5)外部类中不能直接访问内部类中的成员,如果要访问必须先要创建内部类的对象

2.1.2 静态内部类

static修饰的内部成员类就称为静态内部类;

//测试静态内部类
public class OutClass {
    private int a;
    //静态成员变量b
    static int b;
    
    public void methodA(){
        a=10;
        System.out.println(a);
    }

    public static void methodB(){
        System.out.println(b);
    }

// InnerClass 就是静态内部类
    static class InnerClass{
        public void methodInner(){
            // 在内部类中只能访问外部类的静态成员变量及方法
           // a=100; 编译失败,原因:a不是外部类中的静态成员变量
         // methodA(); //编译失败,原因:methodA()不是静态类成员方法
             b=100;
            methodB();
        }
    }

    public static void main(String[] args) {
        //静态成员变量访问:类名.成员变量名
           System.out.println(OutClass.b);
           
        // 静态内部类对象的创建
        //不需要借助外部类对象 
        InnerClass ic=new InnerClass();
        // 静态成员方法访问
        innerClass.methodInner();
    }
}

运行结果

0
100

由上我们可以知道:

(1) 在内部类中只能访问外部类中的静态成员(包括静态成员变量和静态成员方法)

(2)创建内部类对象时,不需要先创建外部类对象

(3) 成员内部类,经过编译之后会生成独立的字节码文件,命名格式为:外部类名称$内部类名称;

2.2 局部内部类(不常用)

定义在外部类的方法体或者代码块{}中,该种内部类只能在其定义的位置进行使用,其他位置均不能使用;

//测试局部内部类
public class OutClass {
    int a=20;
    public void method(){
        int b=10;
        // InnerClass 就是局部内部类
        //  定义在外部类(OutClass)的(method)方法体中
        class InnerClass{
            //static int c;  编译失败 不能在局部内部类中定义静态成员
            public void methodInnerClass(){
                System.out.println(a);
                System.out.println(b);
            }
        }
        // 只能在该方法体内部使用,其他位置不行
        InnerClass innerClass=new InnerClass();
        innerClass.methodInnerClass();
    }

    public static void main(String[] args) {
      //  OutClass.InnerClass.ic=null; 
      // 编译失败,原因是:在外部使用了局部内部类
    }
}

局部内部类不能被publicstatic等访问限定符修饰,若加上修饰符,就会报错,光标点上去之后会显示提示信息,提示信息如下所示:

在这里插入图片描述

由上面可以知道:

(1)局部内部类只能在所定义的方法体内部使用
(2)不能被public、static等修饰符修饰
(3)不能在局部内部类中定义静态成员

2.3 匿名内部类

匿名内部类属于局部内部类,不同的是,它是没有名字的局部内部类,通常和匿名对象一起使用,(接口部分为大家仔细介绍该类的使用);

2.4 对象打印(补充一个)

对于私有的成员变量,我们都需要提供SetGet的访问方式,当私有成员较多时,可以采用IDEA直接生成,生成方式:alt+insert+Setalt+insert+Get

打印时:

(1)基本类型打印:结果为设定的值;
(2)引用类型打印:打印的是相当于对象的地址,而不是对象本身;

范例定义一个Person类

public class Person {
    String name;
    private String gender;
    private int age;

    public Person(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public static void main(String[] args) {
        //基本类型
        int a=10;
        System.out.println(a);
        //引用类型
        Person p=new Person("韩磊","男",13);
        System.out.println(p);

    }
}

运行结果:

10
day20210913.Person@1b6d3586

如果想要打印对象中内容,如该如何处理呢?

方法: 重写 toString()
快捷键:(alt+insert+toString)

使用toString()后,再次运行,结果如下

10
Person{name='韩磊', gender='男', age=13}

欢迎批评指正!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值