菜鸟笔记
提升您的技术认知

Java内部类 (详细讲述java内部类)

基本介绍

一个类的内部又完整的嵌套了另一个结构,被嵌套的类称为 内部类(inner class),嵌套其他类的类称为 外部类 (outer Class),是我们类的第五大成员,内部类可以直接访问其外部类的私有属性。

类的五大成员

1.属性
2.方法
3.构造器
4.代码块
5.内部类

局部内部类

局部内部类是定义在外部类的方法内的

说明:

1.可以直接访问外部类的所有成员,包括私有属性私有方法
2.局部内部类不可以添加访问修饰符,因为他相当于一个局部的变量,局部变量本来就是不可以使用修饰符的
3.作用域:只定义它的方法或者代码块中(和局部变量一样)
4.局部内部类访问其外部类的成员可以直接访问,但是外部类访问局部类的成员需要创建对象进行访问并且必须在定义它的方法内

例子:

 package code04;
 import com.sun.org.apache.bcel.internal.classfile.Code;
 
 public class Test {
     public static void main(String[] args) {
         Code01 code01 = new Code01(); //创建外部类对象
         code01.cry();//调用外部类cry方法
     }
 }
 class Code01{
     public void  cry(){
         class Name{ //定义内部类 Name
             public void cry(){
                 System.out.println("这是内部类的cry方法");
             }
         }
         Name name = new Name();//创建局部内部类对象
         name.cry();//调用局部内部类对象
     }
 
 }

输出:

 这是内部类的cry方法

不知道兄弟们有没有好奇过正常类的在java中编译应该就是类名
那么局部内部类的类名按照思路就是它定义的类名
不过真的是这样吗?
我们都知道实例化后对象通过getClass可以看到它的类名
在外部类的cry方法中加上一行

   package code04;
   import com.sun.org.apache.bcel.internal.classfile.Code;
    public class Test {
        public static void main(String[] args) {
            Code01 code01 = new Code01(); //创建外部类对象
            code01.cry();//调用外部类cry方法
        }
    }
    class Code01{
        public void  cry(){
            class Name{ //定义内部类 Name
                public void cry(){
                    System.out.println("这是内部类的cry方法");
                }
            }
            Name name = new Name();//创建局部内部类对象
            name.cry();//调用局部内部类对象
            System.out.println("内部类的地址" + name.getClass());
        }
    
    }

输出:

    内部类的地址class code04.Code01$1Name

我们会发现它是一个外部类名+$1+局部内部类名的一种方式那么兄弟们如果再定义一个局部内部类呢 其实是一个外部类名+$2+局部内部类名的名字这个是java自己在内部定义的

属性方面:

如果局部内部类和外部类的属性重名了怎么办?他会输出什么?

上代码:

package code04;
 
import com.sun.org.apache.bcel.internal.classfile.Code;
 
public class Test {
     public static void main(String[] args) {
         Code01 code01 = new Code01();
         code01.cry();
     }
 }
 
class Code01{
     public int age = 100;//定义外部类属性
     public void  cry(){
         class Name{
             public int age = 200;//定义局部内部类属性
 
              public void cry(){
                 System.out.println("这是内部类的cry方法");
                 System.out.println("age" + age);
 
             }
         }
 		 Name name = new Name();
         name.cry();
         System.out.println("内部类的地址" + name.getClass());
     }
 
 
 }

在上面我定义了两个相同的属性age 外部的值为100 内部的为200

输出:

age200

这是因为局部内部类就近原则导致的如果我们想访问外部的属性可以通过 外部类名.this.属性访问

 System.out.println("外部类age"+Code01.this.age + "内部类的age" + age);

打印:

 外部类age100内部类的age200

匿名内部类:

  • 它与局部类很相似,不同的是它没有类名,如果某个局部类你只需要使用一次,就可以使用匿名类代替局部类。
  • 匿名类是表达式,而非常规的类
  • 匿名内部类定义在外部类的局部位置,比如方法中,正如名字所说匿名,匿名内部类没有名字它的本质是一个对象
  • 匿名类可以使你的代码更简洁,可以理解为其实就是一个表达式

通过一个例子可以看到体会到局部内部类和匿名内部类的区别以及匿名内部类的简洁

 package code04;
  
 public class Interface09 {
      public static void main(String[] args) {
          TestGood testGood = new TestGood();
          testGood.getCode01();
  
      }
  }
 interface code01{ //接口类code01
      void cry(); 
  }
  class TestGood { //外部类
      public void getCode01(){ //方法
          class Inside implements code01{ //局部内部类实现接口从de
              @Override
              public void cry() {
                  System.out.println("这是局部内部类实现接口code01 cry方法");
              }
          }
          Inside inside = new Inside();//创建实现接口的对象
          inside.cry(); //调用重写的方法
          code01 inter = new code01(){ //匿名类实现接口方法
              @Override
              public void cry() {
                  System.out.println("这是匿名类实现接口cry方法");
              }
          };
          inter.cry();//调用匿名类方法
      }
  }

输出:

    这是code01 cry方法
    这是匿名类实现接口cry方法

局部内部类和匿名类的区别:

局部内部类有自己的类名 需要先实例化对象再调用方法
匿名类直接使用调用方法(在定义的时候已经完成实例化)并且内部类必须以;结尾

再实现一个例子加深理解

package code04;
 
public class Interface09 {
     public static void main(String[] args) {
         code01 inside = new code01() { //定义一个匿名类
             String name = "Tom";//定义一个name属性
 
             @Override
             public void cry() {
                 System.out.println("cry方法");
             }
 
             @Override
             public void getName() { //重写实现接口的getName
                 System.out.println(name);
             }
 
             code01 setName(String name) { //匿名对象的setName方法
                 this.name = name;
                 return this;
             }
         }.setName("Lili");//这里调用setName方法传递了name值为Lili所以值做变化了
         inside.getName();
     }
 }
 interface code01{ //接口类code01
     void cry();
     void getName();
 }

结果:

    Lili

继承父类的匿名类:

package code05;    

public class Test {
        public static void main(String[] args) {
            String name = "lili";
            Cat cat = new Cat();
            System.out.println("cat类的name = " + cat.getName());
            Cat inside = new Cat(name) {
                @Override
                public String getName() {
                    return super.getName();
                }
            };
            System.out.println("匿名类继承父类的name = " + inside.getName());
        }
    }
    
class Cat {
    String name = "tom";

    public Cat(String name) {
        this.name = name;
    }

    public Cat() {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

打印结果:

    cat类的name = tom
    匿名类继承父类的name = lili

上面创建匿名类是继承了父类并实例化 将带参数的构造器赋值给了name属性
调用getName得到了传入赋值的新name属性