Подтвердить что ты не робот

Что на самом деле делает "новое" ключевое слово на Java, и не следует ли мне создавать новые объекты?

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

Я искал похожие вопросы, но на самом деле я не мог найти ответ, который я искал. Теперь, зная, что в Java (для языка, на котором мне было предложено начать с), считается хорошей практикой программирования для объявления и создания экземпляров переменных по мере необходимости, пожалуйста, рассмотрите следующие строки:

class MyClass {
    void myMethod() {
        AnotherClass myObject = new AnotherClass();
        myObject.doStuff();
    }
}

Теперь предположим, что я вызываю myMethod(), скажем, 10 раз во время запуска моей программы, как это работает? Создается ли новый объект каждый раз? Переменная myObject перераспределяется каждый раз? Прокомментирует ли пропутчик что-то вроде кода, поскольку он видит, что объект уже создан, и переменная myObject уже была назначена для такого объекта? В двух словах: следует ли писать такой код только в том случае, если я планирую вызывать этот метод только один раз? Я знаю... стыдно за меня, задавая такой глупый вопрос, но, пожалуйста, дайте мне шанс! Спасибо заранее!

--------------------------- отредактировал ------------------- ----------

Итак, теперь я должен отредактировать этот пост после получения новых ответов? Кстати... черт возьми, это было быстро, спасибо! И ничего себе, что меня смутило, много, я думаю, из-за того, что я так учил... В любом случае, не бесполезно ли каждый раз создавать объект new AnotherClass для переменной myObject? Я имею в виду, если я хочу использовать переменную myObject во всей моей программе, не должен ли я объявлять ее "Как и для всех"? может быть, в другом методе, что я буду вызывать только один раз? Поскольку, насколько я понимаю, каждый раз, когда я вызываю myMethod(), создается новый объект, тем самым переопределяя собственные свойства myObject как переменные или я просто говорю глупости?

--------------------------- отредактировал ------------------- ----------

Мои сомнения появились после прочтения этого кода с некоторого веб-сайта, который я не могу вспомнить прямо сейчас:

    public class DataBase {

    private static String buf, retString = "\n";
    private static File file = new File("test.txt");

    public static void readText(JTextArea area) {   
        try {
            FileReader fr = new FileReader (file);
            BufferedReader br = new BufferedReader(fr);
            while ((buf = br.readLine()) != null) {
                area.append(buf); 
                area.append(retString);
            }
            br.close(); 
            fr.close();
        }
        catch (IOException e) {
            System.out.println("Exception: " + e);
        }
    }

    public static void writeText(JTextArea area) {
        try {
            FileWriter fw = new FileWriter (file);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write(area.getText());
            bw.close(); 
            fw.close();
        }
        catch (IOException e) {
            System.out.println("Exception: " + e);
        }
    }
}

Я имею в виду, почему бы не объявить FileWriter, FileReader, BufferedReader и BufferedWriter в верхней части класса, как и для других переменных? и почему не инициализировать их, а может быть, в конструкторе? Зачем делать это каждый раз, когда вызывается метод, а не используя, возможно, одну и ту же переменную экземпляра?

4b9b3361

Ответ 1

Да, если вы вызвали myMethod() 10 раз, он создаст 10 уникальных и отдельных объектов.

Ключевое слово new делает именно то, что он говорит о жесте, оно создает совершенно новый объект, независимо от того, существует ли он уже. Он создает новый объект и заполняет ссылку на этот объект внутри переменной, которую он дал, перезаписывая любое предыдущее значение (объект), которое удерживается переменной.

Переменная myObject перераспределяется каждый раз?

Опять же, да, он будет переназначен новым объектом каждый раз при вызове метода. Интересная записка об этом будет заключаться в том, что переменная не будет "действительно" перераспределена, поскольку вы определяете переменную внутри самого тела метода, поэтому каждый раз, когда метод заканчивается, он удаляет переменные, которые были определены в пределах своей области, Так что на самом деле это создание 10 отдельных переменных и назначение 10 отдельных объектов, хотя, как я уже сказал, остальные должны были быть удалены автоматически, поэтому он не будет использовать дополнительную память.

