2

尽管有 Java 教程、Wikipedia 搜索、stackoverflow 巨魔以及数小时的代码示例阅读,但构造函数仍然让我感到困惑。我一直在尝试回答三个相关的问题,以帮助我更好地理解构造函数。

首先,我一直认为构造函数的名称需要与其类相同。考虑:

public class Money {
    public Money(long l) {
        this.value = l;
    }

    public Money(String s) {
        this.value = toLong(s);
    }

    public long getLong() {
        return this.value;
    }

    public String getString() {
        return toString(this.value);
    }
} 

我认为这是四个构造函数……对吗?因此,似乎构造函数名称与包含它们的类的名称不同。有人可以确认吗?

其次,我似乎对理解 set 和 get 方法有障碍。考虑:

 public class GetSetSample {
     public int getFoo()  {
 return int Foo;
 }
 public void setFoo(int fooValue) {
 int Foo = fooValue;
 } 
} 

为什么我不能这样做:

public class getFoo(int fooValue){
     foo=fooValue;
}

foo = getFoo(12)从其他类/方法中使用?

第三个问题有点深奥,但会帮助我构想更大的图景……这是我的学习方式,有利于我在调试时跟踪程序流程的能力。getand方法暗示了我的set“to”和“from”关系。例如,将值“传递给”构造函数,“从”get 方法接收结果。在我看来,“to”和“from”会根据你的观点而改变。我认为 anysetMethod正在为一个对象设置参数,即使该变量来自另一个类或方法,并且GetMethod正在使用适当的参数get对结果对象(例如)进行设置。无论在哪里或this.foosetgetset在具有单个构造函数的主方法或独立类中使用时,“set”始终与发送参数相关联,并且get始终与接收具有该参数的对象相关联。这是一个很好的理解吗?还是我错过了一个重要的部分?

4

6 回答 6

8

问题一:

我认为这是四个构造函数……对吗?

不,那个类有两个构造函数和两个方法。(getLong并且getString是方法。)

问题2:

为什么我不能这样做:

public class getFoo(int fooValue){
    foo=fooValue;
}

好吧,那是在尝试声明一个带参数的,并且您正在get方法中设置一个值,这将是非常奇怪的。目前尚不清楚您要在这里实现什么,但该代码完全无效。

问题 3:

get 和 set 方法暗示了我的“to”和“from”关系。

好吧,这不是真正的关系IMO。关系暗示了比这两种方法中任何一种都更长期的东西。setter 通常以某种方式更改对象的状态,而 getter 通常只返回对象状态的某些方面。你的解释的其余部分是什么意思并不是很清楚,因为你在使用术语时有点快速和松散。例如:“get总是与接收带有该参数的对象相关联”对我来说真的没有意义。对象没有参数,方法/构造函数有——getter 可以获取原始值或引用......

我怀疑您会从阅读Java 教程的“类”部分中受益,其中讨论了构造函数和方法。

于 2012-04-14T17:57:29.557 回答
3

您已经展示了 2 个构造函数,它们确实需要与类同名。

您还展示了两个“getter”方法,它们以用户请求的形式返回类变量的值。您还可以创建“setter”方法,用于将值传输到类变量中。

您使用构造函数来创建特定类的对象,并可选择设置其部分或全部内部状态(即其成员变量)。

您使用 setter 和 getter 将类变量与外界隔离,因此您不需要允许其他代码直接访问它们。为什么?因为,在 setter 更新变量之前,它可以验证新值是否有效,并且操作不违反类正常工作所需的任何规则(“业务逻辑”)。

因此,您可以添加一个 setter 并更新构造函数以使用它:

public Money(long l) {
    setValue(l);
}

public Money(String s) {
    setValue(toLong(s));
}

// Example setter that validates `l` by prohibiting negative values
public Money setValue(long l) {
  if (l < 0) {
    // Warn about negative values
  }
  this.value = l;
  return this;  // Return the current object to allow chaining; see below.
}

请注意,setter 通常不需要返回值(也就是说,它可以是 type void),但返回对象本身通常会很有帮助。这使您可以编写如下代码:

Money earnings = new Money().setValue(4).setOtherField("foo");

这将创建一个类型的对象Money,设置各种属性,并将其存储在变量中earnings。显然,这对于像这样的简单类并不是非常有用,但对于更复杂的类可能非常有用:

Paycheck check = new Paycheck("MyCompany")
  .setEmployee("YourName")
  .setSalary(50,000)
  .setPaySchedule(Schedule.BIWEEKLY)
  .setAccountNumber("1234567")
  .setDefaultTaxRate();
于 2012-04-14T17:57:20.573 回答
3

关于第一个答案,只有 2 个构造函数。不同之处在于它们将如何被调用(使用字符串调用将使用具有字符串具有参数的构造,而使用 long 调用将使用另一个构造)。所以要回答,是的,构造函数与类同名。

两个构造函数:

public Money(long l) {
        this.value = l;
    }

    public Money(String s) {
        this.value = toLong(s);
    }

关于第二个答案,getter 和 setter 并不意味着是类。他们应该在班级本身内。

考虑这个例子,它使用 getter 和 setter 来获取打印机类的 ans set 值:

public class Printer {

    @Inject @Informal Greeting greeting;

    private String name;
    private String salutation;

