Từ khóa static và final trong java

Từ khóa static trong java

Trong Java, từ khóa static được sử dụng để quản lý bộ nhớ tốt hơn và nó có thể được truy cập trực tiếp thông qua lớp mà không cần khởi tạo.

Từ khóa static thuộc về lớp chứ không thuộc về instance ( biểu lộ ) của lớp .Chúng ta hoàn toàn có thể vận dụng từ khóa static với những biến, những phương pháp, những khối, những lớp lồng nhau ( nested class ) .

Các trường hợp sử dụng static:

  1. Biến static (static variables): khi bạn khai báo một biến là static, thì biến đó được gọi là biến tĩnh, hay biến static.
  2. Phương thức static (static methods): khi bạn khai báo một phương thức là static, thì phương thức đó gọi là phương thức static.
  3. Khối static (static blocks): được sử dụng để khởi tạo thành viên dữ liệu static.
  4. Lớp static (static class): một class được có thể được đặt là static chỉ khi nó là một nested class. Một  nested static class có thể được truy cập mà không cần một object của outer class (lớp bên ngoài).
  5. Import static: từ phiên bản Java 5, cho phép import các thành viên tĩnh (static member) của một class hoặc package vào một class khác bằng cách sử dụng từ khóa import và sau đó sử dụng chúng như là thành viên của lớp đó.

Biến static (static variables) trong Java

Trong Java, biến có thể được khai báo cùng với từ khóa static, và lúc đó nó có thể được gọi là class variable.

Việc cấp phép bộ nhớ cho biến static chỉ xảy ra một lần khi class được nạp vào bộ nhớGiá trị mặc định khi khai báo và khởi tạo biến static và non-static là giống nhau, đơn cử :

  • primitive integers (long, int, short, byte): 0
  • primitive floating points (double, float): 0.0
  • boolean: false
  • object references: null

Biến static hoàn toàn có thể được sử dụng làm thuộc tính chung, để dùng chung tài liệu cho toàn bộ objects ( hoặc instances ) của lớp đó và điều đó giúp cho chương trình tiết kiệm chi phí bộ nhớ hơn

Nếu một biến vừa khai báo từ khóa final vừa khai báo từ khóa static thì nó được xem như là một hằng số. Một hằng số nên được viết hoa và nếu có nhiều từ thì phân cách bằng dấu gạch dưới (_)


public static final PI = 3.14;

Trong Interface, mặc định một biến sẽ được khai báo là public static final.

Nếu một biến được khai báo với từ khóa static thì bạn hoàn toàn có thể truy vấn trực tiếp trải qua lớp .Ví dụ : Website gpcoder.com có rất nhiều bài viết, mỗi bài viết cần hiển thị địa chỉ của website dưới mỗi bài viết, địa chỉ này giống nhau và có nhiều lớp cần sử dụng. Để tiết kiệm chi phí bộ nhớ, thuận tiện san sẻ và sử dụng ở những lớp khác. Chúng ta hoàn toàn có thể sử dụng từ khóa static như sau :MyWebsite. java

public class MyWebsite {
	public static String WEBSITE = "gpcoder.com";
}

UsingStaticExample. java

public class UsingStaticExample {
	private String subject;
	
	UsingStaticExample (String subject) {
		this.subject = subject;
	}
	
	public void print() {
		System.out.println("Subject = " + subject);
		System.out.println("Website = " + MyWebsite.WEBSITE);
	}
	
	public static void main(String[] args) {
		UsingStaticExample ex1 = new UsingStaticExample("Core Java");
		ex1.print();
		System.out.println("----");
		UsingStaticExample ex2 = new UsingStaticExample("Object Oriented Programing");
		ex2.print();
	}
}

Kết quả :


Subject = Core Java
Website = gpcoder.com
----
Subject = Object Oriented Programing
Website = gpcoder.com

Một ví dụ khác thường hay được sử dụng để minh họa cho việc sử dụng từ khóa static là bộ đếm Counter. Bạn có một website và bạn cần đếm số lượt truy vấn vào trang. Bạn viết chương trình như sau :

public class Counter {
	int count = 0; 

	public Counter() {
		
	}
	
	public void visit() {
		count++;
		this.print();
	}
	
	public void print() {
		System.out.println("count = " + count);		
	}

	public static void main(String[] args) {
		Counter c1 = new Counter();
		c1.visit();
		Counter c2 = new Counter();
		c2.visit();
		Counter c3 = new Counter();
		c3.visit();
	}
}

