Заставить Java ждать, пока не будет вызвано свойство? - PullRequest
0 голосов
/ 29 декабря 2011

Я недавно начал работать с JOGL, поэтому я создал векторный класс. Внутри этого класса я использовал строку

    public Vector unit=new Vector(x/length,y/length,z/length);

Чтобы найти вектор единицы. И, конечно, это вызывает переполнение стека. Есть ли способ заставить java ждать вызова модуля перед его запуском, или мне нужно будет сделать unit методом?

Ответы [ 3 ]

1 голос
/ 30 декабря 2011

Я лично создал второй конструктор, который вычисляет вектор единиц измерения и устанавливает для него собственный вектор единиц измерения. В идеале вы должны использовать частные значения и метод get, как предлагает Эрнест. Причина этого в том, что в противном случае другие классы могут просто перезаписать значения x, y, z и т. Д., Если у них есть доступ к одному из ваших объектов. У Java есть традиция использования окончательных классов для чистого хранения данных. См. String класс для примера. Вы не можете изменить существующий String, только создать новый String. После создания String остается прежним. Для ваших целей это может не иметь большого значения, но в другом контексте это может привести к неправильной работе вашего приложения, если ваш класс используется кем-то, у кого нет подсказки. В некоторых случаях это может даже представлять угрозу безопасности.

Вы можете просто проигнорировать это и получить доступ к переменным напрямую, и наслаждаться менее загруженным кодом и небольшим увеличением производительности. Но я бы все-таки предложил знать, в чем проблема на будущее.

В любом случае, ниже мой предложенный код для решения проблемы единичного вектора, за исключением методов получения.

import java.lang.Math;

class Vector{
    public double x,y,z,length;
    public Vector unit;

    public static void main(String[]s){
        new Vector(5,5,5);

    }

    public Vector(double x, double y, double z){
        this.length = Math.sqrt(x*x + y*y + z*z);

        this.x=x;
        this.y=y;
        this.z=z;

        this.unit = new Vector(x/length, y/length, z/length, true);
    }

    private Vector(double x, double y, double z, boolean isUnitVector){
        // Temp variable for calculating the length
        double length = Math.sqrt(x*x + y*y + z*z);

        if (isUnitVector){
            this.length = 1;

            this.x=x/length;
            this.y=y/length;
            this.z=z/length;

            this.unit = this;
        }else{
            this.length = Math.sqrt(x*x + y*y + z*z);

            this.x=x;
            this.y=y;
            this.z=z;

            this.unit = new Vector(x/length, y/length, z/length, true);
        }

    }

}

Я не совсем доволен дублированием кода между конструкторами, которое следует из логического аргумента. На практике я, вероятно, хотел бы создать фабричный класс VectorFactory с одним статическим методом, единственной задачей которого является создание объектов Vector. Или, может быть, просто используйте Java javax.vecmath.Vector3d и связанные с ним классы.

1 голос
/ 29 декабря 2011

Да, это достаточно просто, но вам нужно немного исправить свой дизайн. Что наиболее важно, как почти всегда в случае со всеми переменными-членами, unit должно быть private , и весь доступ к нему должен осуществляться через метод с именем что-то вроде getUnit(). Затем вы просто пишете getUnit(), чтобы проверить, была ли инициализирована unit:

public synchronized Vector getUnit() {
    if (unit == null)
        unit = new Vector(x/length,y/length,z/length);
    return unit;
}

Я сделал этот метод synchronized, чтобы избежать проблем, если два разных потока вызывают getUnit() примерно в одно и то же время, а unit еще не инициализирован.

0 голосов
/ 30 декабря 2011

Я предлагаю конструктор, который сам решает, является ли он единичным вектором или нет.Если это единичный вектор, то unit указывает на себя.Это нарушит рекурсию конструктора.Единственной проблемой могут быть числа, где length не совсем 1.0 из-за ошибок округления.

public class Vector {
    public double x, y, z;
    public Vector unit;

    public Vector(double x, double y, double z){
        this.x = x;
        this.y = y;
        this.z = z;
        double length = calcLength(x, y, z);
        if( length == 1.0 )  // perhaps add a little fuzz factor.
            this.unit = this;
        else
            this.unit = new Vector(x/length, y/length, z/length);
    }
}
...