一:基本介绍

一个类的内部又完整的嵌套了另一个类结构,被嵌套的类成为内部类
嵌套其他类的类称为外部类( outer class )。是类的第五大成员。 :::danger 类的五大成员!!!!!
属性,方法,构造器,代码块,内部类 ::: 内部类的最大特点是可以直接访问私有属性,迫切可以直接提现类与类之间的包含关系
在看底层源码时,有大量的内部类

1:内部类的分类

  • 定义在外部类局部位置上
    • 局部内部类
    • 匿名内部类
  • 定义在外部类的成员位置上
    • 成员内部类(没用static修饰)
    • 静态内部类(使用static修饰)

      四:局部内部类的使用

      :::danger 局部内部类是定义在外部类的局部位置,比如方法中,并且有类名 :::
  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,但是可以使用final修饰,因为局部变量也可以使用final
  3. 作用域:仅仅在定义他的方法或者代码中
  4. 局部内部类可以直接访问外部类的成员
  5. 外部类 —> 访问 —> 局部内部类的成员
    1. 访问方式:创建对象,再访问,(注意必须在作用域中)作用域:定义的方法或者代码块中。
  6. 外部其他类不能访问局部内部类(因为局部内部类是一个局部变量) ```java public class InnerCLass { public static void main(String[] args) {

    1. Outer outer = new Outer();
    2. outer.Sakura();
    3. //执行sakura()方法时,在方法体内定义局部内部类
    4. //定义完之后再执行下面的创建对象

    }

} class Outer { //外部类 private int n1 = 10; //属性

  1. private void Test(){ //私有方法
  2. System.out.println("Test方法");
  3. }
  4. public void Sakura(){ //方法
  5. //可以用final修饰
  6. final class Inner{ //局部内部类
  7. private int n1 = 100;
  8. public void F(){
  9. //局部内部类:访问--> 外部类的成员
  10. //[ 访问方式:直接访问 ]
  11. System.out.println(n1);
  12. Test();
  13. //如果有重名的,就近原则
  14. //若想访问外部类的成员使用:外部类名.this.成员
  15. //因为外部类名.成员 只有在静态的时候才这样
  16. //非静态,非共有。需要加this表明是这个对象的属性
  17. System.out.println("内部类的成员"+ n1);
  18. System.out.println("外部类的的n1" + Outer.this.n1);
  19. }
  20. }
  21. //外部类在局部内部类作用域(定义局部内部类-的方法体或者代码块)
  22. //中,可以创建对象,然后调用方法即可
  23. Inner inner = new Inner();
  24. inner.F();
  25. }

}

  1. <a name="Bxmuj"></a>
  2. ### 五:匿名内部类
  3. <a name="kbDUw"></a>
  4. #### 1:基本使用
  5. 1. 本质是类
  6. 2. 内部类
  7. 3. 该类没有名字
  8. 4. 同时还是一个对象
  9. :::danger
  10. 说明:匿名内部类是定义在外部类的局部位置,比如方法中并且没有类名
  11. :::
  12. ```java
  13. public class AnonymousInnerClass {
  14. public static void main(String[] args) {
  15. outer outer = new outer();
  16. outer.method();
  17. }
  18. }
  19. class outer{
  20. private int n1 = 10;
  21. public void method(){
  22. //需求:使用A接口,并创建对象
  23. //传统写法:创建类实现接口,创建对象调用方法
  24. // A cat = new cat();
  25. //cat.cry();
  26. //需求:类只使用一次,后面不在使用
  27. //使用匿名内部类
  28. //编译类型:A 运行类型:匿名内部类 Onter&1
  29. //底层
  30. /*
  31. class Outer04$1 implements IA {
  32. @Override public void cry() {
  33. System.out.println("猫叫了");
  34. }
  35. }
  36. */
  37. //jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例
  38. //并且把地址返回给 tiger
  39. A cat = new A(){
  40. @Override
  41. public void cry() {
  42. System.out.println("猫叫了");
  43. }
  44. };
  45. //通过getclass来查看当前的运行类型
  46. System.out.println("Cat的运行类型:"+ cat.getClass());
  47. cat.cry();
  48. }
  49. }
  50. interface A{
  51. public void cry();
  52. }
  53. /*class cat implements A{
  54. @Override
  55. public void cry() {
  56. System.out.println("猫叫了");
  57. }
  58. }*/
  59. class father{
  60. public father(String name) {
  61. System.out.println("接收到name"+ name);
  62. }
  63. }

