Java Bài 25: Khả Năng Truy Cập (Access Modifier)

Posted by

Chào mừng các bạn đã đến với bài học Java thứ 25, bài học về Khả năng truy cập (Access Modifier). Đây là bài viết trong chuỗi bài về lập trình ứng dụng Java của Yellow Code Books.

Bài hôm nay chúng ta sẽ nói đến một vấn đề đã được hứa khá lâu, từ khi các bạn mới vừa làm quen với các thuộc tínhphương thức của lớp, đó là kiến thức về Khả năng truy cập vào các giá trị lớp. Vậy thì cái Khả năng truy cập này là gì và chúng quan trọng như thế nào, mời các bạn cùng theo dõi bài học nhé.

Khả Năng Truy Cập (Access Modifier) Là Gì?

Khả năng truy cập, hay còn gọi là Access Modifier, là các Định nghĩa được Java cung cấp sẵn. Và bạn, hay các lập trình viên khác sẽ sử dụng các Định nghĩa này, để thể hiện các quyền được truy cập vào các giá trị của lớp. Các giá trị của lớp ở đây mình muốn nhắc đến bao hồm các thuộc tính, các phương thức, và cả các constructor của một lớp.

Các Access Modifier trong Java chính là các từ khóa: private, protected, publicdefault (hay hiểu là chẳng có định nghĩa gì).

Định Nghĩa Khả Năng Truy Cập Như Thế Nào?

Chúng ta khoan hãy nói đến từng Khả năng truy cập đã nêu trên, mà hãy điểm lại xem làm cách nào để khai báo một khả năng truy cập nhé.

Bạn hãy nhớ lại đi, trong các cú pháp liên quan đến việc khai báo các giá trị của lớp, mình đều có nêu cách khai báo Khả năng truy cập này rồi đấy.

Chẳng hạn như khi khai báo thuộc tính của lớp này.

[khả_năng_truy_cập]  kiểu_thuộc_tính  tên_thuộc_tính  [= giá_trị_ban_đầu];

Hay khi khai báo phương thức của lớp này.

[kả_năng_truy_cập]  kiểu_trả_về  tên_phương_thức  () {
     // Các dòng code
}

Hay khi khai báo một constructor này.

[khả_năng_truy_cập]  tên_phương_thức  () {
     // Các dòng code
}

Vậy bạn có thể hiểu cách để định nghĩa một Khả năng truy cập vào các giá trị lớp rồi đúng không nào. Dưới đây là một ví dụ đầy đủ cho việc khai báo các Khả năng truy cập này ở lớp HinhTron.

public class HinhTron {
	
	protected final float PI = 3.14f;
	private float banKinh;
	
	// Constructor
    public HinhTron(float banKinh) {
        this.banKinh = banKinh;
    }
 
    protected float tinhChuVi() {
        return 2 * PI * banKinh;
    }
 
    protected float tinhDienTich() {
        return PI * banKinh * banKinh;
    }
	
	public void xuatThongTin() {
		System.out.println("Đây là Hình tròn");
	}

}

Ý Nghĩa Của Các Khả Năng Truy Cập

Nào, giờ chúng ta sẽ đi qua từng Khả năng truy cập xem chúng có ý nghĩa và lợi ích gì nhé.

Trước hết, mình xin tổng hợp các Khả năng truy cập dựa trên một bảng dưới đây, để cho các bạn dễ nhớ. Bảng này chỉ đơn giản mang các giá trị “Có” nếu như định nghĩa này cho phép truy cập ở một phạm vi nào đó, và mang giá trị “Không” cho ý nghĩa ngược lại.

Phạm vi truy cập private default protected public
Bên trong lớp
Ở lớp khác, nhưng trong cùng package Không
Ở lớp con, trong cùng package Không
Ở lớp con, khác package Không Không
Ở bất cứ lớp nào khác (không phải lớp con), khác package Không Không Không

Giờ mình sẽ nói rõ hơn từng Khả năng truy cập.

Khả Năng Truy Cập private

Nếu bạn chỉ định một giá trị nào đó (thuộc tính, phương thức hay constructor) của lớp là private, thì như bảng trên, bạn chỉ có thể truy xuất đến giá trị này bên trong lớp đó mà thôi.