Kết quả thực thi chương trình trên

count = 1
count = 1
count = 1

Bạn thắc mắc tại sao kết quả ra kỳ vậy, rõ ràng là tôi đã tăng số lượng truy cập lên rồi mà.
Đó là bởi vì, biến count lấy bộ nhớ tại thời điểm tạo đối tượng, mỗi đối tượng sẽ có bản sao của biến instance, nếu biến count được tăng lên, nó sẽ không ảnh hướng đến các đối tượng khác. Vì thế mỗi đối tượng sẽ có giá trị 1 trong biến count.

Như bạn đã thấy ở trên, biến static sẽ lấy bộ nhớ chỉ một lần, nếu bất kể đối tượng người tiêu dùng nào biến hóa giá trị của biến static, nó sẽ vẫn ghi nhớ giá trị của nó .

public class Counter {
	static int count = 0; 

	public Counter() {
		
	}
	
	public void visit() {
		count++;
		this.print();
	}
	
	public void print() {
		System.out.println("count = " + count);		
	}

	public static void main(String[] args) {
		Counter c1 = new Counter();
		c1.visit();
		Counter c2 = new Counter();
		c2.visit();
		Counter c3 = new Counter();
		c3.visit();
	}
}

Kết quả thực thi chương trình trên

count = 1
count = 2
count = 3

Phương thức static (static methods)

Nếu một phương thức được khai báo với từ khóa static thì phương thức đó được gọi là phương thức static.

Một số đặc thù :

  • Một phương thức static thuộc lớp chứ không phải đối tượng của lớp.
  • Một phương thức static có thể được gọi mà không cần tạo khởi tạo (instance) của một lớp.
  • Phương thức static có thể truy cập biến static và có thể thay đổi giá trị của nó.
  • Một phương thức static chỉ có thể gọi một phương thức static khác, không thể gọi được một phương thức non-static.
  • Một phương thức static không thể được sử dụng từ khóa thissuper.
  • Người dùng không thể override (đè) phương thức static trong Java, bởi vì kỹ thuật đè (overriding) phương thức được dựa trên quá trình gán (binding) động khi khi chương trình đang chạy (runtime) và những phương thức static  được gán tĩnh trong thời gian biên dịch. Phương thức tĩnh không ràng buộc với thực thể của lớp nên phương thức tĩnh sẽ không thể override (đè).

Khi nào sử dụng từ khóa static cho một phương pháp ?

  • Khi phương thức không phụ thuộc vào trạng thái của đối tượng, nghĩa là không cần sử dụng bất kỳ dữ liệu thành viên nào của đối tượng, mọi thứ được truyền như các tham số (parameter).
  • Các phương thức tiện ích là một trường hợp thường được sử dụng nhất trong Java vì chúng có thể được truy cập trực tiếp bằng tên lớp mà không cần tạo bất thể hiện nào. Lớp java.lang.Math là một ví dụ trường hợp sử dụng static method.
  • Sử dụng trong các Design Pattern cần truy cập global như Singleton pattern, Factory pattern, …

Ví dụ :


public class UsingStaticExample {
	private String subject;
	
	UsingStaticExample (String subject) {
		this.subject = subject;
	}
	
	public void print() {
		System.out.println("Subject = " + subject);
		System.out.println("Website = " + MyWebsite.WEBSITE);
	}
	
	public static void changeWebsite(String website) {
		MyWebsite.WEBSITE = website;
	}
	
	public static void main(String[] args) {
		UsingStaticExample ex1 = new UsingStaticExample("Core Java");
		ex1.changeWebsite("abc.com");
		ex1.print();
		System.out.println("----");
		UsingStaticExample.changeWebsite("http://gpcoder.com");
		ex1.print();
	}
}

Kết quả :


Subject = Core Java
Website = abc.com
----
Subject = Core Java
Website = http://gpcoder.com

Khối static (static blocks)

  • Khối static được dùng để khởi tạo hoặc thay đổi giá trị của các biến static.
  • Nó được thực thi trước phương thức main tại thời gian tải lớp.
  • Một class có thể có nhiều static blocks.

Ví dụ :

public class UsingStaticExample {
	
	private static String subject;
	
	static {
        System.out.println("Khối static được gọi");
    }
	
	static {
		subject = "Khối static (static blocks)";
    }
	
	UsingStaticExample () {
		System.out.println("hàm main() được gọi");
		System.out.println("Subject = " + subject);
	}
	
