В Java, какая разница между:
private final static int NUMBER = 10;
и
private final int NUMBER = 10;
Оба являются private
и final
, разница - это атрибут static
.
Что лучше? И почему?
В Java, какая разница между:
private final static int NUMBER = 10;
и
private final int NUMBER = 10;
Оба являются private
и final
, разница - это атрибут static
.
Что лучше? И почему?
В общем случае 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;
Если он не может измениться, то нет экземпляра на экземпляр.
Для final ему могут быть присвоены разные значения во время выполнения при инициализации. Например,
Class Test{
public final int a;
}
Test t1 = new Test();
t1.a = 10;
Test t2 = new Test();
t2.a = 20; //fixed
Таким образом, каждый экземпляр имеет различное значение поля a.
Для static 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.
A static
переменная остается в памяти на протяжении всего срока службы приложения и инициализируется во время загрузки класса. Переменная non static
инициализируется каждый раз, когда вы создаете объект new
. Обычно лучше использовать:
private static final int NUMBER = 10;
Почему? Это уменьшает объем памяти в каждом экземпляре. Возможно, это также благоприятно для хитов кэша. И это имеет смысл: static
следует использовать для вещей, которые совместно используются во всех экземплярах (объекты a.k.a.) определенного типа (a.k.a. class
).
static означает "связанный с классом"; без него переменная связана с каждым экземпляром класса. Если он статичен, значит, у вас будет только один в памяти; если нет, у вас будет один для каждого создаваемого вами экземпляра. 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 [email protected]
final static int address [email protected]
final file address [email protected]
final static file address [email protected]
Результаты для 2-го объекта:
final int address [email protected]
final static int address [email protected]
final file address [email protected]
final static file address [email protected]
Заключение:
Как я думал, 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 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-го курса, Греция
Кроме того, Джон отвечает, если вы используете статический финал, он будет вести себя как своего рода "определение". После компиляции класса, который его использует, он будет скомпилирован. Проверьте мою тему об этом здесь.
Для вашей основной цели: если вы не используете NUMBER по-разному в разных экземплярах класса, я бы посоветовал использовать final и static. (Вам просто нужно иметь в виду не копировать скомпилированные файлы классов, не учитывая возможные проблемы, как описано в моем примере. Большинство случаев этого не происходит, не беспокойтесь:))
Чтобы показать вам, как использовать разные значения в экземплярах, проверьте этот код:
public class JustFinalAttr {
public final int Number;
public JustFinalAttr(int a){
Number=a;
}
}
...System.out.println(new JustFinalAttr(4).Number);
Вот мои два цента:
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
}
}
}
Ключ состоит в том, что переменные и функции могут возвращать разные значения. Поэтому конечным переменным может присваиваться разные значения.
Нет большой разницы, поскольку они оба являются константами. Для большинства объектов данных класса статичность означает нечто, связанное с самим классом, причем имеется только одна копия независимо от того, сколько объектов было создано с помощью нового.
Поскольку он является константой, он не может быть фактически сохранен ни в классе, ни в экземпляре, но компилятор по-прежнему не позволяет вам обращаться к экземплярам объектов из статического метода, даже если он знает, что они быть. Существование API отражения может также потребовать некоторой бессмысленной работы, если вы не сделаете его статическим.
Так как переменная в классе объявлена как final И инициализирована в той же команде, нет абсолютно никаких оснований не объявлять его как статичным, так как он будет иметь такое же значение независимо от экземпляра. Таким образом, все экземпляры могут совместно использовать один и тот же адрес памяти для значения, тем самым экономя время обработки, устраняя необходимость создания новой переменной для каждого экземпляра и сохраняя память, разделяя один общий адрес.
private static final будет считаться константой, а константу можно получить только в этом классе. Поскольку ключевое слово 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
Статический - это один и тот же член во всех экземплярах класса и самом классе.
Нестатический - один для каждого экземпляра (объекта), поэтому в вашем конкретном случае это пустая трата памяти, если вы не ставите статическую.
Если вы помечаете эту переменную static, то, как вы знаете, вам потребуются статические методы для повторного доступа к этим значениям, это будет полезно, если вы уже думаете об использовании этих переменных только в статических методах. Если это так, тогда это будет лучшим.
Однако вы можете сделать переменную теперь общедоступной, так как никто не может ее изменить так же, как "System.out", она снова зависит от ваших намерений и того, чего вы хотите достичь.
Давайте скажем, если класс будет иметь не один экземпляр, а затем какой-то другой памяти:
private static final int ID = 250; или private final int ID = 250;
Я понял, что static будет ссылаться на тип класса только с одной копией в памяти, а нестационарная будет в новой ячейке памяти для каждой переменной экземпляра. Однако внутренне, если мы просто сравниваем один экземпляр одного и того же класса (т.е. Более 1 экземпляр не будет создан), тогда есть ли какие-либо накладные расходы в пространстве, используемом 1 статической конечной переменной?
Статическая переменная принадлежит классу (что означает, что все объекты разделяют эту переменную). Нестационарная переменная принадлежит к каждому объекту.
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 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 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, значение переменной будет одинаковым во всех ваших экземплярах, при изменении в одном экземпляре другие тоже изменятся.
Конечная: после назначения конечной переменной она всегда содержит одно и то же значение. где переменная является статической или нет статический: это будет только одна переменная для всех экземпляров, инициализированных один раз в памяти
Это может помочь
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.");
}
}