Khả năng private này mang ý nghĩa bảo vệ các giá trị bên trong lớp, không cho các lớp bên ngoài có thể “nhìn thấy” (đọc và chỉnh sửa) được.

Nếu private được chỉ định cho một thuộc tính, thuộc tính đó sẽ không được phép truy cập, hay chỉnh sửa từ các lớp khác, trừ khi bạn xây dựng các phương thức gettersetter cho thuộc tính đó mà mình sẽ nói sau.
– Còn nếu private được chỉ định cho một phương thức, phương thức đó sẽ không được truy cập hay kế thừa từ lớp khác.
– Và nếu private được chỉ định cho constructor, constructor này sẽ không dùng được để khởi tạo đối tượng cho lớp đó.

Theo mình biết thì khả năng private này được dùng rất nhiều, nếu bạn không chắc một giá trị có nên được gọi đến hay dùng lại hay không, thì cứ chỉ định private cho nó cho chắc cú.

Bài Thực Hành Số 1

Bài thực hành này mình tạo lớp HinhTron có khai báo các giá trị là private. Bạn có thể thấy các giá trị này khi dùng bên trong lớp HinhTron thì rất tốt, không bị báo lỗi từ hệ thống.

public class HinhTron {
	
	private final float PI = 3.14f;
	private float banKinh;
	
	// Constructor
	private HinhTron() {	
	}
 
    private float tinhChuVi() {
        return 2 * PI * banKinh;
    }
 
    private float tinhDienTich() {
        return PI * banKinh * banKinh;
    }
}

Vậy bạn có thể tự trắc nghiệm xem, với việc gọi đến các giá trị này của HinhTron từ hàm main(), thì dòng code nào sau đây sẽ bị hệ thống báo lỗi nhé.

public class MainClass {

	public static void main(String[] args) {
		HinhTron hinhTron = new HinhTron();
		hinhTron.banKinh = 20;
		hinhTron.tinhDienTich();
	}
}

Kết quả dòng bị báo lỗi ở dưới đây.

Dòng 4 báo lỗi
Dòng 5 báo lỗi
Dòng 6 báo lỗi

Khả Năng Truy Cập default

Như mình có nói, default ở đây có nghĩa là không định nghĩa khả năng truy cập gì hết, nó giống như các bài học mở đầu mà chúng ta đã làm quen, khi đó chúng ta tạm thời để trống các khai báo Khả năng truy cập này.

Và với việc để trống Khả năng truy cập cho các giá trị của lớp, thì bạn có thể thấy rằng, nếu bên trong lớp đó hoặc các lớp khác trong cùng package, sẽ có thể nhìn thấy và truy xuất đến các giá trị đó. Khả năng nhìn thấy và truy xuất chỉ bị chặn khi bạn gọi đến các giá trị này từ một lớp nằm ngoài package mà thôi.

Khả năng này ít được dùng hơn, vì ai cũng muốn sự tường minh trong code cả.

Bài Thực Hành Số 2

Ở đây mình bỏ hết các khai báo Khả năng truy cập cho các giá trị của lớp HinhTron.

package shapes;

public class HinhTron {
	
	final float PI = 3.14f;
	float banKinh;
	
	// Constructor
	HinhTron() {	
	}
 
    float tinhChuVi() {
        return 2 * PI * banKinh;
    }
 
    float tinhDienTich() {
        return PI * banKinh * banKinh;
    }
}

Và tương tự, với các dòng code khai báo ở hàm main() như sau, bạn đoán xem dòng nào sẽ bị lỗi nhé.

package main;

import shapes.HinhTron;

public class MainClass {

	public static void main(String[] args) {
		HinhTron hinhTron = new HinhTron();
		hinhTron.banKinh = 20;
		hinhTron.tinhDienTich();
	}
}

Kết quả dòng bị lỗi như sau.

Dòng 8 báo lỗi
Dòng 9 báo lỗi
Dòng 10 báo lỗi