	public static void main(String[] args) {
		UsingStaticExample ex1 = new UsingStaticExample();
	}
}

Kết quả :


Khối static được gọi
hàm main() được gọi
Subject = Khối static (static blocks)

Lớp static ( static class )

Một class được có thể được đặt là static chỉ khi nó là một nested class (tức nằm trong một lớp khác). Một nested static class có thể được truy cập mà không cần một object của outer class (lớp bên ngoài).

Ví dụ :


public class UsingStaticExample {
	private String subject;
	
	UsingStaticExample (String subject) {
		this.subject = subject;
	}
	
	// nested static class
	static class MyWebsite {
		public static String WEBSITE = "gpcoder.com";
    }
	
	public void print() {
		System.out.println("Subject = " + subject);
		System.out.println("Website = " + MyWebsite.WEBSITE);
	}
	
	public static void main(String[] args) {
		UsingStaticExample ex1 = new UsingStaticExample("Core Java");
		ex1.print();
	}
}

Kết quả :

Subject = Core Java
Website = gpcoder.com

Import static trong Java

Java cho phép import các thành viên tĩnh (static member) của một class hoặc package vào một class khác bằng cách sử dụng từ khóa import và sau đó sử dụng chúng như là thành viên của lớp đó.

Ví dụ :SystemConfig. java


package com.gpcoder;

public final class SystemConfig {

	public static final String USER_NAME = "gpcoder";
	public static final String PASSWORD = "123";
	public static final String EMAIL = "gpcodervn@gmail.com";

	private SystemConfig() {
	}
}

StaticImportDemo. java


package com.gpcoder;

import static com.gpcoder.SystemConfig.*;

public class StaticImportDemo {

	public static void main(String[] args) {
		System.out.println("Username: " + USER_NAME);
		System.out.println("Password: " + PASSWORD);
		System.out.println("Email: " + EMAIL);
	}
}

Như bạn thấy, khi sử dụng import static tất cả chúng ta hoàn toàn có thể gọi trực tiếp những thành viên mà không cần phải trải qua tên class, ví dụ điển hình SystemConfig. USER_NAME

Một số câu hỏi thường gặp khi đi phỏng vấn tương quan đến từ khóa static

Ý nghĩa của từ khoá static trong Java là gì? Chúng ta có thể override (đè) một hàm private hoặc static trong Java không?

Từ khoá static biểu lộ cho biến hoặc phương pháp hoàn toàn có thể được truy vấn ( sử dụng ) mà không cần tạo ra thực thể của lớp chứa nó. Người dùng không hề override phương pháp static trong Java, chính bới kỹ thuật đè ( overriding ) phương pháp được dựa trên quy trình gán ( binding ) động khi runtime ( khi chương trình đang chạy ) và những phương pháp static được gán tĩnh trong thời hạn biên dịch. Phương thức tĩnh không ràng buộc với thực thể của lớp nên phương pháp tĩnh sẽ không hề override .

Chúng ta có thể truy cập một biến không tĩnh(non-static) trong một ngữ cảnh static được không?

Một biến static phụ thuộc vào vào lớp của nó và giá trị của nó sẽ sống sót ( giữ ) cho toàn bộ những thực thể của lớp đó. Biến static được tạo ra khi lớp chứa đó được tải ( load ) bởi JVM. Nếu nỗ lực truy vấn vào một biến non-static ( trong hàm static ) mà không có trong thực thể ( instance ) nào thì trình biên dịch sẽ báo lỗi, do tại những biến đó ( non-static ) chưa được khởi tạo và chúng không có ràng buộc với bất kỳ thực thể nào .

Tại sao phương thức main trong Java là static?

Trả lời : Bởi vì không thiết yếu phải tạo đối tượng người tiêu dùng để gọi phương pháp static. Nếu nó là phương pháp non-static, JVM tiên phong tạo đối tượng người dùng và sau đó gọi phương pháp main ( ) mà hoàn toàn có thể gây ra yếu tố về cấp phép bộ nhớ bộ nhớ phụ .

Chúng ta có thể thực thi một chương trình mà không có phương thức main()?

Trả lời: Có thể, một trong các cách đó là khối static trong phiên bản trước của JDK 1.7.

Ví dụ :


public class ProgramWithoutMain {
	static {
		System.out.println("static block is invoked");
		System.exit(0);
	}
}

Kết quả :Trường hợp chạy ở JDK < 1.7

