1. 属性:getters 和 setters

当数十名程序员同时开发一个大型项目时,如果他们以不同方式处理存储在类字段中的数据,问题往往会突然出现。

也许人们没有详细研究类文档,或者它没有描述每个案例。因此,经常会出现对象的内部数据“损坏”,从而使对象无效的情况。

为了避免这些情况,习惯上在 Java 中将所有类字段设为私有。只有类的方法可以修改类的变量。其他类的任何方法都不能直接访问变量。

如果您希望其他类能够获取或更改您的类对象中的数据,您需要向您的类添加两个方法——get 方法和 set 方法。例子:

代码 笔记
class Person
{
   private String name;

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

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}


privatename field



通过构造函数初始化字段


getName()— 此方法返回 name 字段的值




setName()— 此方法更改 name 字段的值

没有其他类可以直接更改名称字段的值。如果有人需要获取 name 字段的值,他们将不得不调用对象getName() 上的方法Person。如果某些代码想要更改名称字段的值,则需要调用对象setName() 上的方法Person

getName()方法也称为“名称字段的获取器setName()”,该方法称为“名称字段的设置器”。

这是一种非常常见的方法。在 80-90% 的所有 Java 代码中,您永远不会在类中看到公共变量。相反,它们将被声明private(或protected),并且每个变量都有公共的 getter 和 setter。

这种方法使代码更长,但更可靠。

直接访问一个类变量就像让你的车通过双黄线转弯:它更容易也更快,但如果每个人都这样做,那么每个人的情况都会变得更糟。

假设您要创建一个描述点 ( x, y) 的类。以下是新手程序员的做法:

class Point
{
   public int x;
   public int y;
}

经验丰富的 Java 程序员会这样做:

代码
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

代码更长吗?无疑。

但是您可以向 getter 和 setter 添加参数验证。例如,您可以确保 和x始终y大于零(或不小于零)。例子:

代码 笔记
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}


2. 对象生命周期

您已经知道对象是使用new运算符创建的,但是如何删除对象呢?它们不会永远存在。内存不足。

在许多编程语言中,例如 C++,都有一个专门delete用于删除对象的运算符。但是这在 Java 中是如何工作的呢?

在 Java 中,一切的安排都略有不同。Java 没有删除运算符。这是否意味着在 Java 中对象不会被删除?不,它们当然被删除了。否则,Java 应用程序会很快耗尽内存,而且不会有几个月不间断运行的程序。

在 Java 中,对象的删除是完全自动化的。Java 机器本身处理对象的删除。这个过程称为垃圾收集,收集垃圾的机制称为垃圾收集器( GC )。

那么 Java 机器如何知道何时删除一个对象呢?

垃圾收集器将所有对象分为“可达”和“不可达”。如果至少有一个对象的引用,则认为它是可达的。如果没有引用某个对象的变量,则该对象被认为是不可访问的,并被声明为垃圾,这意味着它可以被删除。

在 Java 中,您不能创建对现有对象的引用——您只能分配您已有的引用。如果我们删除对一个对象的所有引用,那么它就永远丢失了。

循环引用

在我们遇到一个简单的反例之前,这个逻辑听起来很棒:假设我们有两个相互引用的对象(存储对彼此的引用)。没有其他对象存储对这些对象的引用。

这些对象不能从代码中访问,但它们仍然被引用。

这就是垃圾收集器将对象分为可达和不可达,而不是“已引用”和“未引用”的原因。

可达对象

首先,将 100% 存活的对象添加到可达列表中。例如,当前线程 ( Thread.current()) 或控制台 InputStream ( System.in)。

然后,可达对象列表会扩展,以包括由初始可达对象集引用的对象。然后再次扩展以包含此扩展集引用的对象,依此类推。

这意味着如果有一些对象只相互引用,但是没有办法从可达对象中到达它们,那么这些对象将被认为是垃圾,将被删除。


3.垃圾收集

内存碎片

与对象删除相关的另一个重点是内存碎片。如果你不断地创建和删除对象,很快内存就会严重碎片化:占用的内存区域将散布在未占用的内存区域中。

结果,我们很容易陷入无法创建大对象(例如,具有一百万个元素的数组)的情况,因为没有大块的空闲内存。换句话说,可能有空闲内存,甚至很多,但可能没有大的连续空闲内存块

内存优化(碎片整理)

Java 机器以特定的方式解决了这个问题。它看起来像这样:

内存分为两部分。所有对象的创建(和删除)仅占内存的一半。当需要清理内存中的漏洞时,前半部分的所有对象都被复制到后半部分。但是它们是紧挨着复制的,所以没有孔。

该过程大致如下所示:

第 1 步:创建对象后

Java 中的垃圾收集

第二步:“洞”的出现

Java 2 中的垃圾收集

第三步:消除“洞”

Java 3 中的垃圾收集

这就是您不需要删除对象的原因。Java 机器只是将所有可到达的对象复制到一个新位置,并释放用于存储对象的整个内存区域。