Biến không tĩnh không thể được tham chiếu từ ngữ cảnh tĩnh


288

Tôi đã viết mã kiểm tra này:

class MyProgram
{
    int count = 0;
    public static void main(String[] args)
    {
        System.out.println(count);
    }
}

Nhưng nó đưa ra lỗi sau:

Main.java:6: error: non-static variable count cannot be referenced from a static context
        System.out.println(count);
                           ^

Làm thế nào để tôi có được các phương thức của mình để nhận ra các biến lớp?


Cố gắng tránh sử dụng tĩnh bất cứ khi nào có thể. Bạn có thể viết một chương trình hoàn chỉnh, tất cả tĩnh, giống như trong C. Nhưng nó sẽ không phải là một thứ rất tốt. Cố gắng sử dụng Java theo cách nó được sử dụng, như một ngôn ngữ hướng đối tượng.
Erick G. Hagstrom

Câu trả lời:


294

Bạn phải hiểu sự khác biệt giữa một lớp và một thể hiện của lớp đó. Nếu bạn nhìn thấy một chiếc xe hơi trên đường phố, bạn sẽ biết ngay đó là một chiếc xe ngay cả khi bạn không thể nhìn thấy mẫu hoặc loại. Điều này là do bạn so sánh những gì bạn thấy với lớp "xe hơi". Các lớp chứa tương tự như tất cả các xe. Hãy nghĩ về nó như một khuôn mẫu hoặc một ý tưởng.

Đồng thời, chiếc xe bạn nhìn thấy là một ví dụ của lớp "xe hơi" vì nó có tất cả các đặc tính mà bạn mong đợi: Có ai đó lái nó, nó có động cơ, bánh xe.

Vì vậy, lớp nói "tất cả các xe đều có màu" và ví dụ nói "chiếc xe cụ thể này có màu đỏ".

Trong thế giới OO, bạn xác định lớp và bên trong lớp, bạn xác định trường loại Color. Khi lớp được khởi tạo (khi bạn tạo một thể hiện cụ thể), bộ nhớ được dành riêng cho màu sắc và bạn có thể cung cấp cho cá thể cụ thể này một màu. Vì các thuộc tính này là cụ thể, chúng không tĩnh.

Các trường và phương thức tĩnh được chia sẻ với tất cả các trường hợp. Chúng dành cho các giá trị dành riêng cho lớp và không phải là một thể hiện cụ thể. Đối với các phương thức, đây thường là các phương thức trợ giúp toàn cầu (như Integer.parseInt()). Đối với các trường, nó thường là hằng số (như các loại ô tô, tức là thứ mà bạn có bộ giới hạn không thay đổi thường xuyên).

Để giải quyết vấn đề của bạn, bạn cần khởi tạo một thể hiện (tạo một đối tượng) của lớp để thời gian chạy có thể dự trữ bộ nhớ cho cá thể (nếu không, các thể hiện khác nhau sẽ ghi đè lên nhau mà bạn không muốn).

Trong trường hợp của bạn, hãy thử mã này như một khối bắt đầu:

public static void main (String[] args)
{
    try
    {
        MyProgram7 obj = new MyProgram7 ();
        obj.run (args);
    }
    catch (Exception e)
    {
        e.printStackTrace ();
    }
}

// instance variables here

public void run (String[] args) throws Exception
{
    // put your code here
}

main()Phương thức mới tạo một thể hiện của lớp mà nó chứa (nghe có vẻ lạ nhưng vì main()được tạo bằng lớp thay vì với thể hiện, nên nó có thể làm điều này) và sau đó gọi một phương thức cá thể ( run()).


Tôi đang giải thích điều này vào lúc này cho đồng nghiệp mới của chúng tôi - cảm ơn vì lời giải thích tuyệt vời này. Điều này nên chấp nhận câu trả lời.
Supahupe

83

Các trường và phương thức tĩnh được kết nối với chính lớp đó chứ không phải các thể hiện của nó. Nếu bạn có một lớp A, một phương thức 'bình thường' bvà một phương thức tĩnh cvà bạn tạo một thể hiện acủa lớp của bạn A, các cuộc gọi đến A.c()a.b()hợp lệ. Phương thức c()không có ý tưởng nào được kết nối, vì vậy nó không thể sử dụng các trường không tĩnh.

Giải pháp cho bạn là bạn làm cho các trường của bạn tĩnh hoặc các phương thức của bạn không tĩnh. Bạn chính có thể trông như thế này sau đó:

class Programm {

    public static void main(String[] args) {
        Programm programm = new Programm();
        programm.start();
    }

    public void start() {
        // can now access non-static fields
    }
}

54

Các statictừ khóa sẽ thay đổi vòng đời của một phương pháp hoặc biến bên trong một lớp. Một staticphương thức hoặc biến được tạo tại thời điểm một lớp được tải. Một phương thức hoặc biến không được khai báo staticlà chỉ được tạo khi lớp được khởi tạo như một đối tượng chẳng hạn bằng cách sử dụng newtoán tử.

Vòng đời của một lớp, theo nghĩa rộng, là:

  1. mã nguồn cho lớp được viết tạo ra một mẫu hoặc mẫu hoặc tem mà sau đó có thể được sử dụng để
  2. tạo một đối tượng với newtoán tử bằng cách sử dụng lớp để tạo một thể hiện của lớp như một đối tượng thực tế và sau đó khi được thực hiện với đối tượng
  3. phá hủy đối tượng lấy lại các tài nguyên mà nó đang giữ như bộ nhớ trong quá trình thu gom rác.

Để có một điểm vào ban đầu cho một ứng dụng, Java đã thông qua quy ước rằng chương trình Java phải có một lớp có chứa một phương thức với một tên đặc biệt hoặc theo thỏa thuận. Phương pháp đặc biệt này được gọi là main(). Do phương thức phải tồn tại cho dù lớp chứa phương thức chính đã được khởi tạo hay chưa, nên main()phương thức phải được khai báo bằng công cụ staticsửa đổi để ngay khi lớp được tải, main()phương thức có sẵn.

Kết quả là khi bạn khởi động ứng dụng Java của mình bằng một dòng lệnh, chẳng hạn như java helloworldmột loạt các hành động xảy ra. Trước hết, Máy ảo Java được khởi động và khởi tạo. Tiếp theo, tệp helloworld. Class chứa mã Java đã biên dịch được tải vào Máy ảo Java. Sau đó, Máy ảo Java tìm kiếm một phương thức trong helloworldlớp được gọi main(String [] args). phương thức này phải staticđể nó tồn tại mặc dù lớp chưa thực sự được khởi tạo như một đối tượng. Máy ảo Java không tạo một thể hiện của lớp bằng cách tạo một đối tượng từ lớp. Nó chỉ tải lớp và bắt đầu thực hiện tại main()phương thức.

Vì vậy, bạn cần tạo một thể hiện của lớp của bạn dưới dạng một đối tượng và sau đó bạn có thể truy cập các phương thức và biến của lớp chưa được khai báo với công cụ staticsửa đổi. Khi chương trình Java của bạn đã bắt đầu với main()hàm, sau đó bạn có thể sử dụng bất kỳ biến hoặc phương thức nào có công cụ sửa đổi staticvì chúng tồn tại như một phần của lớp được tải.

Tuy nhiên, các biến và phương thức của lớp nằm ngoài main()phương thức không có công cụ staticsửa đổi không thể được sử dụng cho đến khi một thể hiện của lớp được tạo như một đối tượng trong main()phương thức. Sau khi tạo đối tượng, bạn có thể sử dụng các biến và phương thức của đối tượng. Một nỗ lực sử dụng các biến và phương thức của lớp không có bộ staticsửa đổi mà không đi qua một đối tượng của lớp đã bị trình biên dịch Java bắt gặp tại thời điểm biên dịch và bị đánh dấu là lỗi.

