помогите со статическими переменными в Java - PullRequest
3 голосов
/ 30 июня 2010

У меня есть класс,

class MyClass {
    private int val;
    public static final MyClass myObject = new MyClass(1);
    MyClass(int a){
        val = a;
    }
    public int getVal(){
        return val;
    }
    public MyClass func1(){
        MyClass temp = myObject;
        temp.val = 2;
        return temp;
    }
    public static void main(String [] args){
        MyClass x = new MyClass(4);
        System.out.println(myObject.getVal());
        x.func1();
        System.out.println(myObject.getVal());
    }
}

Он печатает:

 1
 2

Я ожидал, что он напечатает:

 1 
 1

Кажется, с моей стороны есть фундаментальное недоразумение. Я ожидал, что myObject как значение final static не может быть изменено, и когда я делаю MyClass temp = myObject, я создаю новый объект с именем temp типа MyClass и присваиваю значение myObject этому новому созданный объект. Пожалуйста, поправьте меня, если я ошибаюсь. Похоже, что новый объект не создан и temp просто указывает на исходный myObject

РЕДАКТИРОВАТЬ: Спасибо за ответы! Теперь я понимаю, что оператор = никогда не делает копию объекта, он просто копирует ссылку. Мне нужно сделать копию myObject и сохранить ее в temp. Каков наилучший способ добиться этого?

EDIT2: еще один странный поведение или особенность Java?

Я немного изменил код

class MyClass {
    private Integer val;
    public static final MyClass myObject = new MyClass(1);
    MyClass(int a){
        val = a;
    }
    public int getVal(){
        return val;
    }
    public MyClass func1(){
        MyClass temp = new MyClass(33);
        temp.val = myObject.val;
        temp.val = 2;
        return temp;
    }
    public static void main(String [] args){
        MyClass x = new MyClass(4);
        System.out.println(myObject.getVal());
        MyClass y = x.func1();
        System.out.println(x.getVal());
        System.out.println(y.getVal());
        System.out.println(myObject.getVal());
    }
}

вывод

 1
 4
 2
 1

Поэтому, когда я создаю temp с использованием new MyClass(33) и затем устанавливаю temp.val = 2, он фактически создает копию val. Другими словами, temp.val не указывает на myObject.val. Почему это так?

Ответы [ 7 ]

7 голосов
/ 30 июня 2010
MyClass temp = myObject;

Это не создание нового экземпляра, это просто присвоение ссылки, чтобы temp указывал на тот же экземпляр, что и myObject.

Итак, ваше утверждение:

Я создаю новый объект с именем temp тип MyClass

неверно, так как вы не создаете новый объект здесь, просто присваиваете ссылку на объект.

EDIT Если ваша цель состоит в том, чтобы сделать копию myObject и вернуть ее из func1(), то вы можете сделать это (под копией я предполагаю, что вы имеете в виду также копирование значения val, если вы хотите использовать другое значение для val тогда вы можете настроить этот код соответственно):

public MyClass func1(){
    MyClass temp = new MyClass(myObject.getVal());
    return temp;
}
5 голосов
/ 30 июня 2010

Поле равно final, что означает, что вы не можете переназначить поле.Ваш myObject var, однако, не является неизменным.Когда вы звоните func1() на ваш myObject, вы меняете myObject.val на 2.

2 голосов
/ 30 июня 2010

Вы получаете ссылку на экземпляр объекта MyClass и изменяете один из его членов.Эта ссылка не является неизменной;только поле с именем myObj является неизменным.

1 голос
/ 30 июня 2010

После прочтения опубликованных ответов:

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

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

http://www.javapractices.com/topic/TopicAction.do?Id=29

или

http://java.sun.com/docs/books/tutorial/essential/concurrency/imstrat.html

1 голос
/ 30 июня 2010

В Java оператор = назначает ссылки, а не объекты, как в C ++.

Последнее поле может быть назначено только один раз.Это не означает, что объекты, доступные через конечное поле, не могут быть изменены.

Иными словами: в отличие от const в C ++, final защищает только ссылку, а не объект.

1 голос
/ 30 июня 2010

Я думаю, вы как бы ответили на свой вопрос. Вы правы, говоря, что на самом деле новый объект, созданный строкой MyClass temp = myObject; temp, не является ссылкой на ваш статический экземпляр myClass.

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

public MyClass func1(){
    MyClass temp = myObject;
    System.out.println(myObject == temp);//print true
    temp.val = 2;
    return temp;
}
0 голосов
/ 30 июня 2010

Определение окончательного состояния модификатора, что ссылка на объект не может быть изменена.В первом фрагменте кода

public static final MyClass myObject = new MyClass(1);

myObject является окончательной ссылкой, указывающей на объект с val = 1.Однако это не означает, что содержимое объекта не может быть изменено.функция func1 () получает ссылку на объект со значением 1 и изменяет его значение val на 2. тем самым оно совершенно допустимо.

для второго фрагмента

public MyClass func1(){
    MyClass temp = new MyClass(33);
    temp.val = myObject.val;
    temp.val = 2;
    return temp;
}
public static void main(String [] args){
    MyClass x = new MyClass(4);              //line A
    System.out.println(myObject.getVal());  //returns 1
    MyClass y = x.func1();                  //line B
    System.out.println(x.getVal());         //line C
    System.out.println(y.getVal());         //line D
    System.out.println(myObject.getVal());
}

в строке A objс val 4 создан.В строке B вызывается func1, который в итоге создает новый объект с val = 33, который затем изменяется на val = 1, а затем val = 2.В строке C мы получаем вывод 4 из объекта, созданного в строке A.В строке D мы получаем вывод 2 из изменений, которые мы сделали при использовании строки B.В строке E мы получаем вывод 1 из статического конечного объекта, который не изменяется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...