static block is invoked

Trường hợp chạy ở JDK > = 1.7

Error: Main method not found in class com.gpcoder.ProgramWithoutMain, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

Từ khóa final trong java

Từ khóa final trong Java được sử dụng để hạn chế thao tác của người dùng.

Các trường hợp sử dụng :

  • Biến final: khi một biến được khai báo với từ khoá final, nó chỉ chứa một giá trị duy nhất trong toàn bộ chương trình (hay dễ hiểu hơn gọi là biến hằng).
  • Phương thức final: khi một phương thức được khai báo với từ khoá final, các class con kế thừa sẽ không thể ghi đè (override) phương thức này.
  • Lớp final: khi từ khoá final sử dụng cho một lớp, lớp này sẽ không thể được kế thừa.
  • Biến static final trống: Một biến final mà không được khởi tạo tại thời điểm khai báo được gọi là biến final trống.

Từ khóa final hoàn toàn có thể được vận dụng với những biến, một biến final mà không có giá trị nào được gọi là biến final trống hoặc biến final không được khởi tạo. Nó chỉ hoàn toàn có thể được khởi tạo trong constructor. Biến final trống cũng hoàn toàn có thể là static mà sẽ chỉ được khởi tạo trong khối static. Chúng ta sẽ khám phá cụ thể về những điều này .

Biến final trong Java

Trong Java, biến có thể được khai báo cùng với từ khóa static, và lúc đó bạn sẽ không thể thay đổi giá trị của biến final (nó được gọi là hằng số).

Ví dụ : Trình biên dịch sẽ thông tin lỗi khi bạn cố ý đổi khác giá trị của biến này, chính do biến final một khi được gán giá trị thì không khi nào biến hóa được .

Bạn sẽ nhận được thông tin lỗi khi cố ý đổi khác giá trị của biến final : The final field UsingFinalExample. WEBSITE cannot be assigned .Ví dụ : Có thể đổi khác giá trị của thuộc tính của một object là final, nhưng bạn không hề khởi tạo lại object đó một lần nữa .

Phương thức final trong Java

Ví dụ về không hề ghi đè phương pháp final .

Bạn sẽ nhận được thông tin lỗi khi cố ý ghi đè phương pháp final : Cannot override the final method from Parent .

Lớp final trong Java

Ví dụ về không hề thừa kế lớp final .

Bạn sẽ nhận được thông tin lỗi khi cố ý kế thừa từ lớp final : The type Child cannot subclass the final class Parent .

Biến static final trống trong Java

Một biến static final mà không được khởi tạo tại thời gian khai báo thì đó là biến static final trống. Nó chỉ hoàn toàn có thể được khởi tạo trong khối static và một khi nó đã được khởi tạo thì không hề bị biến hóa .Ví dụ :

Một số câu hỏi thường gặp khi đi phỏng vấn tương quan đến từ khóa final

  • Phương thức final có được kế thừa không?

Trả lời: , phương thức final được kế thừa nhưng bạn không thể ghi đè nó.

  • Biến final trống hoặc không được khởi tạo là gì?

Trả lời : Một biến final mà không được khởi tạo tại thời gian khai báo được gọi là biến final trống. Biến được khởi tạo tại thời gian tạo đối tượng người tiêu dùng và một khi nó đã được khởi tạo thì không hề bị đổi khác .Ví dụ :

Bạn sẽ nhận được thông tin lỗi khi cố ý đổi khác giá trị của biến final : The final field WEBSITE may already have been assigned .

  • Tham số final là gì?

Nếu bạn khai báo bất kể tham số nào là final, thì bạn không hề đổi khác giá trị của nó .

Bạn sẽ nhận được thông tin lỗi khi cố ý biến hóa giá trị của tham số final : The final local variable website cannot be assigned. It must be blank and not using a compound assignment .

Tài liệu tham khảo:

Trên đây là những lý thuyết cơ bản về từ khóa static, final. Khi tham gia vào các dự án thực tế sẽ có nhiều trường hợp áp dụng khác nhau. Nếu có bất kỳ thắc mắc hay góp ý, bạn có thể để lại bình luận bên dưới. Tôi sẽ cố gắng giải đáp cho các bạn.

Cám ơn những bạn đã theo dõi bài viết. Hẹn gặp lại ở bài viết tiếp theo .5.0

Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé!

Shares

Bình luận

phản hồi

5/5 - (1 vote)

Bài viết liên quan

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments