Java在内存中的含义是什么

时间:2010-01-30 23:22:59

标签: java memory

我是java新手,还在学习。我抓住了内心和匿名课程。现在我有一个技术问题,关于java在内存中的表现,分配对象,定义类等等。

当我有一个在外部类和内部类中定义的对象的字段时,就像内存看起来一样。静态类看起来与非静态类不同吗?

我只需要一个视觉参考。

谢谢大家

6 个答案:

答案 0 :(得分:4)

答案 1 :(得分:3)

细节在实施中(不是规范)。然而,实现通常遵循非常简单的模式。 Java中的大多数内存布局都非常简单明了。我的术语可能与Java术语不匹配,因为我没有做很多Java编程。

通常,对象以指向其vtable的指针开头,然后有一堆字段跟随。字段是基本类型(int / bool / float)或指向对象的指针。这就是对象。 (类也是对象。)空指针就像C,它们是无效的,不像Python,其中None是一个对象。

在内部类中,有一个额外的隐藏字段,指向外部类的实例。这是内部类访问外部类中的数据的方式。匿名类的工作方式相同。静态方法只是类的方法而不是实例上的方法。

vtable是所有魔法发生的地方。每个类都有自己的vtable在所有对象之间共享。 vtable具有关于类的信息,例如其实例的大小以及字段的布局方式。垃圾收集器使用此信息。 vtable还有一个指向该类实现的所有方法的指针。当您调用方法时,运行时首先从对象中获取vtable指针,然后将方法指针从vtable中取出,然后调用该方法并将该对象作为隐式参数传递给该方法。它与C ++类似,但实现起来要简单得多。如果方法或类是“最终的”,则可以跳过该过程。

我知道Java没有“指针”,它有“符号句柄”或者其他类似的东西,但是常见的实现只使用普通的旧指针。

答案 2 :(得分:3)

欢迎来到Java世界。与C语言不同,语言结构和内存表示几乎一对一地映射,Java稍微复杂一些。

首先,当人们谈论Java时,它可能意味着两件事:Java-the-language和Java-the-platform。在这里,我将Java称为Java编程语言。用Java编写的代码首先被编译为字节码,Java虚拟机的机器代码。如果您对Java语言的详细信息感兴趣,请访问The Java Language Specification。对于JVM,有The Java Virtual Machine Specification

  

当我有一个字段是外部类和内部类中定义的对象时,内存是什么样的。

我将这解释为Java虚拟机中的内存布局是什么样的,因为物理布局取决于JVM的实现。为此,我浏览了Structure of the Java Virtual Machine

  

与Java语言类似,Java虚拟机以两种类型运行:原始类型引用类型。相应地,有两种值可以存储在变量中,作为参数传递,由方法返回,并在以下操作:原始值参考值

     

Java虚拟机期望几乎所有类型检查都在编译时完成,而不是由Java虚拟机本身完成。特别是,无需标记数据或以其他方式检查数据以确定类型。

...

  

对对象的引用被视为具有Java虚拟机类型reference。类型reference的值可以被认为是指向对象的指针。

所以答案似乎是两个字段看起来完全相同:reference

答案 3 :(得分:1)

  

就像我记忆中的样子一样   有一个对象的字段   在外部类中定义与   内心阶级。静态类看起来   不同于非静态?

非静态内部(或匿名)类的实例将引用用于实例化它的外部类实例。这允许内部类中的方法引用封闭类中声明的实例级成员。通常,此引用作为构造函数中的隐藏额外参数传递给内部类。但是,如果使用反射来创建内部类实例,则必须显式提供该额外参数。

(请注意,当匿名类在实例化它的方法范围内使用locals /参数时,会使用不同的机制...)

如果您需要更多细节,可以使用javap来反汇编一些简单示例类的字节码。

  

我只需要一个视觉参考。

对不起,我不做漂亮的照片: - )

答案 4 :(得分:0)

静态(嵌套)类的工作方式与顶级类的工作方式完全相同。唯一的区别是它的名字有另一个以它为前缀的类名。 (如果查看已编译的.class文件,您实际上会看到,对于名为Nested的类嵌套在名为Outer的类中,您将获得类似“Outer $ Nested.class”的内容。)

内部类有一个隐藏字段,它是对其外部类的包含实例的引用。当你写:

class Outer {
  final int x;

  class Nested {
    int y;

    Nested(int y) {
      this.y = y;
    }

    int bar() {
      return x + y;
    }
  }

  void foo() {
    Nested n = new Nested(5);
  }
}

就像你写的那样:

class Outer {
  final int x;

  static class Nested {
    Outer outer;
    int y;

    Nested(Outer outer, int y) {
      this.outer = outer;
      this.y = y;
    }

    int bar() {
      return outer.x + y;
    }
  }

  void foo() {
    Nested n = new Nested(this, 5);
  }
}

隐藏了该隐藏字段的名称(我称之为“外部”) 对你而言,虽然你可以通过说Outer.this内部来引用它 内部类(当然,Outer是你的外部类的名称)。 同样,请注意当内部类中的方法引用时 在外部类中的某些东西,该引用实际上是通过隐藏的 引用外层。

关于访问控制(例如:private)如何与嵌套/内部类一起工作,还有一些其他的复杂问题,但这并不会真正影响您所询问的“内存”问题。

答案 5 :(得分:0)

public class I {
    class inner {
        public void ctor() {};
    }
}

看起来有点像,你可以使用JAD

class I$inner {

  // Field descriptor #6 LI;
  final synthetic I this$0;

  // Method descriptor #8 (LI;)V
  // Stack: 2, Locals: 2
  I$inner(I arg0);
     0  aload_0 [this]
     1  aload_1
     2  putfield I$inner.this$0 : I [10]
     5  aload_0 [this]
     6  invokespecial java.lang.Object() [12]
     9  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 10] local: this index: 0 type: I.inner

  // Method descriptor #14 ()V
  // Stack: 0, Locals: 1
  public void ctor();
    0  return
      Line numbers:
        [pc: 0, line: 4]
      Local variable table:
        [pc: 0, pc: 1] local: this index: 0 type: I.inner
}

作为hexdump,它将以0xcafebabe

开头