Вкратце: должен ли я писать такой код, только если я планирую вызывать этот метод только один раз?

Как я уже сказал, в приведенном выше примере каждый объект будет уничтожен в конце выполнения метода (если вы не присвоили ссылку на объект переменной вне области действия метода), поэтому в вашем примере вы могли бы с радостью вызовите метод столько раз, сколько захотите, но каждый раз никоим образом не будет подключаться к предыдущим вызовам.

Я понимаю, что мой способ письма может сбить с толку, поэтому, если вы хотите, чтобы я прояснил что-либо, просто спросите.

Обновлен ответ, чтобы отразить отредактированный вопрос

'почему бы не объявить FileWriter, FileReader, BufferedReader и BufferedWriter в верхней части класса, как это было сделано для других переменных?

Хорошо, я полагаю, вы понимаете, что переменные на самом деле не называются FileWriter, FileReader, BufferedReader и BufferedWriter, а скорее это тип переменной. Их имена: fw, fr, br и bw. Если вы не понимаете, о чем я говорю, просто спросите. Отныне я буду ссылаться на переменные по именам, которые вы сделали, чтобы сделать чтение более легким, а после fw просто означает FileWriter, так что не должно быть слишком много путаницы.

Ключ к этому вопросу скрыт в именах самих переменных. Обратите внимание, как они заканчиваются на Reader или Writer, что может дать нам тонкий ключ к их использованию. Очевидно, что FileWriter и BufferedWriter связаны с выходом каким-то образом. Просмотрев код, мы видим, что наши подозрения были правильными и что ни в какой другой момент, кроме метода writeText(JTextArea area), эти переменные не появляются. Поэтому, если переменная не используется нигде в коде, логический смысл определять и инициализировать их в рамках метода, в котором они используются, не только делает код более удобным для чтения, потому что мы тогда "знаем" эти переменные относятся только к этому методу, но также имеют преимущество от того, что эти переменные удаляются в конце выполнения метода, тем самым не оставляя переменных в существовании, которые использовались очень кратко. По этим правилам мы можем сказать, что то же самое верно для FileReader и BufferedReader.

Соблюдайте этот пример в области переменных. (Посмотрите на комментарии, которые я добавил в код)

public class DataBase {

private static String buf, retString = "\n"; // buf & retString - created
private static File file = new File("test.txt"); // file - created

public static void readText(JTextArea area) {   
    try {
        FileReader fr = new FileReader (file); // fr (FileReader) - created
        BufferedReader br = new BufferedReader(fr); // br (BufferedReader) - created
        while ((buf = br.readLine()) != null) {
            area.append(buf); 
            area.append(retString);
        }
        br.close();
        fr.close();
    } // fr (FileReader & br (BufferedReader) - destroyed
    catch (IOException e) {
        System.out.println("Exception: " + e);
    }
}

public static void writeText(JTextArea area) {
    try {
        FileWriter fw = new FileWriter (file); // fw (FileWriter) - created
        BufferedWriter bw = new BufferedWriter(fw); // bw (BufferedWriter) - created
        bw.write(area.getText());
        bw.close(); 
        fw.close();
    } // fw & bw - destroyed
    catch (IOException e) {
        System.out.println("Exception: " + e);
    }
}
} // buf, retString and file - Still exist as long as the object exists

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

Зачем делать это каждый раз, когда вы вызываете метод, а не используете, возможно, одну и ту же переменную экземпляра?

Ну, этот вопрос связан с типами переменных. Мы не могли повторно использовать одну переменную для всей информации, так как типы должны были быть разными.

Если взять все переменные из кода

private static String buf, retString = "\n"; // valid
private static File file = new File("test.txt"); // valid

FileReader fr = new FileReader (file); // valid
BufferedReader br = new BufferedReader(fr); // valid
FileWriter fw = new FileWriter (file); // valid
BufferedWriter bw = new BufferedWriter(fw); // valid

Теперь мы знаем, что мы не можем поместить в эту переменную значение того же типа, что и переменная, что-то вроде

FileReader fr = new BufferedReader(fr); // Is not valid!

