java基础系列(七):内部类的详解

为什么使用java内部类?

使用内部类的一个主要原因:每个内部类都能独立的继承一个类(接口),无论外围类是否已经继承某个类,对内部类没有任何的影响。

使用内部类的优点:它能非常好的解决多重继承的问题,提供了更好的封装,除了外围类,其他的类都不能访问。

内部类的使用:

内部类的使用方式有四种:成员内部类,静态内部类,局部内部类,匿名内部类。接下来分别看一下,内部类的使用方式。

1.成员内部类

public class Outer{
        public String name;
        public class Inner{
        public int age;
        public int info(){
          System.out.println("我的年龄是:"+age);
        }
     } }

注意:

  1. 成员内部类定义在外部类的内部,相当于外部类的一个成员变量的位置,内部类可以像类属性那样被访问控制符修饰。
  2. 内部类可以访问外部类的成员,而不受任何访问控制符的限制,包括直接访问外部类的私有属性。
  3. 创建内部类对象,外部类.内部类 对象名=外部类对象.new 内部类();
  4. 内部类不能存在任何static的变量和方法,可以定义常量。因为静态变量或方法依赖类,不依赖于实例变量,但是内部类是依赖于外部类的实例对象的,这样的话就会产生一个矛盾,编译器不会编译的。
  5. 如果内部类和外部类具有相同的成员变量和方法,内部类默认访问自己的成员变量或方法,如果访问外部类的成员变量,使用这种方式:外部类.this.name。

问题:为什么成员内部类可以直接访问外部类的属性或方法呢?

  java文件被编译之后,内部类会持有一个外部类的隐式引用,这个引用是编译过程中添加进去的。编译的时候,编译器会给内部类的构造器添加一个外部类的引用,无论使用有参构造器或是无参构造器,这样内部类就可以访问外部类的属性或者方法。这也从侧面说明成员内部类是依赖于外部类的。

2.静态内部类

public class Outer{
        public String name;
        public static class Inner{
        public int age;
        public int info(){
          System.out.println("我的年龄是:"+age);
        }
     }
}
  1. 静态内部类不能直接访问外部类的非静态成员,但是可以通过new 外部类().成员的方式访问
  2. 如果外部类的静态成员与内部类的成员名称相同,可通过类名.静态成员访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过成员名直接调用外部类的静态成员。
  3. 创建静态内部类的对象时,不需要外部类的对象,可以直接创建:内部类 对象名 = new 内部类()

3.局部内部类

public class Outer{
        public String name;
        public void showinfo(){
                class Inner{
        public int age;
        public int info(){
          System.out.println("我的年龄是:"+age);
        }
     }
 
        }
        
}
  1. 局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的
  2. 局部内部类只能访问局部final变量,尽管jdk1.8不需要final显式的修饰局部变量,但是编译器仍然是按final变量进行编译的,这点可以通过反编译验证。这个在编译内部类的时候,如果局部变量的值在编译期间可以确定,则会在内部类创建一个拷贝(基本数据类型),如果局部变量的值是无法在编译期间确定,则通过构造器传参的方式来对拷贝进行初始化赋值。使用的形参为什么要用final呢?在内部类中的属性和外部方法的参数两者从外表上看使用一种东西,但是内部类只是持有的一个变量的拷贝而已,内部类属性的改变不会影响到外部形参,但是从程序员的角度看,这就是同一个变量,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。

4.匿名内部类

public class Outer{
        public String name;
        public getInner(){
                return new Innter(){
                        public int getNumber(){
                             return 123;
                        }
                };
        }
        interface Inner{
              int getNumber();
       }
        
}
  1. 匿名内部类它仅能被使用一次,创建匿名内部类时他会立即船舰一个该类的实例,该类的定义会立即消失。
  2. 使用匿名内部类我们必须继承一个类或实现一个接口,且只能继承一个类或实现一个接口。
  3. 匿名内部类是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法。
  4. 匿名类初始化:使用构造器代码块,利用构造代码块能够达到为匿名内部类创建一个构造器的效果。
posted @ 2020-07-29 11:07  J-mo-太阳  阅读(120)  评论(0编辑  收藏  举报