01/10/2018, 17:18

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?

Trương Tấn Phát viết 19:28 ngày 01/10/2018

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.

Nguyễn Văn Thịnh viết 19:24 ngày 01/10/2018

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

Trần Hoàn viết 19:21 ngày 01/10/2018
  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.

Nguyễn Văn Thịnh viết 19:28 ngày 01/10/2018

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:

Tôi thắc mắc – 18 Apr 15

Bài 3. Sự khác nhau giữa kiểu dữ liệu cơ sở và kiểu dữ liệu tham chiếu trong...

Xin chào tất cả các bạn! Biến (variable) là một khái niệm cực kỳ quen thuộc với một developer, và đi kèm với nó chính là các kiểu dữ liệu. Ở bài trước, tớ đã cho các bạn thấy cách phân loại các kiể…

Quân viết 19:20 ngày 01/10/2018

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

Nguyễn Văn Thịnh viết 19:18 ngày 01/10/2018

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??

Nguyễn Văn Thịnh viết 19:32 ngày 01/10/2018

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 close topic ạ

Trần Hoàn viết 19:28 ngày 01/10/2018

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.

Nguyễn Văn Thịnh viết 19:32 ngày 01/10/2018

IT Phú Trần - Chia sẻ kiến thức lập trình | Việt Nam tươi đẹp – 16 Mar 17

Phân biệt tham chiếu và tham trị trong java - IT Phú Trần - Chia sẻ kiến thức...

Tham chiếu và tham trị trong java rất dễ gây nhầm lẫn cho các bạn mới học,kể cả các lập trình viên code lâu năm cũng đôi lúc có sự nhầm lẫn về sự phân biệt  khái niệm tham chiếu và tham trị trong java.Trong bài này,tôi sẽ chia sẻ theo kinh nghiệm...


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].

Trần Hoàn viết 19:22 ngày 01/10/2018

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)

Bài liên quan
0