Приватный финальный статический атрибут против приватного финального атрибута

В Java какая разница между:

private final static int NUMBER = 10;

а также

private final int NUMBER = 10;

Оба private а также finalразница в том static приписывать.

Что лучше? И почему?

20 ответов

В общем, static означает "связанный с самим типом, а не с экземпляром типа".

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

Test x = new Test();
Test y = new Test();
x.instanceVariable = 10;
y.instanceVariable = 20;
System.out.println(x.instanceVariable);

распечатывает 10: y.instanceVariable а также x.instanceVariable отделены, потому что x а также y ссылаются на разные объекты.

Вы можете ссылаться на статические члены через ссылки, хотя это плохая идея. Если бы мы сделали:

Test x = new Test();
Test y = new Test();
x.staticVariable = 10;
y.staticVariable = 20;
System.out.println(x.staticVariable);

тогда это напечатало бы 20 - есть только одна переменная, не одна на экземпляр. Было бы яснее написать это так:

Test x = new Test();
Test y = new Test();
Test.staticVariable = 10;
Test.staticVariable = 20;
System.out.println(Test.staticVariable);

Это делает поведение намного более очевидным. Современные IDE обычно предлагают изменить второй листинг на третий.

Нет причин иметь такую ​​декларацию, как

private final int NUMBER = 10;

Если это не может измениться, нет смысла иметь одну копию на экземпляр.

static Переменная остается в памяти в течение всего времени жизни приложения и инициализируется во время загрузки класса. Неstatic переменная инициализируется каждый раз, когда вы создаете new объект. Обычно лучше использовать:

private static final int NUMBER = 10;

Зачем? Это уменьшает объем памяти на экземпляр. Возможно, это также благоприятно для попадания в кэш. И это просто имеет смысл: static следует использовать для вещей, которые являются общими для всех экземпляров (или объектов) определенного типа (или class).

Для финала, ему могут быть присвоены разные значения во время выполнения при инициализации. Например

Class Test{
  public final int a;
}

Test t1  = new Test();
t1.a = 10;
Test t2  = new Test();
t2.a = 20; //fixed

Таким образом, каждый экземпляр имеет различное значение поля a.

Для статического final все экземпляры имеют одинаковое значение и не могут быть изменены после первой инициализации.

Class TestStatic{
      public static final int a;
}

TestStatic t1  = new TestStatic();
t1.a = 10;
TestStatic t2  = new TestStatic();
t1.a = 20;   // ERROR, CAN'T BE ALTERED AFTER THE FIRST INITIALIZATION.

Статический означает "связанный с классом"; без него переменная связана с каждым экземпляром класса. Если он статический, это означает, что у вас будет только один в памяти; если нет, у вас будет один для каждого создаваемого вами экземпляра. static означает, что переменная будет оставаться в памяти до тех пор, пока класс загружен; без него переменная может быть gc'd, когда ее экземпляр.

Читая ответы, я не нашел ни одного реального теста, подходящего к сути. Вот мои 2 цента:

public class ConstTest
{

    private final int         value             = 10;
    private static final int  valueStatic       = 20;
    private final File        valueObject       = new File("");
    private static final File valueObjectStatic = new File("");

    public void printAddresses() {


        System.out.println("final int address " +
                ObjectUtils.identityToString(value));
        System.out.println("final static int address " +
                ObjectUtils.identityToString(valueStatic));
        System.out.println("final file address " + 
                ObjectUtils.identityToString(valueObject));
        System.out.println("final static file address " + 
                ObjectUtils.identityToString(valueObjectStatic));
    }


    public static void main(final String args[]) {


        final ConstTest firstObj = new ConstTest();
        final ConstTest sndObj = new ConstTest();

        firstObj.printAdresses();
        sndObj.printAdresses();
    }

}

Результаты для первого объекта:

final int address java.lang.Integer@6d9efb05
final static int address java.lang.Integer@60723d7c
final file address java.io.File@6c22c95b
final static file address java.io.File@5fd1acd3

Результаты для 2-го объекта:

final int address java.lang.Integer@6d9efb05
final static int address java.lang.Integer@60723d7c
final file address java.io.File@3ea981ca
final static file address java.io.File@5fd1acd3

Заключение:

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

Однако существует дублирование памяти для нестатических элементов, если они не являются экземплярами примитивного типа.

Изменение значения valueStatic на 10 пойдет даже дальше, поскольку Java будет давать одинаковые адреса двум переменным int.

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