Sở dĩ các dòng này báo lỗi, là vì chúng ở package "main" khác với package "shapes" của HinhTron. Bạn thử đưa chúng về cùng một package rồi kiểm chứng lại nhé.

Khả Năng Truy Cập protected

Khả năng này mang ý nghĩa bảo vệ các giá trị của lớp cho các lớp con của nó dùng lại hoặc ghi đè. Do đó có thể hiểu, khả năng protected sẽ trao quyền sử dụng hoàn toàn tự do cho các lớp con, dù có ở cùng hay khác package. Khả năng này chỉ giới hạn với các lớp không phải lớp con của nó và nằm ngoài package mà thôi.

Bài Thực Hành Số 3

Lần này bạn hãy xem các khai báo protected cho các giá trị bên trong HinhTron như sau.

package shapes;

public class HinhTron {
	
	protected final float PI = 3.14f;
	protected float banKinh;
	
	// Constructor
	public HinhTron(float banKinh) {
		this.banKinh = banKinh;
	}
 
    protected float tinhChuVi() {
        return 2 * PI * banKinh;
    }
 
    protected float tinhDienTich() {
        return PI * banKinh * banKinh;
    }
}

Và với code ở hàm main(), bạn lại thử đoán xem dòng code nào bị báo lỗi.

package main;

import shapes.HinhTron;

public class MainClass {

	public static void main(String[] args) {
		HinhTron hinhTron = new HinhTron(10);
		hinhTron.tinhDienTich();
	}
}

Kết quả dòng bị lỗi như sau.

Dòng 9 báo lỗi

Phương thức tinhDienTich() rơi vào trường hợp "Không" duy nhất của protected. Bởi nó vừa gọi từ một lớp không có quan hệ kế thừa với HinhTron, và cũng nằm ngoài package so với HinhTron nữa.

Bài Thực Hành Số 4

Vẫn với code của Bài thực hành số 3, lần này mình khai báo thêm HinhTru kế thừa từ HinhTron, và hàm main() như sau. Bạn xem có dòng nào báo lỗi không nhé.

package shapes;

public class HinhTru extends HinhTron {

	public float chieuCao;
	
	// Constructor
	public HinhTru(float banKinh, float chieuCao) {
		super(banKinh);
		this.chieuCao = chieuCao;
	}
	
	public float tinhTheTich() {
		return tinhDienTich() * chieuCao;
    }
}
package main;

import shapes.HinhTru;

public class MainClass {

	public static void main(String[] args) {
		HinhTru hinhTru = new HinhTru(10, 20);
		hinhTru.tinhTheTich();
	}
}

Đây là kết quả các dòng báo lỗi.

Không dòng nào báo lỗi hết.

Vì HinhTru kế thừa các phương thức từ cha và set lại khả năng truy cập là public.

Khả Năng Truy Cập public

Có lẽ không cần tốn nhiều giấy mực để nói về khả năng này. Nếu bạn chỉ định một giá trị trong lớp là public, thì coi như tất cả các lớp nào khác đều có thể truy xuất đến các giá trị này.

Vậy là mình vừa “trả” xong món nợ về kiến thức Khả năng truy cập, hay còn gọi là Access ModifierTừ bài học sau chúng ta sẽ dùng nhiều các khai báo khả năng của ngày hôm nay.

Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy đánh giá 5 sao nếu thấy thích bài viết, hãy comment bên dưới nếu có thắc mắc, hãy để lại địa chỉ email của bạn để nhận được thông báo mới nhất khi có bài viết mới, và nhớ chia sẻ các bài viết của Yellow Code Books đến nhiều người khác nữa nhé.

Bài Kế Tiếp

Bạn đã biết đến việc sử dụng từ khóa final trong khai báo biến và thuộc tính? Vậy thì bài sau chúng ta cùng xem từ khóa này được dùng trong phương thức và ngay cả khi khai báo một lớp, sẽ như thế nào nhé.

 

Advertisements
Rating: 5.0/5. From 9 votes.
Please wait...

8 comments

    1. Bạn phải đảm bảo lớp HinhTron và lớp MainClass nằm ở 2 package khác nhau thì mới bào lỗi nhé

Gửi phản hồi