[Java基础] 外部类, 内部类

2019-10-01  本文已影响0人  LCN233
Alt 'Java 类'

外部类

我们在创建类的时候,创建的 .java 文件(源文件)的文件名必须和我们要创建的类的名字一样。而这个我们创建的类,就是外部类, 也叫顶级类。

做一点引申:

  1. 在一个源文件里面,可以有很多个顶级类, 但是这些顶级类只有和文件名一样的顶级类才能被 public 修饰, 只有一个,其他的都只能用默认(什么都不加)进行修饰。
  2. 同一个源文件里面的多个顶级类,因为只有一个可以被 public 修饰,所以导致其他的顶级类,只能在当前包路径下使用。
  3. 《Effective Java, Third Edition》第25条建议: 每个源文件只对应一个顶级类

内部类

又称之为嵌套类,是在类中在定义另外一个类,这个类可以在顶级类里面的任意地方

1. 静态内部类

public class OutClass {
    public static class InnerClass {  
    }
}

直接在顶级类的内部声明, 通过 static 进行修饰的类

特点:

  1. 所有的权限修饰符都可以进行修饰
  2. 能够在类能定义静态属性和方法
  3. 只能使用外部类的静态属性和方法
  4. 在其他类里面调用静态内部类(静态内部类与外部类没有关系, 在编译后,就是2个普通的类)
OutClass.StaticInnerClass innerClass = new OutClass.StaticInnerClass();

2. 非静态内部类

1. 成员内部类

public class OutClass {
    public class InnerClass {
    }
}

在顶级类的直接内部,和类的属性同级

特点:

  1. 所有的权限修饰符都可以进行修饰
  2. 不能够在类内定义静态属性和方法
  3. 能够访问外部类的所有属性和方法, 包括静态的
  4. 在其他类里面调用成员内部类(成员内部类对象会隐式的引用一个外部类对象, 也就是2者之间有联系)
OutClass outClass = new OutClass();
// 需要先创建出外部类的实例,通过实例才能创建内部类
OutClass.InnerClass innerClass = outClass.new InnerClass();

2. 局部内部类

public class OutClass {
   public void fn() {
       class InnerClass {
       }
   }
}

声明在顶级类的某个作用域内(方法体内, if 判断里面等)

特点:

  1. 这个类只能使用默认权限修饰符, 不能被其他的权限修饰符修饰
  2. 不能够在类内定义静态属性和方法
  3. 可以访问到外部类的属性和方法,包括静态的
  4. 在其他类是无法调用到局部内部类的
  5. 局部类只能在对应的作用域起作用, 超出了对应的作用域就没了,所以无法被其他的类调用

3. 匿名内部类

public class OutClass {
    public void fn() {
       /**
        *     创建格式:
        *     new 父类/接口(参数列表) {
        *     }
        */
        new Thread(new Runnable() {
          @Override
          public void run() {
          }
        });
    }
}

在顶级类的某个作用域内, 直接创建使用, 没有进行具体的声明

特点:

  1. 匿名内部类为局部内部类的特例, 具备局部内部类的特点

内部类如何访问外部类的同名方法/属性

内部类的属性, 方法和外部类的重名了,在调用时,优先使用内部类的, 同时可以通过外部类.this.方法/属性,访问到外部类的同名方法/属性

局部内部类访问方法体内入参/变量的条件

  1. 局部内部类可以访问方法内的局部变量和入参,但是前提是这个变量和入参在这个方法体内是被 final 修饰过的。
  2. 在 jdk8 中, 可以直接声明后使用,只要你保证你的入参/变量满足 Effectively final

注: Effectively final 是 jdk8 新增的一个特性。(对于一个变量,如果没有给它加final修饰,而且没有对它的二次赋值,那么这个变量就是effectively final(有效的不会变的)。简单的来说,我们在方法 fn 里面声明了一个 变量 int a = 1; 在这个方法体内,除了第一次声明外,没有别的地方对其进行了修改, 他就是 effectively final

public class OutClass {

  public void fn() {
    int a = 123;

    class InnerClass {
      public void innerFn() {
        // 内部类 调用 外部的变量, 在 jdk8 之前, a 必须用 final 继续修饰
        // 但是在 jdk8 下, 我们的 a 除了声明式做了赋值, 在整个方法体内没进行其他的修改了
        // 此时 我们的 a 是 effectively final 的, 可以在内部类进行使用
        System.out.println("a : " + a);
      }
    }
    // 如果把下面的 a 赋值 注释去掉, 会报错, a 不是 effectively final 了
    // a = 1233;
  }
}


作用

/**
 * 加密器接口
 */
public interface Encrypter {

    /**
     * 对内容进行加密
     * @param content 加密的内容
     * @return 加密后的内容
     */
    String encrypt(String content);
}

/**
 * 外部类
 */
public class OutClass {

    /**
     * 隐藏起来的加密器
     */
    private class MyEncrypter implements Encrypter {
        @Override
        public String encrypt(String content) {
            // 在需要加密的内容后面加上 encrypt
            return content + "encrypt";
        }
    }

    /**
     * 获取加密器
     * @return
     */
    public Encrypter getEncrypter() {
        return new MyEncrypter();
    }
}

/**
 * 调用类
 */
public class Main {

    public static void main(String[] args) {

        String str = "需要加密的内容";

        // 取到加密器, 此处我们只知道通过外部类就能获得加密器,但是加密器的加密过程我们是不知道的
        OutClass outClass = new OutClass();
        Encrypter encrypter = outClass.getEncrypter();

        // 加密内容
        String encryptedContent = encrypter.encrypt(str);

        System.out.println(encryptedContent);
    }
}
/**
 * 加密器
 */
 public class Encrypter {

     /**
      * 对内容进行加密
      * @param content 加密的内容
      * @return 加密后的内容
      */
     public String encrypt(String content) {
         // 在需要加密的内容后面加上 encrypt
         return content + "encrypt";
     }
 }

/**
 * 解密器
 */
 public class Decrypter {

    /**
     * 对内容进行解密
     * @param content 需要解密的内容
     * @return 解密后的内容
     */
    public String decrypt(String content) {

        // 在需要加密的内容后面加上 encrypt
        int length = "encrypt".length();
        // 解密的内容不为空,同时长度需要大于 length
        if (content == null || "".equals(content) || content.length() < length) {
            return content;
        }
        return content.substring(0, content.length() - length );
    }
}


/**
 * 外部类,此时我们的外部类具备了编码和解码的功能
 */
public class OutClass {

  private class MyEncrypter extends Encrypter{
  }

  private class MyDecrypter extends Decrypter{
  }

  public String encrypt(String content) {
      return new MyEncrypter().encrypt(content);
  }

  public String decrypt(String content) {
      return new MyDecrypter().decrypt(content);
  }
}
/** 匿名内部类 */
myBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
       //这里写代码
    }
});
上一篇下一篇

猜你喜欢

热点阅读