Java内部类的实现原理与可能的内存泄漏说明

在使用java内部类的时候要注意可能引起的内存泄漏

代码如下

package com.example;
public class MyClass {

 public static void main(String[] args) throws Throwable {

 }

 public class A{
  public void methed1(){

  }
 }

 public static class B{
  public void methed1(){

  }
 }

编译生成了如下文件

Java内部类的实现原理与可能的内存泄漏说明

反编译MyClass

Java内部类的实现原理与可能的内存泄漏说明

反编译MyClassA

Java内部类的实现原理与可能的内存泄漏说明

反编译GlassB

Java内部类的实现原理与可能的内存泄漏说明

从反编译的结果可以知道,内部类的实现其实是通过编译器的语法糖实现的,通过生成相应的子类即以OutClassName$InteriorClassName命名的Class文件。

并添加构造函数,在构造函数中传入外部类,这也是为什么内部类能使用外部类的方法与字段的原因。

我们明白了这个也就要小心,当外部类与内部类生命周期不一致的时候很有可能发生内存泄漏,例如在一个Activity启动一个Thread执行一个任务,因为Thread是内部类持有了Activity的引用,当Activity销毁的时候如果Thread的任务没有执行完成,造成Activity的引用不能释放,Activity不能被释放而引起了内存泄漏。

这种情况下可以通过声明一个static的内部类来解决问题,从反编译中可以看出,声明为static的类不会持有外部类的引用,如果你想使用外部类的话,可以通过软引用的方式保存外部类的引用。

具体的代码就不上了。

补充知识:Java内部类的底层实现原理

摘要:

定义:在一个类中创建另一个类,叫做成员内部类,这个内部类可以是静态的,也可以是非静态的。

已知静态内部类的应用(可以解决的问题):

通过内部类解决java 的单继承问题,外部类不能同时继承的类可以交给内部类继承

设计模式中,builder 模式通过定义一个静态内部类实现

类型汇总:

静态内部类

成员内部类

方法内部类

匿名内部类

一、静态内部类

静态内部类的定义和普通的静态变量或者静态方法的定义方法是一样的,使用static关键字,只不过这次static是修饰在class上的,一般而言,只有静态内部类才允许使用static关键字修饰,普通类的定义是不能用static关键字修饰的,这一点需要注意一下。下面定义一个静态内部类:

public class Out {
 private static String name;
 private int age;
 
 public static class In{
  private int age;
  public void sayHello(){
   
   System.out.println("my name is : "+name);
   //--编译报错---
   //System.out.println("my age is :"+ age);
  }
 }
}

在上述代码中,In这个类就是一个静态内部类。我们说内部类是可以访问外部类的私有字段和私有方法的,对于静态内部类,它遵循一致的原则,只能访问外部类的静态成员。上述代码中,外部类的非静态私有字段age在静态内部类中使不允许访问的,而静态字段name则是可访问的。下面我们看,如何创建一个静态内部类的实例对象。

public static void main(String [] args){
 Out.In innerClass = new Out.In();
 innerClass.sayHello();
}

静态内部类的实例对象创建还是比较简洁的,不同于成员内部类,它不需要关联外部类实例(具体的下文介绍),下面我们再看一段代码:

public class Out {
 private static String name;
 
 public static class In{
  public void sayHello(){
   System.out.println(name);
   showName();
  }
 }
 
 private static void showName(){
  System.out.println(name);
 }
}

上述代码在内部类中两次访问了外部类的静态成员,第一次访问了静态字段name,第二次访问的静态方法showName。在我们反编译这个类之前,首先需要知道的是,所谓的内部类的概念只是出现在编译阶段,对于jvm层是没有内部类这个概念的。也就是说,编译器会将一个类编译成一个源文件,对于内部类也是一样,它会从它的外部类中抽离出来,增加一些与外部类的联系,然后被编译成一个单独的源文件。下面我们先编译运行之后,利用Dj反编译class文件看看编译器都做了些什么事情。

Java内部类的实现原理与可能的内存泄漏说明

扫一扫手机访问