    public void createSalutation() {
        this.salutation = greeting.greet(name);
    }

    public String getSalutation() {
        return salutation;
    }

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

    public String getName() {
       return name;
    }
}

好好阅读这个链接绝对可以帮助你! Java 面向对象原则

于 2012-04-14T17:58:47.773 回答
0

我想试着回答你隐含的概念性问题——你已经有很多这样和那样的例子,所以我只是试着解释一下。毫无疑问,您之前已经听说过其中的大部分——也许是所有这些——但我不确定,也不确定是哪些部分。

面向对象的编程主要围绕对象;对象是代码和数据的融合。您通过编写一个类来定义对象,并使用类构造函数创建由该类定义的对象的一个​​或多个副本(称为实例化类)。

其他语言的并行:您可以拥有相关项目的数据结构和一组对该数据结构进行操作的子例程。将类视为一种将数据结构中的项目和对其进行操作的子例程收集到一个单元中的方法。

调用构造函数后,您将拥有该类中定义的数据的副本以及引用该副本的方法。通过在调用类方法时引用该实例,您可以使用该类中定义的方法对该数据副本进行操作。

如果您要使用非 OO 语言执行此操作,则可以有一个例程在内存中创建数据结构的副本,然后仅在该数据结构上使用为它规定的方法。您可以在内存中拥有一个指向副本的指针,并将该指针作为参数传递给对其进行操作的每个子例程,事实上,这就是一些 OO 之前的系统的编程方式。

构造函数类似于返回值的方法调用;它涉及(或可能涉及)语句的执行,并且它总是返回该类的对象。构造函数和方法之间也有区别;例如,在构造函数完成之前,对象还没有完全创建,并且不应该在其上调用某些方法。

所以我希望这会有所帮助;如果您仍然对概念性的事情有疑问,也许这里的某些内容会帮助您形成一个具体的问题,以便我们进一步解释。

于 2012-04-14T18:33:54.597 回答
0

许多人发现,如果他们花了数年时间学习诸如 COBOL 和 FORTRAN 之类的语言,那么转向 OO 编程就意味着忘掉旧语言。当我 20 年前第一次接触 C++ 时,我当然发现了这一点。根据您的描述,您显然在与这些概念作斗争,我对此表示同情。

我不认为有一个简单的食谱。练习简单的例子,不要灰心。不要害怕提出这样的问题——如果问题被明确提出,你会得到一个有用的答案。

获得一个好的 IDE(Eclipse、Netbeans 等),它允许您使用调试器“查看内部”对象。希望在某些阶段事情会点击!

于 2012-04-14T18:34:58.483 回答
0

问题 1 - 基本 Java 类:

在 Java 类中你几乎只能找到 3 样东西

  • 字段/属性(取决于您的原籍语言)
  • 方法
  • 构造函数(看起来像是一种特殊的方法)

每个类都将有一个类名,该类名与它所在的文件名共享。因此,将 Money 扩展一下:

Money.java
----------
public class Money {
   // This is a field/attribute
   Long value;

   // This is a constructor
   public Money() {
      this.value = Long(0L);
   }

   // This is a method
   public Long getValue() {
      return value;
   }

   // Another method
   public void makeMoney(Long moreMoney) {
      this.value = this.value + moreMoney;
   }
} // Everything in here is part of the Money class

构造函数和方法之间的唯一区别是构造函数没有指定的返回值,它在潜在方法的名称之前被声明为类型。构造函数的名称必须与它们所在的类的名称相同,但它们的编写方式中隐含了为什么。

另一种看待它的方法是,如果您从您正在查看的方法的前面删除所有与类型无关的 Java 关键字(public、private 等,但不包括 float 和 int)(其中的列表你可以在这里找到),方法前面还有什么东西吗?

使用我们目前拥有的资金,它看起来像这样:

  • 钱()
  • 长 getValue()
  • 无效的赚钱()

构造函数是没有返回值类型的构造函数,因为它隐含在声明中。

问题 2/3 - 获取/设置方法:

我要说一些可能引起争议的事情,但不要担心这些。Get/Set 本质上是面向对象开发的模式,通常是良好的 Java 风格,但它们不是必需的(最后我检查,Android 开发实际上出于优化原因不鼓励使用它们)。此外,并非对象中的所有字段都是可访问或可变的,因此编写它们不是强制性的。

如果您将所有字段声明为公共字段(就像现在隐含的“值”字段一样),您可以简单地执行以下操作:

Money myMoney = new Money(new Long(40L));
System.out.println(myMoney.value) // 40
myMoney.value = new Long(20L);
System.out.println(myMoney.value) // 20

除此之外,get() 和 set() 的概念只是方法。它们根本没有什么特别之处。它们存在的主要原因是因为对于一般的面向对象编程,您不必直接修改对象的内部工作方式(这是封装的原理)。影响状态或从中获取某些东西所需的一切都应该由方法处理。

简而言之:如果您需要知道对象的字段才能使用它,那么您的设计是错误的。

大图 所以 get() 和 set() 真正是一对常用的方法,它们碰巧以极其简单的方式影响对象中的字段(get() 是对字段的简单访问,set() 是分配给该领域)。只是你编写的其他方法会碰巧做比这更复杂的事情。

于 2012-04-14T18:53:50.437 回答