我不明白为什么静态方法不能使用非静态数据。谁能解释什么是问题,为什么我们不能解决?
我不明白为什么静态方法不能使用非静态数据。谁能解释什么是问题,为什么我们不能解决?
Answers:
在大多数OO语言中,当您在类中定义方法时,它便成为Instance Method。当您通过关键字创建该类的新实例时new
,将初始化该实例唯一的一组新数据。然后,属于该实例的方法可以使用您在其上定义的数据。
相比之下,静态方法对单个类实例一无所知。静态方法类似于C或C ++中的自由函数。它与类的特定实例无关。这就是为什么他们无法访问实例值的原因。没有任何实例可以借鉴!
静态数据类似于静态方法。声明的值static
没有关联的实例。它在每个实例中都存在,并且仅在内存中的单个位置声明。如果更改,则该类的每个实例都会更改。
一个静态方法可以访问静态数据,因为它们都独立存在的一类特定的实例。
与实例方法相比,看一下如何调用静态方法可能会有所帮助。假设我们有以下类(使用类似Java的伪代码):
class Foo {
// This static value belongs to the class Foo
public static final string name = "Foo";
// This non-static value will be unique for every instance
private int value;
public Foo(int value) {
this.value = value;
}
public void sayValue() {
println("Instance Value: " + value);
}
public static void sayName() {
println("Static Value: " + name);
}
}
Foo foo1 = new Foo(10);
Foo foo2 = new Foo(20);
foo1.sayValue(); // Prints "Instance Value: 10" - called on foo1
foo2.sayValue(); // Prints "Instance Value: 20" - called on foo2
Foo.sayName(); // Prints "Static Value: Foo" - called on Foo (not foo1 or foo2)
由于前来指出的评论,静态方法是能够与非静态数据的工作,但必须明确地传递。假设Foo
该类具有另一个方法:
public static Foo Add(Foo foo1, Foo foo2) {
return new Foo(foo1.value + foo2.value);
}
Add
仍然是静态的,没有value
自己的实例,但作为类Foo的成员,它可以访问私有value
传入的领域foo1
和foo2
实例。在这种情况下,我们使用它来返回带有两个传入值的添加值的新 Foo
值。
Foo foo3 = Foo.Add(foo1, foo2); // creates a new Foo with a value of 30
this
-reference可用。我认为了解这一点至关重要。
让我们用一个假设的样本来解释它。
想象一个简单的类:
class User
{
User(string n) { name = n; };
string name;
}
现在,我们创建该类的2个实例:
User Bones = new User("Bones");
User Jim = new User("Jim");
现在,考虑-如果我们向User添加新的静态方法,例如:
static string GetName();
然后您将其称为:
string x = User::GetName()
x将包含什么?“吉姆”,“骨头”还是其他?
问题在于静态方法是在类上定义的单个方法,而不是对象。结果,您不知道它可能适用于哪个对象。这就是为什么它很特别的原因。最好将静态方法视为独立的事物,例如C中的函数。Java之类的语言将它们包含在类中主要是Java不允许在类外部存在任何内容的问题,因此必须以某种方式将此类函数强制在类内部(有点像main()被强制为在所有意义上说它应该是一个单一的独立函数时,也可以在类中使用)。
它可以使用现场数据;考虑下面的java代码:
class MyBean {
private String myString;
static void myStaticMethod() {
myString = "tada";/*not allowed; if this was possible how would
be different from a field without static?*/
MyBean myBean = new MyBean();//allowed if associated with an instance
myBean.myString = "tada";
}
}
static
。
我认为这里的问题是一种理解。
从技术角度来看,从对象内部调用的静态方法将非常有能力查看实例字段。我强烈怀疑这是首先导致问题的原因。
问题是方法可以从对象外部调用。那时没有实例数据可以提供它们,因此编译器无法解析代码。由于允许实例数据引起了矛盾,因此我们绝对不能允许实例数据。
我认为解释此问题的最简单方法是先查看一些代码,然后考虑我们期望代码产生的结果。
// Create three new cars. Cars have a name attribute.
Car car1 = new Car("Mazda3");
Car car2 = new Car("FordFocus");
Car car3 = new Car("HondaFit");
// Now we would like to print the names of some cars:
// First off why don't we try this:
Car.printCarName();
// Expected behaviour:
// If we think about what we are trying to do here it doesn't
// really make sense. What instance of car name should this
// print? Should it print Mazda3? FordFoucs?
// What is the expected behaviour? If we are going to have a
// static call on car call printCarName it should probably do
// something like print all car names or a random car name or
// throw an error.
//Now lets try this instead:
Car.printCarName(car1);
// Expected Behaviour:
// Luckily the expected behaviour is very clear here. This
// should print Mazda3. This works as expected.
// Finally lets try this:
car1.printMyName();
// Expected Behaviour:
// Same as previous example, however this is the *right* way
// to do it.
为了完整起见,这里是汽车类:
public class Car{
public String name;
public Car(String name){
this.name = name;
}
public static printCarName(){
print "Not sure what to do here... Don't know which car you are talking about.";
}
public static printCarName(Car c){
print c.name;
}
public /*NOT static*/ printMyName(){
print this.name;
}
}
其他答案几乎说明了一切,但是,我想补充一些“细节”。
静态方法(例如Java中的静态方法)只是没有与之关联的隐式对象(可通过访问this
),通常可以通过名称直接访问其成员。
这并不意味着他们无法访问非静态数据。
class MyClass {
public static void foo(MyOtherClass object) {
System.out.println(object.member);
}
}
class MyOtherClass {
public int member = 10;
}
我知道这只是一个细节,但是当我阅读它时,发现您的问题很奇怪。“只能使用静态数据”限制太多。
顺便说一句,我没有测试代码,我只是在这里写它,以例证我在说什么。