2:匿名内部类的细节

  • 匿名内部类即时一个类的定义,同时也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征。

    1. public class TestClass {
    2. public static void main(String[] args) {
    3. Test T = new Test();
    4. T.A();
    5. }
    6. }
    7. class Test{
    8. //创建一个基于类的匿名对象
    9. public void A(){
    10. //第一种匿名内部类创建方法
    11. Person person = new Person(){
    12. @Override
    13. public void speak() {
    14. System.out.println("重写Person里的speak方法");
    15. }
    16. };
    17. person.speak(); //动态绑定 运行类型是Test&1
    18. //第二种匿名内部类创建方法
    19. //底层 class 匿名内部类 extends Person
    20. new Person(){
    21. @Override
    22. public void speak() {
    23. System.out.println("重写Person里的speak方法");
    24. }
    25. @Override
    26. public void eat(String name) {
    27. // super.eat(name); 调用父类也就是Person的eat方法
    28. System.out.println(name+"吃饭了");
    29. }
    30. }.eat("sakura");
    31. }
    32. }
    33. class Person{
    34. public void speak(){
    35. System.out.println("人说话");
    36. }
    37. public void eat(String name){
    38. System.out.println("人吃饭");
    39. }
    40. }

    :::danger 其他和局部内布类一样:

  • 可以直接访问外部类的所有成员,包含私有的

  • 不能添加访问修饰符,因为它的地位就是一个局部变量
  • 作用域:仅仅在定义它的方法或代码块
  • 匿名内部类—-访问——>外部类成员
  • 外部其他类—- 不能访问——->匿名内部类(因为匿名内部类地位是一个局部变量)
  • 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问 :::

    六:匿名内部类的最佳实践

    1:当做实惨传递

    ```java public class Test00 { public static void main(String[] args) {

    1. //当做实惨直接传递,简洁高效
    2. Test(new AA() {
    3. @Override
    4. public void eat() {
    5. System.out.println("人吃饭");
    6. }
    7. });
    8. //传统方法
    9. Test(new Person());

    }

    public static void Test(AA aa){

    1. aa.eat();

    } }

interface AA{ public void eat(); }

//传统方法 class Person implements AA{ @Override public void eat() { System.out.println(“吃饭吃饭吃饭”); } }

  1. <a name="Inq7H"></a>
  2. ##### 2:
  3. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2595924/1660632068047-a99a4e4b-623b-4027-9081-76956a4e9cb5.png#clientId=u7e033b8d-da80-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=268&id=u644d0e86&margin=%5Bobject%20Object%5D&name=image.png&originHeight=268&originWidth=594&originalType=binary&ratio=1&rotation=0&showTitle=false&size=241819&status=done&style=none&taskId=u4592abb6-d889-418f-bba1-83dfeb76050&title=&width=594)
  4. ```java
  5. public class Test01 {
  6. public static void main(String[] args) {
  7. Cellphone cellphone = new Cellphone();
  8. //1. 传递的是实现了 Bell 接口的匿名内部类 InnerClassExercise02$1
  9. // 2. 重写了 ring
  10. //Bell bell = nee Bell(){
  11. // @Override
  12. // public void Ring() {
  13. // System.out.println("起床了");
  14. // }
  15. //}
  16. cellphone.alarmClock(new Bell() {
  17. @Override
  18. public void Ring() {
  19. System.out.println("起床了");
  20. }
  21. });
  22. cellphone.alarmClock(new Bell() {
  23. @Override
  24. public void Ring() {
  25. System.out.println("不起床");
  26. }
  27. });
  28. }
  29. }
  30. interface Bell {
  31. public void Ring();
  32. }
  33. class Cellphone{
  34. public void alarmClock(Bell bell){
  35. bell.Ring();
  36. }
  37. }

七:成员内部类的使用