Поскольку типы просто не совпадают.

Имеют смысл?

Ответ 2

Да, каждый раз создается новый объект. Ссылка на каждый myObject выделяется в стеке.

Вкратце: должен ли я писать такой код, только если планирую вызывать этот метод только один раз?

Если вы хотите myObject исчезнуть после завершения выполнения метода, да, да. Если по какой-то причине вам нужно сохранить ссылку на нее, вы можете объявить ее как член класса.

class MyClass {
    AnotherClass myObject;
    void myMethod() {
        myObject = new AnotherClass();
        myObject.doStuff();
    }
}

Таким образом, он будет создан каждый раз, когда вы вызываете myMethod(), но он все равно будет существовать после завершения myMethod. Это может быть удобно или нет, в зависимости от ситуации.

Прокомментирует ли пропутчик что-то вроде кода, поскольку он видит, что объект уже был создан, и переменная myObject уже была присвоенный этому объекту?

Это не произойдет при использовании new. Гарантируется, что он создаст новый экземпляр. Он может быть реализован с помощью FactoryMethods (а не компилятор, пропуская строки кода, но предотвращая создание нового объекта), Например, класс Integer реализует это: если вы попытаетесь получить целое число между -128 и 127, оно всегда будет возвращать то же самое экземпляр (не создавайте новый объект) при использовании его метода Factory valueOf

 Integer five = Integer.valueOf("5");//Will always return the same instance.
 Integer otherFive = Integer.valueOf("5");

 assert(five==otherFive);//true

Конечно, использование new не возвращает тот же экземпляр, но всегда новый

 Integer five = new Integer("5");//Will create a new object each time.
 Integer otherFive = new Integer("5");

 assert(five==otherFive);//false

после обновления вопроса

На самом деле не так много сказать о коде, который вы добавили. Однако, если вы посмотрите, вы заметите два метода. Основываясь на своих именах, один раз, кажется, пишет, другой, похоже, читает. Это поведение специфично для каждого метода, поэтому метод writeFile не заботится об объектах, используемых для чтения. И метод readFile не заботится о том, какие объекты используются для записи. Поэтому нет смысла делать fileReader доступным для метода writeFile и т.д.

Возвращаясь к исходному вопросу, да, это создает экземпляр нового объекта каждый раз при вызове метода. Это не важно. Его предпочтительнее спрашивать себя: "Почему метод readFile имеет доступ к экземпляру FileWriter?

Ответ 3

Теперь предположим, что я вызываю myMethod(), скажем, 10 раз, когда запускаю мой программа, как это работает? Создается ли новый объект каждый раз?

Да!

Повторное использование или не повторное использование экземпляра объекта зависит от дизайна и ситуации. Бывают случаи, когда лучше повторять использование объектов, и в этом случае вы можете создать поле класса для привязки к ссылке, и есть случаи, когда лучше всего создавать новый объект каждый раз (посмотрите, например, на неизменность).

Ответ 4

если вы вызываете 10 раз, в вашем стеке java будет 10 меток, каждый кадр будет действовать new(), а когда кадр закончен, он будет выпущен.

enter image description here

Ответ 5

Каждый раз, когда вы вызываете метод myMethod, код выполняется сверху, без памяти о том, что он делал при предыдущих исполнениях (если, конечно, вы не изменили некоторые поля объекта MyClass. Это означает, что каждый вы запустите этот метод, вы создадите новый объект AnotherClass и сохраните его в myObject. В более общем плане, каждое выполнение метода будет запускать код сверху и не позволит избежать перекомпоновки значений, даже если они могли бы быть кэшируется из предыдущих итераций, если вы явно не сохраняете значения где-то.

Если это не то, что вы хотите, и вместо этого вы хотите сохранить выделенный вами объект, чтобы в будущих итерациях вы могли ссылаться на него снова, вы можете сохранить его в переменной экземпляра класса.

Ответ 6

Новый объект создается каждый раз при вызове метода. Если элемент управления достигает строки кода с "новым" оператором на нем, тогда объект будет создан; там нет за кулисами кеширования или другой магии.