[英]private final static attribute vs private final attribute
在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 通常会建议将第二个列表更改为第三个。
没有理由像下面那样使用内联声明来初始化值,因为每个实例都有自己的NUMBER
但始终具有相同的值(不可变并用文字初始化)。 这与所有实例只有一个final static
变量相同。
private final int NUMBER = 10;
因此,如果它无法更改,则每个实例只有一个副本是没有意义的。
但是,如果在这样的构造函数中初始化是有道理的:
// No initialization when is declared
private final int number;
public MyClass(int n) {
// The variable can be assigned in the constructor, but then
// not modified later.
number = n;
}
现在,对于MyClass
每个实例,我们可以有一个不同但不可变的number
值。
对于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 = 0;
}
TestStatic t1 = new TestStatic();
t1.a = 10; // ERROR, CAN'T BE ALTERED AFTER THE FIRST
TestStatic t2 = new TestStatic();
t1.a = 20; // ERROR, CAN'T BE ALTERED AFTER THE FIRST INITIALIZATION.
static
变量在应用程序的整个生命周期中都保留在内存中,并在类加载期间进行初始化。 每次构造new
对象时都会初始化一个非static
变量。 通常最好使用:
private static final int NUMBER = 10;
为什么? 这减少了每个实例的内存占用。 它也可能有利于缓存命中。 这很有意义: static
应该用于在特定类型(又名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 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
第二个对象的结果:
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 的三个实例现在将打印三个不同的随机值,因为每个实例都有自己随机生成的常量值。
我想不出任何情况下在不同实例上使用不同的常量值真的很有用,但我希望这有助于指出静态和非静态 final 之间存在明显差异。
没有太大区别,因为它们都是常数。 对于大多数类数据对象,静态意味着与类本身相关联的东西,无论用 new 创建了多少对象,都只有一个副本。
由于它是一个常量,它实际上可能不会存储在类或实例中,但编译器仍然不会让您从静态方法访问实例对象,即使它知道它们将是什么。 如果您不将其设为静态,反射 API 的存在也可能需要一些毫无意义的工作。
正如 Jon 已经说过的,静态变量,也称为类变量,是一个跨类实例存在的变量。
我在这里找到了一个例子:
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
此外,对于 Jon 的回答,如果您使用 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);
这是我的两分钱:
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
}
}
}
关键是变量和函数可以返回不同的值。因此最终变量可以分配不同的值。
只是另一个简单的例子来理解静态、静态最终、最终变量的用法。 代码注释有正确的解释。
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);
}
}
从我所做的测试来看,静态最终变量与最终(非静态)变量不同! 最终(非静态)变量可能因对象而异!!! 但这仅当在构造函数中进行初始化时! (如果它不是从构造函数初始化,那么它只会浪费内存,因为它为每个创建的对象创建了无法更改的最终变量。)
例如:
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 学生,希腊
由于类中的变量在同一命令中声明为 final 并初始化,因此绝对没有理由不将其声明为 static,因为无论实例如何,它都将具有相同的值。 因此,所有实例都可以为一个值共享相同的内存地址,从而通过消除为每个实例创建新变量的需要以及通过共享 1 个公共地址来节省内存来节省处理时间。
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
静态成员是所有类实例和类本身的相同成员。
非静态是每个实例(对象)的一个,因此在您的确切情况下,如果您不放置静态,则会浪费内存。
静态变量属于类(这意味着所有对象共享该变量)。 非静态变量属于每个对象。
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”,我们应该在类中分配一个变量(静态变量属于类)。
如果您将此变量标记为静态,那么正如您所知,您将需要静态方法来再次访问这些值,如果您已经考虑仅在静态方法中使用这些变量,这将非常有用。 如果是这样,那么这将是最好的。
但是,您现在可以将变量设为公开,因为没有人可以像“System.out”那样修改它,这又取决于您的意图和想要实现的目标。
如果您使用 static 变量的值将在您的所有实例中相同,如果在一个实例中更改,其他实例也会更改。
Final:一旦分配了 final 变量,它总是包含相同的值。 无论变量是静态的还是非静态的:对于在内存中初始化一次的所有实例,它只会是一个变量
假设该类永远不会有多个实例,那么哪一个需要更多内存:
私有静态最终整数 ID = 250; 或私有最终 int ID = 250;
我已经理解静态将指代在内存中只有一个副本的类类型,非静态将在每个实例变量的新内存位置中。 但是在内部,如果我们只是比较同一类的 1 个实例(即不会创建 1 个以上的实例),那么在 1 个静态最终变量使用的空间方面是否有任何开销?
这可能有帮助
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.");
}
}
“静态”关键字使类的可变属性而不是类的单个实例。 该变量的一个副本将在该类的所有实例之间共享。 静态变量状态的任何变化都将反映在所有实例中。 将 final 添加到 static 中,我们得到一个在类加载时一劳永逸地初始化的变量,以后不能被类的任何实例更改。 静态最终变量需要在声明时初始化,否则我们会出现编译时错误。 就私有实例字段而言,它指的是对象的属性/状态/类的实例。 类的每个实例/对象都有自己的实例变量副本。 当实例变量被声明为 final 时,这意味着我们不能为这个实例改变它的值。 为此,我们需要在声明或构造函数中初始化最终变量。如果没有在其中任何一个中完成,将显示编译时错误。 一旦初始化,如果您尝试重新分配一个值,您将收到编译时错误。 使用静态最终变量,其中数据将在类的所有实例之间共享,并且您希望数据是只读的。如果您想表示属于类的每个单独实例的某些数据,请使用实例最终变量但一次存储无法更改。 静态和实例关键字的使用取决于您的设计需求以及该数据在域中代表什么。 如果跨类实例使用数据,则不需要每个对象的单独副本/内存引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.