:::danger 说明:成员内部类定义在外部类的的成员位置,并且没有static修饰 :::

  1. 可以直接访问外部类的所有成员,包含私有的属性
  2. 可以添加任意访问修饰符
  3. 作用域
    1. 和外部类的其他成员一样,为整个类体。
  4. 成员内部类访问外部类对象(比如:属性)
    1. 访问方式:直接访问
  5. 外部类访问成员内部类
    1. 访问方式:创建对象,再访问
  6. 外部其他类访问 ```java public class Test02 { public static void main(String[] args) {

    1. Outer outer = new Outer();
    2. outer.UseInnerClass();
    3. //外部其他类访问成员内部类的三种方式
    4. //(前提要先创建外部类)
    5. //第一种
    6. outer.new Inner();//new Inner()当做是 outer 成员
    7. Outer.Inner inner = outer.new Inner();
    8. //第二种 在外部类中编写一个方法,可以返回Inner对象
    9. //接收通过InnerInstance返回的Inner对象
    10. Outer.Inner innerInstance = outer.getInnerInstance();

    } }

class Outer{ //外部类 private int Num = 10; private void Test(){ System.out.println(“外部类的Test方法”); } public class Inner{ //成员内部类 //可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员 private int Num = 100; public void Say(){ System.out.println(“外部类的Num:”+ Outer.this.Num); System.out.println(“成员内部类Num:” + Num); } } //使用成员内部类 //通过写方法,创建成员内部类的对象,然后使用相关的方法 public void UseInnerClass(){ Inner inner = new Inner(); inner.Say(); } public Inner getInnerInstance(){ //返回一个Inner实例,但是没有对象接收 return new Inner(); } }

  1. <a name="SLwM1"></a>
  2. ### 七:静态内部类的使用
  3. :::danger
  4. **_说明:静态内部类是定义在外部类的成员位置,并且有static修饰_**
  5. :::
  6. 1. **_可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员_**
  7. 2. **_可以添加任意访问修饰符(pubic,protected,默认,private)因为它的地位就是一个成员_**
  8. 3. **_作用域:_**
  9. 1. **_同其他的成员一样,为整个类体_**
  10. 4. **_静态内部类访问外部类(比如:静态属性)_**
  11. 1. **_访问方式:直接访问所有静态成员_**
  12. 5. **_外部类访问静态内部类_**
  13. 6. **_外部其他类范文静态内部类_**
  14. 7. **_如果外部类和静态内部类的成员,泽可以使用(外部类。成员)去访问_**
  15. ```java
  16. public class Tets00 {
  17. public static void main(String[] args) {
  18. Outer outer = new Outer();
  19. outer.UseInnerClass();
  20. //第一种:
  21. //因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
  22. Outer.Inner inner = new Outer.Inner();
  23. //第二种
  24. //编写一个方法,可以返回静态内部类的对象实例.
  25. Outer.Inner inner1 = outer.getInner();
  26. }
  27. }
  28. class Outer{ //外部类
  29. private static int Num = 10;
  30. private void Test(){
  31. System.out.println("外部类的Test方法");
  32. }
  33. public static class Inner{ //成员内部类
  34. //可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
  35. private int Num = 100;
  36. public void Say(){
  37. System.out.println("外部类的Num:"+ Outer.Num);
  38. System.out.println("成员内部类Num:" + Num);
  39. }
  40. }
  41. //外部类访问静态内部类
  42. //通过写方法,创建成员内部类的对象,然后使用相关的方法
  43. public void UseInnerClass(){
  44. Inner inner = new Inner();
  45. inner.Say();
  46. }
  47. public Inner getInner(){
  48. //返回一个Inner实例,但是没有对象接收
  49. return new Inner();
  50. }
  51. }

:::danger 非静态成员内部类创建对象
new Inner( )当做是 outer 成员
Outer.Inner inner1 = outer.new Inner( );
静态成员内部类创建对象
因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer.Inner inner2 = new Outer.Inner( ); :::

七:练习

  1. public class Test {//外部类
  2. public Test() {//构造器
  3. Inner s1 = new Inner();
  4. s1.a = 10;
  5. Inner s2 = new Inner();
  6. System.out.println(s2.a);
  7. }
  8. class Inner { //内部类,成员内部类
  9. public int a = 5;
  10. }
  11. public static void main(String[] args) {
  12. Test t = new Test();//5
  13. //正常情况是要应该是Test.Inner
  14. Inner r = t.new Inner();
  15. System.out.println(r.a);//5
  16. }
  17. }