import java.io.*;

class HelloWorld {
    int myInt;      // this is a class variable that is unique to each object
    static int myInt2;  // this is a class variable shared by all objects of this class

    static void main (String [] args) {
        // this is the main entry point for this Java application
        System.out.println ("Hello, World\n");
        myInt2 = 14;    // able to access the static int
        HelloWorld myWorld = new HelloWorld();
        myWorld.myInt = 32;   // able to access non-static through an object
    }
}

11

Trước tiên, hãy phân tích chương trình của bạn .. Trong chương trình của bạn, phương thức đầu tiên của bạn là main()và ghi nhớ nó là phương thức tĩnh ... Sau đó, bạn khai báo biến cục bộ cho phương thức đó (so sánh, thấp, cao, v.v.). Phạm vi của biến này chỉ là phương thức khai báo, bất kể nó là phương thức tĩnh hay không tĩnh. Vì vậy, bạn không thể sử dụng các biến đó bên ngoài phương thức đó. Đây là lỗi cơ bản bạn mắc phải.

Sau đó chúng ta đến điểm tiếp theo. Bạn bảo tĩnh là giết bạn. (Nó có thể giết chết bạn nhưng nó chỉ mang lại sự sống cho chương trình của bạn !!) Trước tiên, bạn phải hiểu điều cơ bản. * Phương thức tĩnh chỉ gọi phương thức tĩnh và chỉ sử dụng biến tĩnh. * Biến tĩnh hoặc phương thức tĩnh không phụ thuộc vào bất kỳ trường hợp nào của lớp đó. (tức là nếu bạn thay đổi bất kỳ trạng thái nào của biến tĩnh, nó sẽ phản ánh trong tất cả các đối tượng của lớp) * Vì điều này bạn gọi nó là biến lớp hoặc phương thức lớp. Và còn nhiều hơn nữa về từ khóa "tĩnh". Tôi hy vọng bây giờ bạn có được ý tưởng. Đầu tiên thay đổi phạm vi của biến và khai báo nó dưới dạng tĩnh (để có thể sử dụng nó trong các phương thức tĩnh).

Và lời khuyên cho bạn là: bạn đã hiểu sai ý tưởng về phạm vi của các biến và chức năng tĩnh. Nhận ý tưởng rõ ràng về điều đó.


11

Điều rất cơ bản là các biến tĩnh hoặc các phương thức tĩnh ở cấp độ lớp. Các biến hoặc phương thức mức lớp được tải trước các phương thức hoặc biến mức của thể hiện. Và rõ ràng là thứ không được tải không thể được sử dụng. Vì vậy, trình biên dịch java không để những thứ được xử lý trong thời gian chạy giải quyết tại thời gian biên dịch. Đó là lý do tại sao nó mang lại cho bạn lỗi những thứ không tĩnh không thể được gọi từ ngữ cảnh tĩnh. Bạn chỉ cần đọc về Phạm vi cấp độ lớp, Phạm vi cấp độ sơ thẩm và Phạm vi địa phương.


8

Để có thể truy cập chúng từ các phương thức tĩnh của bạn, chúng cần phải là các biến thành viên tĩnh, như thế này:

public class MyProgram7 {
  static Scanner scan = new Scanner(System.in);
  static int compareCount = 0;
  static int low = 0;
  static int high = 0;
  static int mid = 0;  
  static int key = 0;  
  static Scanner temp;  
  static int[]list;  
  static String menu, outputString;  
  static int option = 1;  
  static boolean found = false;

