Tôi không hiểu tại sao một phương thức tĩnh không thể sử dụng dữ liệu không tĩnh. Bất cứ ai có thể giải thích vấn đề là gì và tại sao chúng ta không thể làm điều đó?
Tôi không hiểu tại sao một phương thức tĩnh không thể sử dụng dữ liệu không tĩnh. Bất cứ ai có thể giải thích vấn đề là gì và tại sao chúng ta không thể làm điều đó?
Câu trả lời:
Trong hầu hết các ngôn ngữ OO, khi bạn định nghĩa một phương thức bên trong một lớp, nó sẽ trở thành một Phương thức sơ thẩm . Khi bạn tạo một mới dụ của lớp đó, thông qua các new
từ khóa, bạn khởi tạo một bộ mới của dữ liệu duy nhất để chỉ trường hợp đó. Các phương thức thuộc về trường hợp đó sau đó có thể làm việc với dữ liệu bạn đã xác định trên đó.
Ngược lại, các Phương thức tĩnh là không biết gì về các cá thể lớp riêng lẻ. Phương thức tĩnh tương tự như một hàm miễn phí trong C hoặc C ++. Nó không bị ràng buộc với một khởi tạo cụ thể của lớp. Đây là lý do tại sao họ không thể truy cập các giá trị cá thể. Không có ví dụ để lấy một giá trị từ!
Dữ liệu tĩnh tương tự như một phương thức tĩnh. Một giá trị được khai báo static
không có trường hợp liên quan. Nó tồn tại cho mọi trường hợp và chỉ được khai báo ở một nơi duy nhất trong bộ nhớ. Nếu nó được thay đổi, nó sẽ thay đổi cho mọi phiên bản của lớp đó.
Một phương pháp tĩnh có thể truy cập dữ liệu tĩnh vì cả hai đều tồn tại độc lập với trường hợp cụ thể của một lớp.
Nó có thể giúp xem xét cách bạn gọi một phương thức tĩnh, so với một phương thức cá thể. Giả sử chúng ta có lớp sau (sử dụng mã giả giống như 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)
Như ĐẾN TỪ điểm ra trong các ý kiến, một phương pháp tĩnh là có khả năng làm việc với các dữ liệu không tĩnh, nhưng nó phải được thông qua một cách rõ ràng. Giả sử Foo
lớp có một phương thức khác:
public static Foo Add(Foo foo1, Foo foo2) {
return new Foo(foo1.value + foo2.value);
}
Add
vẫn còn tĩnh, và không có value
trường hợp riêng của mình, nhưng là một thành viên của lớp Foo nó có thể truy cập vào tin value
các lĩnh vực của truyền-in foo1
và foo2
các trường hợp. Trong trường hợp này, chúng tôi đang sử dụng nó để trả về một giá trị mới Foo
với các giá trị được thêm vào của cả hai giá trị được truyền vào.
Foo foo3 = Foo.Add(foo1, foo2); // creates a new Foo with a value of 30
this
-reference có sẵn. Tôi nghĩ rằng đó là cực kỳ quan trọng để hiểu.
Hãy giải thích nó với một mẫu giả thuyết.
Hãy tưởng tượng một lớp học đơn giản:
class User
{
User(string n) { name = n; };
string name;
}
Bây giờ chúng ta tạo 2 thể hiện của lớp này:
User Bones = new User("Bones");
User Jim = new User("Jim");
bây giờ, hãy suy nghĩ - điều gì sẽ xảy ra nếu chúng ta thêm một phương thức tĩnh mới vào Người dùng, ví dụ:
static string GetName();
và bạn gọi nó là:
string x = User::GetName()
x sẽ chứa cái gì? "Jim", "Xương", hay cái gì khác?
Vấn đề là một phương thức tĩnh là một phương thức duy nhất, được định nghĩa trên lớp chứ không phải các đối tượng. Kết quả là, bạn không biết nó có thể áp dụng cho đối tượng nào. Đây là lý do tại sao nó là một điều đặc biệt. Tốt nhất nên nghĩ về các phương thức tĩnh như những thứ riêng lẻ, như các hàm trong C chẳng hạn. Các ngôn ngữ như Java có chúng chứa bên trong các lớp chủ yếu là vấn đề với Java không cho phép bất cứ thứ gì tồn tại bên ngoài một lớp, do đó, các hàm như thế này phải bị buộc trong một lớp theo một cách nào đó (hơi giống như cách main () bị buộc phải bên trong một lớp cũng vậy khi tất cả các giác quan đều nói rằng nó phải là một hàm số ít, độc lập).
Dữ liệu không tĩnh được liên kết với một thể hiện của lớp. Các phương thức tĩnh (và dữ liệu) không được liên kết với một thể hiện cụ thể của lớp. Không cần phải có một thể hiện của một lớp để sử dụng các phương thức tĩnh trên nó. Ngay cả khi có (các) cá thể, Java sẽ không có cách nào để đảm bảo rằng bạn đang hoạt động trên cá thể mà bạn đang mong đợi khi bạn gọi một phương thức tĩnh. Do đó, các phương thức tĩnh không thể có quyền truy cập vào dữ liệu không tĩnh.
Nó có thể sử dụng dữ liệu thực địa; hãy xem xét mã java sau đây:
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
Ness.
Tôi nghĩ vấn đề ở đây là một sự hiểu biết.
Từ quan điểm kỹ thuật, một phương thức tĩnh được gọi từ bên trong một đối tượng sẽ hoàn toàn có khả năng nhìn thấy các trường đối tượng. Tôi mạnh mẽ nghi ngờ đây là nguyên nhân gây ra câu hỏi ngay từ đầu.
Vấn đề là các phương thức có thể được gọi từ bên ngoài đối tượng. Tại thời điểm đó, không có dữ liệu cá thể để cung cấp cho họ - và do đó không có cách nào để trình biên dịch giải quyết mã. Vì việc cho phép dữ liệu cá thể gây ra mâu thuẫn, chúng tôi không được phép cho phép dữ liệu cá thể.
Hãy nghĩ về nó như các phương thức tĩnh sống trong một chiều không hướng đối tượng.
Trong "chiều hướng đối tượng", một lớp có thể sinh ra nhiều bản ngã (ví dụ), mỗi bản ngã có lương tâm của chính nó thông qua trạng thái của nó.
Trong không gian phẳng, không có OO, một lớp không biết gì về bản ngã của họ sống trong không gian OO. Thế giới của họ phẳng và mang tính thủ tục, gần như thể OOP chưa được phát minh và như thể lớp học là một chương trình thủ tục nhỏ và dữ liệu tĩnh chỉ là các biến toàn cục.
Tôi nghĩ cách dễ nhất để giải thích điều này là xem xét một số mã và sau đó xem xét kết quả mà chúng tôi mong đợi mã sẽ tạo ra.
// 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.
Để hoàn thiện ở đây là lớp xe:
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;
}
}
Các câu trả lời khác nói lên tất cả, tuy nhiên, có một số "chi tiết" tôi muốn thêm vào.
Các phương thức tĩnh (giả sử các phương thức trong Java) chỉ không có một đối tượng ngầm liên quan đến chúng (có thể truy cập thông qua this
) mà các thành viên bạn có thể truy cập thường trực tiếp bằng tên.
Điều đó không có nghĩa là họ không thể truy cập dữ liệu không tĩnh.
class MyClass {
public static void foo(MyOtherClass object) {
System.out.println(object.member);
}
}
class MyOtherClass {
public int member = 10;
}
Tôi biết đây chỉ là một chi tiết, nhưng tôi thấy câu hỏi của bạn thật lạ khi tôi đọc nó. "Chỉ có thể sử dụng dữ liệu tĩnh" là quá nhiều hạn chế.
Nhân tiện, tôi đã không kiểm tra mã, tôi chỉ viết nó ở đây để làm gương cho những gì tôi đang nói.