Рассмотрим следующий пример:

public class TestClass {
    private final static double NUMBER = Math.random();

    public TestClass () {
        System.out.println(NUMBER);
    }
}

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

Однако при попытке использовать следующий пример:

public class TestClass {
    private final double NUMBER = Math.random();

    public TestClass () {
        System.out.println(NUMBER);
    }
}

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

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

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

public class City {

    // base price that is always same for all objects[For all cities].
    private static double iphone_base_price = 10000;

    // this is total price = iphone_base_price+iphone_diff;
    private double iphone_citi_price;

    // extra price added to iphone_base_price. It is constant per city. Every
    // city has its own difference defined,
    private final double iphone_diff;

    private String cityName = "";

    // static final will be accessible everywhere within the class but cant be
    // changed once initialized.
    private static final String countryName = "India";

    public City(String cityName, double iphone_diff) {
        super();
        this.iphone_diff = iphone_diff;
        iphone_citi_price = iphone_base_price + iphone_diff;
        this.cityName = cityName;

    }

    /**
     * get phone price
     * 
     * @return
     */
    private double getPrice() {

        return iphone_citi_price;
    }

    /**
     * Get city name
     * 
     * @return
     */
    private String getCityName() {

        return cityName;
    }

    public static void main(String[] args) {

        // 300 is the
        City newyork = new City("Newyork", 300);
        System.out.println(newyork.getPrice() + "  " + newyork.getCityName());

        City california = new City("California", 800);
        System.out.println(california.getPrice() + "  " + california.getCityName());

        // We cant write below statement as a final variable can not be
        // reassigned
        // california.iphone_diff=1000; //************************

        // base price is defined for a class and not per instances.
        // For any number of object creation, static variable's value would be the same
        // for all instances until and unless changed.
        // Also it is accessible anywhere inside a class.
        iphone_base_price = 9000;

        City delhi = new City("delhi", 400);
        System.out.println(delhi.getPrice() + "  " + delhi.getCityName());

        City moscow = new City("delhi", 500);
        System.out.println(moscow.getPrice() + "  " + moscow.getCityName());

        // Here countryName is accessible as it is static but we can not change it as it is final as well. 
        //Something are meant to be accessible with no permission to modify it. 
        //Try un-commenting below statements
        System.out.println(countryName);

        // countryName="INDIA";
        // System.out.println(countryName);

    }

}

Закрытый статический финал будет считаться константой, а константа может быть доступна только внутри этого класса. Поскольку ключевое слово static включено, значение будет постоянным для всех объектов класса.

Закрытое окончательное значение переменной будет как константа для объекта.

Вы можете сослаться на java.lang.String или посмотреть пример ниже.

public final class Foo
{

    private final int i;
    private static final int j=20;

    public Foo(int val){
        this.i=val;
    }

    public static void main(String[] args) {
        Foo foo1= new Foo(10);

        Foo foo2= new Foo(40);

        System.out.println(foo1.i);
        System.out.println(foo2.i);
        System.out.println(check.j);
    }
}

//Выход:

10
40
20

Вот мои два цента:

final           String CENT_1 = new Random().nextInt(2) == 0 ? "HEADS" : "TAILS";
final   static  String CENT_2 = new Random().nextInt(2) == 0 ? "HEADS" : "TAILS";

Пример:

package test;

public class Test {

    final long OBJECT_ID = new Random().nextLong();
    final static long CLASSS_ID = new Random().nextLong();

    public static void main(String[] args) {
        Test[] test = new Test[5];
        for (int i = 0; i < test.length; i++){
            test[i] = new Test();
            System.out.println("Class id: "+test[i].CLASSS_ID);//<- Always the same value
            System.out.println("Object id: "+test[i].OBJECT_ID);//<- Always different
        }
    }
}

Ключевым моментом является то, что переменные и функции могут возвращать разные значения. Поэтому конечные переменные могут быть назначены с разными значениями.

Кроме того, к ответу Джона, если вы используете static final, он будет вести себя как своего рода "определение". Как только вы скомпилируете класс, который его использует, он будет сожжен в скомпилированном файле.class. Проверьте мою ветку об этом здесь.

Для вашей главной цели: если вы не используете NUMBER по-разному в разных экземплярах класса, я бы посоветовал использовать final и static.(Вы просто должны помнить, чтобы не копировать скомпилированные файлы классов без учета возможных проблем, подобных описанным в моем примере. В большинстве случаев этого не происходит, не волнуйтесь:))

