Chương trình hiển thị các phần tử của mảng bị sai kết quả

package test.java;

public class ClassA {

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

	 void start() {
		// TODO Auto-generated method stub
		long []a1 = {3,4,5};
		System.out.print(a1[0]+a1[1]+a1[2]+" ");
		long []a2 = fix(a1);
		System.out.print(a1[0]+a1[1]+a1[2]+" ");
		System.out.println(a2[0]+a2[1]+a2[2]);
	}

	 long[] fix(long[] a3) {
		// TODO Auto-generated method stub
		a3[1] = 7;
		return a3;
	}
}

Sau khi thực thi chương trình thì kết quả hiển thị ra console:
15 15? sao không phải là 12 15?

Mảng truyền tham chiếu nên khi bạn thay đổi giá trị tham số thì giá trị gốc thay đổi theo.

3 Likes

bạn có thể giải thích kỹ hơn cho mình hiểu được không?

  1. Khi bạn gọi fix(a1) thì a1 bị thay đổi.
  2. Khi bạn return chính a1 trong hàm thì kết quả trả về không phải bản sao mà là chính nó
  3. Khi bạn gọi long[] a2 = fix(a1), mà fix(a1) lại chính là a1 thì a2 == a1, hai mảng thực ra là 2 tham chiếu cùng trỏ đến duy nhất 1 đối tượng, nên thay đổi a1 cũng thay đổi a2

Hàm start của bạn bản chất nó như thế này:

long[] a1 = {3 ,4 ,5};
System.out.print(a1[0]+a1[1]+a1[2]+" ");
a1[1] = 7;
long[] a2 = a1;//"a2" chỉ là 1 cái tên khác của đối tượng mà cái tên "a1" đang trỏ vào
System.out.print(a1[0]+a1[1]+a1[2]+" ");
System.out.println(a1[0]+a1[1]+a1[2]); //a1 hay a2 cũng thế, vì 2 thằng đó là 1

Trong khi cái bạn muốn nó là thế này:

long[] a1 = {3 ,4 ,5};
System.out.print(a1[0]+a1[1]+a1[2]+" ");
long[] a2 = new long[a1.length];
for (int i = 0; i < a1.length; i += 1)
	a2[i] = a1[i];
a2[1] = 7;
System.out.print(a1[0]+a1[1]+a1[2]+" ");
System.out.println(a2[0]+a2[1]+a2[2]);

Như vậy, hàm fix cần viết như sau:

long[] fix(long[] a3)
{
	long[] output = new long[a3.length];
	for (int i = 0; i < a3.length; i += 1)
		output[i] = a3[i];
	output[1] = 7;
	return output;
}

Chú ý, chỉ có các kiểu dữ liệu primitive - “nguyên thuỷ” (boolean, byte, short, int, long, float, double, char) là truyền bản sao vào hàm, các kiểu dữ liệu khác truyền chính nó (cho nên hàm fix(a1) sẽ làm thay đổi a1). Phép gán “=” đối với các kiểu dữ liệu object - “đối tượng” (tức là không phải primitive) là phép “trỏ tham chiếu đến” chứ không phải phép “sao chép” như các kiểu primitive. Ví dụ: kiểu long[] là kiểu object, khác với long là primitive.

4 Likes

Thanks bạn, lúc đầu mình nghĩ long chỉ là 1 kiểu primitive nên chỉ truyền được giá trị, không phải là kiểu đối tượng. Nhưng mình code lại như này :

package test.java;

public class ClassB {
	public static void main(String[] args) {
		start();

	}

	public static void start() {
		// TODO Auto-generated method stub
		long[] a1 = { 3, 4, 5 };
		long[] a2 = a1;
		System.out.print(a1[0] + a1[1] + a1[2] + " ");
		System.out.println(a2[0] + a2[1] + a2[2]);
		a2[0] = 0;
		System.out.println(a1[0]);
	}

	}

kết quả hiển thị ra a1[0] bằng 0. có vẻ như long[] không phải là kiểu primitive, mà là 1 đối tượng. a1 a2 là 2 biến đối tượng tham chiếu tới cùng 1 giá trị và đều có quyền can thiệp vào chúng. Thanks bạn
Mình cũng vừa mới tham khảo được ở đây:

long và long[] là 2 thằng hoàn toàn khác nhau nhé. long là kiểu số nguyên 64bit còn long[] là mảng. Kiểu dữ liệu tham chiếu không chỉ có đối tượng mà còn các kiểu dữ liệu khác trừ primitive. Bạn xem lại 1 chút về kiến thức java cơ bản để nắm chắc hơn, đừng code lung tung rồi đoán già đoán non dễ dẫn đến kiến thức sai rất nguy hiểm

1 Like

Hi Quân, mình đã suy nghĩ về vấn đề này. Như bạn nói thì long[] chỉ là 1 mảng mà các phần tử của nó có kiểu primitive long. Vậy làm thế nào mà nó trở thành kiểu tham chiếu được??

Thanks mọi người. Kiểu tham chiếu gồm kiểu mảng, kiểu đối tượng class và kiểu interfacec :smiley: :smiley: :smiley: close topic ạ

Interface ko phải kiểu dữ liệu mà chỉ là “tập hợp các thuộc tính”, mỗi đối tượng đều phải thuộc một class nào đó và class có thể có thêm interface.
Kiểu mảng là một class, một mảng là một đối tượng.

Thế nên một tham chiếu chỉ tham chiếu đến một đối tượng, có thể tham chiếu thông qua class hoặc interface, kiểu tham chiếu chỉ có các class.


Bài viết này có nói kiểu tham chiếu bao gồm cả một mảng. Mình thấy đúng vì như thế mới giải thích được code của mình rằng a2 = fix(a1); a1 là 1 mảng, khi thực hiện xong thì a1 đã bị thay đổi giá trị của phần tử a1[1].

Bài viết đó nói đúng nhưng không chính xác. Mảng cũng là lớp đối tượng Class. Còn Interface không đứng riêng lẻ, thế nên nếu một đối tượng có thể được tham chiếu qua được Interface thì sẽ tham chiếu được qua Class.

Chung quy lại, dữ liệu chỉ có 2 dạng: đối tượng và nguyên thuỷ, và để tham chiếu đến đối tượng thì qua kiểu dữ liệu (là Class trực tiếp của đối tượng) hoặc qua định danh (là Class hoặc Interface hoặc super Class của đối tượng)

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?