  public static void main (String[]args) throws IOException {
  ...

7

Bây giờ bạn có thể thêm / sử dụng các thể hiện với trong phương thức

public class Myprogram7 {

  Scanner scan;
  int compareCount = 0;
  int low = 0;
  int high = 0;
  int mid = 0;  
  int key = 0;  
  Scanner temp;  
  int[]list;  
  String menu, outputString;  
  int option = 1;  
  boolean found = false;  

  private void readLine() {

  }

  private void findkey() {

  }

  private void printCount() {

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

    Myprogram7 myprg=new Myprogram7();
    myprg.readLine();
    myprg.findkey();
    myprg.printCount();
  }
}

Ví dụ rất chắc chắn mà tôi đã sử dụng làm mẫu để sửa đổi tệp src phức tạp thành một cấu trúc phù hợp.
Xman

3

Tôi sẽ cố gắng giải thích điều tĩnh cho bạn. Trước hết các biến tĩnh không thuộc về bất kỳ trường hợp cụ thể nào của lớp. Họ được công nhận với tên của lớp. Các phương thức tĩnh một lần nữa không thuộc về bất kỳ trường hợp cụ thể nào. Họ chỉ có thể truy cập các biến tĩnh. Hãy tưởng tượng bạn gọi MyClass.myMethod () và myMethod là một phương thức tĩnh. Nếu bạn sử dụng các biến không tĩnh bên trong phương thức, làm thế quái nào nó biết được biến nào sẽ sử dụng? Đó là lý do tại sao bạn có thể sử dụng từ các phương thức tĩnh chỉ các biến tĩnh. Tôi nhắc lại một lần nữa họ KHÔNG thuộc về trường hợp cụ thể nào.


2
  • Điều đầu tiên là phải biết sự khác biệt giữa một thể hiện của một lớp và chính lớp đó. Một lớp mô hình các thuộc tính nhất định và hành vi của tổng thể trong bối cảnh của các thuộc tính đó. Một thể hiện sẽ xác định các giá trị cụ thể cho các thuộc tính đó.

  • Bất cứ điều gì ràng buộc với từ khóa tĩnh đều có sẵn trong ngữ cảnh của lớp chứ không phải trong ngữ cảnh của một thể hiện của lớp

  • Như một hệ quả tất yếu

    1. các biến trong một phương thức không thể là tĩnh
    2. các trường tĩnh và các phương thức phải được gọi bằng tên lớp, ví dụ MyProgram7.main (...)
  • Tuổi thọ của trường / phương thức tĩnh tương đương với thời gian tồn tại của ứng dụng của bạn

Ví dụ: Say, xe có màu đặc tính và thể hiện hành vi 'chuyển động'. Một ví dụ của chiếc xe sẽ là một chiếc Beetle màu đỏ chuyển động ở tốc độ 25km / h.

Bây giờ một tài sản tĩnh của chiếc xe sẽ là số lượng bánh xe (4) trên đường và điều này sẽ áp dụng cho tất cả các xe.

HTH


1

ClassLoader chịu trách nhiệm tải các tệp lớp. Hãy xem điều gì xảy ra khi chúng ta viết các lớp của chính mình.

Ví dụ 1:

class StaticTest {

      static int a;
      int b;
      int c;
}

Bây giờ chúng ta có thể thấy rằng lớp "StaticTest" có 3 trường. Nhưng thực tế không có sự tồn tại của biến thành viên b, c. Nhưng tại sao ???. OK, hãy xem. Ở đây b, c là biến đối tượng. Biến đối tượng lấy bộ nhớ tại thời điểm tạo đối tượng. Vì vậy, ở đây b, c chưa nhận được bất kỳ bộ nhớ. Đó là lý do tại sao không có sự tồn tại của b, c. Vì vậy, chỉ có sự tồn tại của a. Đối với ClassLoader, nó chỉ có một thông tin về a. ClassLoader chưa nhận ra b, c vì đối tượng chưa được khởi tạo.

Hãy xem một ví dụ khác: Ví dụ 2:

class StaticTest {

      public void display() {
          System.out.println("Static Test");
      }


      public static void main(String []cmd) {

             display();       
      }

}

Bây giờ nếu chúng ta cố gắng biên dịch trình biên dịch mã này sẽ cho lỗi CE. CE: hiển thị phương thức không tĩnh () không thể được tham chiếu từ ngữ cảnh tĩnh.

Bây giờ đối với ClassLoader, nó trông giống như:

class StaticTest {

      public static void main(String []cmd) {

             display();       
      }

}

Trong ví dụ 2 lỗi CE là do chúng ta gọi phương thức không tĩnh từ ngữ cảnh tĩnh. Vì vậy, ClassLoader không thể nhận ra phương thức display () tại thời gian biên dịch. Đã xảy ra lỗi thời gian biên dịch.


Có lẽ đã gửi câu trả lời của bạn một cách tình cờ trước khi bạn quản lý để hoàn thành nó? Vui lòng chỉnh sửa nó và thêm nội dung còn thiếu, cảm ơn!
plamut

1

Trước khi bạn gọi một phương thức cá thể hoặc biến thể hiện. Nó cần một đối tượng (Instance). Khi biến đối tượng được gọi từ trình biên dịch phương thức tĩnh không biết đó là đối tượng mà biến này thuộc về. Bởi vì các phương thức tĩnh không có đối tượng (Chỉ có một bản sao luôn). Khi bạn gọi một biến thisđối tượng hoặc các phương thức cá thể từ phương thức cá thể, nó tham chiếu đến đối tượng. Nó có nghĩa là biến thuộc về bất kỳ đối tượng nào được tạo và mỗi đối tượng có bản sao riêng của các phương thức và biến đối tượng.

Các biến tĩnh được đánh dấu là staticvà các biến thể hiện không có từ khóa cụ thể.


0

Đây là một chút khác biệt để giải thích về từ khóa tĩnh cho tất cả người mới bắt đầu.
Bạn sẽ làm quen với nó một cách rõ ràng khi bạn làm việc nhiều hơn với Classes và Object.

| * | Tĩnh: Các mục tĩnh có thể được gọi bằng Tên lớp
Nếu bạn quan sát theo mã, Một số hàm được gọi trực tiếp với các tên Lớp như

NamCls.NamFnc();

System.out.println();

Điều này là do NamFnc và println sẽ được khai báo bằng từ khóa tĩnh trước chúng.

| * | Không tĩnh: Các mục không tĩnh có thể được gọi với Biến lớp
Nếu nó không tĩnh, bạn cần một biến của lớp,
đặt dấu chấm sau biến lớp và
sau đó gọi hàm.

NamCls NamObjVar = new NamCls();
NamObjVar.NamFnc();


Mã dưới đây giải thích cho bạn gọn gàng

| * | Hàm tĩnh và không tĩnh trong lớp:

public class NamCls
{
    public static void main(String[] args)
    {
        PlsPrnFnc("Tst Txt");

        NamCls NamObjVar = new NamCls();
        NamObjVar.PrnFnc("Tst Txt");
    }

    static void PlsPrnFnc(String SrgPsgVal)
    {
        System.out.println(SrgPsgVal);
    }

    void PrnFnc(String SrgPsgVal)
    {
        System.out.println(SrgPsgVal);
    }
}


| * | Lớp tĩnh và không tĩnh trong một lớp:

public class NamCls
{
    public static void main(String[] args)
    {
        NamTicCls NamTicVaj = new NamTicCls();
        NamTicVaj.PrnFnc("Tst Txt");

        NamCls NamObjVar = new NamCls();
        NamNicCls NamNicVar = NamObjVar.new NamNicCls();
        NamNicVar.PrnFnc("Tst Txt");
    }

    static class NamTicCls
    {
        void PrnFnc(String SrgPsgVal)
        {
            System.out.println(SrgPsgVal);
        }
    }

    class NamNicCls
    {
        void PrnFnc(String SrgPsgVal)
        {
            System.out.println(SrgPsgVal);
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.