Чтобы показать, как использовать разные значения в экземплярах, проверьте этот код:

public class JustFinalAttr {
  public final int Number;

  public JustFinalAttr(int a){
    Number=a;
  }
}

...System.out.println(new JustFinalAttr(4).Number);

Как уже сказал Джон, статическая переменная, также называемая переменной класса, является переменной, которая существует во всех экземплярах класса.

Я нашел пример этого здесь:

public class StaticVariable
{
  static int noOfInstances;
  StaticVariable()
  {
    noOfInstances++;
  }
  public static void main(String[] args)
  {
    StaticVariable sv1 = new StaticVariable();
    System.out.println("No. of instances for sv1 : " + sv1.noOfInstances);

    StaticVariable sv2 = new StaticVariable();
    System.out.println("No. of instances for sv1 : "  + sv1.noOfInstances);
    System.out.println("No. of instances for st2 : "  + sv2.noOfInstances);

    StaticVariable sv3 = new StaticVariable();
    System.out.println("No. of instances for sv1 : "  + sv1.noOfInstances);
    System.out.println("No. of instances for sv2 : "  + sv2.noOfInstances);
    System.out.println("No. of instances for sv3 : "  + sv3.noOfInstances);
  }
}

Вывод программы приведен ниже:

Как мы видим в этом примере, каждый объект имеет свою собственную копию переменной класса.

C:\java>java StaticVariable
No. of instances for sv1 : 1
No. of instances for sv1 : 2
No. of instances for st2 : 2
No. of instances for sv1 : 3
No. of instances for sv2 : 3
No. of instances for sv3 : 3

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

Например:

class A
{
    final int f;
    static final int sf = 5;

    A(int num)
    {
        this.f = num;
    }

    void show()
    {
        System.out.printf("About Object: %s\n Final: %d\n Static Final: %d\n\n", this.toString(), this.f, sf);
    }

    public static void main(String[] args)
    {
        A ob1 = new A(14);
        ob1.show();

        A ob2 = new A(21);
        ob2.show();

    }
}

На экране появляется следующее:

Об объекте: A@addbf1 Финал: 14 Статический Финал: 5

Об объекте: A@530daa Финал: 21 Статический финал: 5

Анонимный студент 1 курса IT, Греция

очень мало и статично

Нет большой разницы, так как они оба постоянные. Для большинства объектов данных класса static будет означать что-то, связанное с самим классом, поскольку существует только одна копия, независимо от того, сколько объектов было создано с новым.

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

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

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

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

Скажем, если у класса не будет больше одного экземпляра, какой из них занимает больше памяти:

приватная статическая конечная int ID = 250; или приватный конечный int ID = 250;

Я понял, что static будет ссылаться на тип класса только с одной копией в памяти, а non static будет в новом месте памяти для каждой переменной экземпляра. Однако внутренне, если мы просто сравним 1 экземпляр одного и того же класса когда-либо (то есть более 1 экземпляр не будет создан), то есть ли какие-либо издержки с точки зрения пространства, используемого 1 статической конечной переменной?

Статический элемент является одним и тем же членом во всех экземплярах класса и самого класса.
Нестатический - один для каждого экземпляра (объекта), так что в вашем конкретном случае это пустая трата памяти, если вы не установите static.

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

Однако теперь вы можете сделать переменную общедоступной, поскольку никто не может изменить ее так же, как "System.out", она снова зависит от ваших намерений и того, чего вы хотите достичь.

Статическая переменная принадлежит классу (что означает, что все объекты имеют эту переменную). Нестатическая переменная принадлежит каждому объекту.

public class ExperimentFinal {

private final int a;
private static final int b = 999; 

public ExperimentFinal(int a) {
    super();
    this.a = a;
}
public int getA() {
    return a;
}
public int getB() {
    return b;
}
public void print(int a, int b) {
    System.out.println("final int: " + a + " \nstatic final int: " + b);
}
public static void main(String[] args) {
    ExperimentFinal test = new ExperimentFinal(9);
    test.print(test.getA(), test.getB());
} }

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

Это может помочь

public class LengthDemo {
public static void main(String[] args) {
    Rectangle box = new Rectangle();
    System.out.println("Sending the value 10.0 "
            + "to the setLength method.");
    box.setLength(10.0);
    System.out.println("Done.");
    }
}

