Java 构造函数内的声明

Declarations inside a constructor in Java

Java是否接受以下内容? 我知道它可以编译,但是它在 Java 中是否被接受,或者我应该将代码更改为其他代码吗?

谢谢!

public class Line extends Shape {

    public Line(int x1, int x2, int y1, int y2, Color myColor) {
        super(x1, x2, y1, y2, myColor);

        Point p1 = new Point(this.getX1(),this.getY1());
        Point p2 = new Point(this.getX2(),this.getY2());
    }

如果你想在构造函数之外使用变量 p1p2 你必须像这样将它声明到 class 级别变量

Point p1;
Point p2;
public Line(int x1, int x2, int y1, int y2, Color myColor) {
    super(x1, x2, y1, y2, myColor);

    p1 = new Point(this.getX1(),this.getY1());
    p2 = new Point(this.getX2(),this.getY2());
}

否则没问题。

p1,p2 - represents the line points...the issue is that I want to use those points in some of the object's method.

那么你必须在构造函数之外声明它们;如果你在内部构造函数中声明它们,它们就是局部变量。与任何函数中的局部变量一样,它们不在函数外部的范围内。 ("function" = "constructor or method")

您可以在构造函数中初始化它们,但您必须在外部声明它们:

public class Line extends Shape {
    private Point p1; // You may or may not want the `private`, it...
    private Point p2; // ...depends what you're going to do with them

    public Line(int x1, int x2, int y1, int y2, Color myColor) {
        super(x1, x2, y1, y2, myColor);

        this.p1 = new Point(this.getX1(),this.getY1());
        this.p2 = new Point(this.getX2(),this.getY2());
    }

    // ...
}

注意:访问上面的实例字段可以在前面有或没有this.来完成。 (例如,this.p1 = new ...p1 = new... 都是有效的。)我总是使用 this. 以便通过查看代码很容易判断我使用的是实例字段还是本地字段多变的;我的 IDE 还可以通过自动完成帮助我解决更多问题。不过我想我可能是那里的少数。


关于你在构造函数外初始化还是在构造函数内部初始化的问题,说说你在构造函数外写的初始化是什么时候真正完成的,可以不明显:

class A { 
    int x;
    int y;

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

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;
    }
}
class B extends A {
    private ImmutablePoint p = new ImmutablePoint(this.getX(), this.getY());

    public B(int x, int y) {
        super(x, y);
        System.out.println("Hello from B");
    }

    public Point getP() {
        return this.p;
    }
}

看起来像初始化发生在调用构造函数之前(无论如何对我来说)。事实并非如此。编译器为 class B 生成的字节码看起来像这样:

// Reconstituted version of the bytecode for our B above
class B extends A {
    private ImmutablePoint p;

    public B(int x, int y) {
        super(x, y);
        this.p = new ImmutablePoint(this.getX(), this.getY()); // <== Inserted
        System.out.println("Hello from B");
    }

    public Point getP() {
        return this.p;
    }
}

请注意它是如何将您的初始化逻辑插入到构造函数中的。

以下是在构造函数中而不是声明中编写初始化的一些原因:

  1. 如果您需要使用仅在构造函数内部可用的信息(一个不会成为对象状态一部分的参数),您别无选择,您必须在构造函数。例如,A 无法初始化其 x 字段,除非使用其 x 参数。

  2. 如果您需要在不同的构造函数中以不同的方式进行初始化。同样,您别无选择,只能在构造函数中而不是在声明中进行初始化。

  3. (这是主观。)清晰。由于初始化代码是 运行 在调用 super 之后并且在构造函数中的任何其他内容之前,因此将其写在源代码中可以帮助清晰。

构造函数之外编写初始化有一个参数,声明为:

  1. 如果您有多个构造函数,并且所有构造函数的初始化逻辑都相同,则使用声明编写它可以让您只写一次并重用它。 (你也可以通过在你的构造函数中调用一个方法来做到这一点,但有些人对此不以为然。)但是,还有一个替代方法,我将在下面标记。

让我们在 B 的上下文中看一下:

class B extends A {
    private ImmutablePoint p = new ImmutablePoint(this.getX(), this.getY());

    public B(int x, int y) {
        super(x, y);
        System.err.println("Hello from B");
    }

    public B(int x, int y, String msg) {
        super(x, y);
        System.out.println(msg);
    }

    public Point getP() {
        return this.p;
    }
}

现在我们有两个构造函数,它们做的事情略有不同(System.errSystem.out,使用参数或使用默认消息。)编译器生成的字节码实际上是这样做的:

// Reconstituted version of the bytecode for our B above
class B extends A {
    private ImmutablePoint p;

    public B(int x, int y) {
        super(x, y);
        this.p = new ImmutablePoint(this.getX(), this.getY()); // <== Inserted
        System.err.println("Hello from B");
    }

    public B(int x, int y, String msg) {
        super(x, y);
        this.p = new ImmutablePoint(this.getX(), this.getY()); // <== Inserted
        System.out.println(msg);
    }

    public Point getP() {
        return this.p;
    }
}

因此可以说在声明的一个地方编写初始化是有好处的。

这是一种风格选择;另一种方法是使用 公分母构造函数 :

class B extends A {
    private ImmutablePoint p;

    private B(int x, int y) {
        super(x, y);
        this.p = new ImmutablePoint(this.getX(), this.getY());
    }

    public B(int x, int y) {
        this(x, y);
        System.err.println("Hello from B");
    }

    public B(int x, int y, String msg) {
        this(x, y);
        System.out.println(msg);
    }

    public Point getP() {
        return this.p;
    }
}

最后:Java 也有 初始化程序块,它们是在任何构造函数之外编写的初始化程序代码,但是以一种非常类似于方法的方式:

class B extends A {
    private ImmutablePoint p;

    // Instance initializer block:
    {
        this.p = new ImmutablePoint(this.getX(), this.getY());
    }

    public B(int x, int y) {
        super(x, y);
        System.err.println("Hello from B");
    }

    public B(int x, int y, String msg) {
        super(x, y);
        System.out.println(msg);
    }

    public Point getP() {
        return this.p;
    }
}

您可以在初始化程序块中使用有限的逻辑。

所以你有各种各样的选择。除了当你需要 在构造函数中初始化时(我之前列表中的#1 或#2),这是一种风格选择。