Ключевое слово "Static" делает свойство переменной класса, а не отдельные экземпляры класса. Будет одна копия этой переменной, которая будет использоваться всеми экземплярами этого класса. Любое изменение состояния статической переменной будет отражено во всех экземплярах. Добавьте final к static, и мы получим переменную, которая была инициализирована раз и навсегда во время загрузки класса и не может быть изменена позже ни одним экземпляром класса. Статические конечные переменные должны быть инициализированы во время объявления, иначе у нас будет ошибка времени компиляции. Что касается поля частного экземпляра, оно относится к свойству / состоянию объекта / экземпляра класса. Каждый экземпляр / объект класса будет иметь свою собственную копию переменной экземпляра. Когда переменная экземпляра объявляется окончательной,это означает, что мы не можем изменить его значение для этого экземпляра. Для этого нам нужно инициализировать конечную переменную либо при объявлении, либо в конструкторе. Если это не сделано ни в одном из них, будет отображаться ошибка времени компиляции. После инициализации, если вы попытаетесь переназначить значение, вы получите ошибку времени компиляции. Используйте статические конечные переменные, где данные будут совместно использоваться всеми экземплярами класса, и вы хотите, чтобы данные были доступны только для чтения. Используйте конечную переменную экземпляра, если вы хотите представить некоторые данные, которые принадлежат каждому отдельному экземпляру класса, но один раз сохраненные не могут быть изменены. Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Для этого нам нужно инициализировать конечную переменную либо при объявлении, либо в конструкторе. Если это не сделано ни в одном из них, будет отображаться ошибка времени компиляции. После инициализации, если вы попытаетесь переназначить значение, вы получите ошибку времени компиляции. Используйте статические конечные переменные, где данные будут совместно использоваться всеми экземплярами класса, и вы хотите, чтобы данные были доступны только для чтения. Используйте конечную переменную экземпляра, если вы хотите представить некоторые данные, которые принадлежат каждому отдельному экземпляру класса, но один раз сохраненные не могут быть изменены. Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Для этого нам нужно инициализировать конечную переменную либо при объявлении, либо в конструкторе. Если это не сделано ни в одном из них, будет отображаться ошибка времени компиляции. После инициализации, если вы попытаетесь переназначить значение, вы получите ошибку времени компиляции. Используйте статические конечные переменные, где данные будут совместно использоваться всеми экземплярами класса, и вы хотите, чтобы данные были доступны только для чтения. Используйте конечную переменную экземпляра, если вы хотите представить некоторые данные, которые принадлежат каждому отдельному экземпляру класса, но один раз сохраненные не могут быть изменены. Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Если этого не сделать ни в одном из них, отобразится ошибка времени компиляции. После инициализации, если вы попытаетесь переназначить значение, вы получите ошибку времени компиляции. Используйте статические конечные переменные, где данные будут совместно использоваться всеми экземплярами класса, и вы хотите, чтобы данные были доступны только для чтения. Используйте конечную переменную экземпляра, если вы хотите представить некоторые данные, которые принадлежат каждому отдельному экземпляру класса, но один раз сохраненные не могут быть изменены. Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Если этого не сделать ни в одном из них, отобразится ошибка времени компиляции. После инициализации, если вы попытаетесь переназначить значение, вы получите ошибку времени компиляции. Используйте статические конечные переменные, где данные будут совместно использоваться всеми экземплярами класса, и вы хотите, чтобы данные были доступны только для чтения. Используйте конечную переменную экземпляра, если вы хотите представить некоторые данные, которые принадлежат каждому отдельному экземпляру класса, но один раз сохраненные не могут быть изменены. Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Используйте статические конечные переменные, где данные будут совместно использоваться всеми экземплярами класса, и вы хотите, чтобы данные были доступны только для чтения. Используйте конечную переменную экземпляра, если вы хотите представить некоторые данные, которые принадлежат каждому отдельному экземпляру класса, но один раз сохраненные не могут быть изменены. Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Используйте статические конечные переменные, где данные будут совместно использоваться всеми экземплярами класса, и вы хотите, чтобы данные были доступны только для чтения. Используйте конечную переменную экземпляра, если вы хотите представить некоторые данные, которые принадлежат каждому отдельному экземпляру класса, но один раз сохраненные не могут быть изменены. Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.Использование статического ключевого слова и ключевого слова экземпляра зависит от потребностей вашего дизайна и того, что эти данные представляют в домене. Если данные используются в экземплярах класса, то нет необходимости в отдельных копиях / ссылках на память для каждого объекта.

Другие вопросы по тегам