Different between using Generics in Array and Collections


bài hôm nay chúng ta thể hiện với các đội tượng trở nên phức tạp hơn trong các bài trước

chúng ta có 1 interface animal và 2 concrete class Cat vs Class Dog extends ( có thể là implement or extend ) đến interface animal.

d1

Interface animal.java có method là eat() and sleep()

package thaihoanghai.generic;

public interface Animal {
	public void eat();
	public void sleep();
}

Chúng ta hiện thự 2 class Dog và Cat implement animal và @overide 2 method eat and sleep
Class Dog.java

package thaihoanghai.generic;

public class Dog implements Animal{

	@Override
	public void eat() {
		System.out.println("Dog eat bone");

	}

	@Override
	public void sleep() {
		System.out.println("Dog eat in garden");

	}

}

Class Cat.java

package thaihoanghai.generic;

public class Cat implements Animal{

	@Override
	public void eat() {
		System.out.println("Cat eat mouse");

	}

	@Override
	public void sleep() {
		System.out.println("Cat sleep on Sofa");

	}

}

Xong giờ chúng ta sẻ hiện thực 1 demo cho việc test trên Array
chúng ta tạo ra 1 class TestMain_1.java

package thaihoanghai.generic;

public class TestMain_1 {
	public static void main(String[] args) {
		// we create array Animal with 2 cat and 1 dog
		Animal[] animals = {new Cat(),new Dog(), new Cat()};
		Dog[] dog = {new Dog(), new Dog(), new Dog()};
		// we call takAnimals() using both array type as arguments
		takeAnimals(animals);
		takeAnimals(dog);			
	}

	private static void takeAnimals(Animal[] animals){
		for(Animal a : animals){
			a.eat();
		}
	}
}

Kết quả sau khi run đoạn chương trình trên .

d1

ok mọi chuyện dường như rất tốt. Chúng ta thể hiện thừa kề qua việc sử dụng đa hình trên interface animal. Chúng ta có ai đặt ra câu hỏi rằng tại sao method

private static void takeAnimals(Animal[] animals)

Điểm quan trọng chúng ta cần để ý ở đây là method của chúng ta có thể nhận Animal[] hay Dog[]. vì dự trên tính chất đa hình chúng ta có thể nói rằng Dog IS-A Animal.

for(Animal a : animals){
	a.eat();
}

Nhớ 1 điều ở đây chúng ta chỉ gọi method được khai báo trong interface animals chứ không gọi của class Cat hay Dog. vì khi chúng ta duyệt qua all đều là animal chúng ta không check varible a của ta là Dog hayCat. cac bạn có thể dùng instanceOf để check thể hiện của chúng. và Cast về loại cần.

OK tới đây chúng ta mọi chuyện vẫn tốt.

(*) Điều gì sẽ xãy ra khi chúng ta chuyển từ một Array to ArrayList ???? mới thoạt nghe chúng ta có thể trả lời nhanh mọi thứ sẻ vẫn ổn thôi. 

Đâu tiên chúng ta thử với một ArrayList<Animal> để xem có sự thay đổi gì không ?
Chúng ta tạo 1 class TestMain_2.java như sau:

</b>package thaihoanghai.generic;

import java.util.ArrayList;

public class TestMain_2 {
	public static void main(String[] args) {
		// we create array Animal with 2 cat and 1 dog
		ArrayList<Animal> animals = new ArrayList<Animal>();
		animals.add(new Dog());
		animals.add(new Cat());
		animals.add(new Dog());

		takeAnimals(animals);
	}

	private static void takeAnimals(ArrayList<Animal> animals){
		for(Animal a : animals){
			a.eat();
		}
	}
}
<b>


Code sau khi chạy

d1

Tới lúc này chúng ta vẫn đồng ý mọi chuyện vẫn tốt . giờ chúng ta thêm 1 đoạn code vào code phía trên như sau:

</b>ArrayList<Dog> dogs = new ArrayList<Dog>();
		dogs.add(new Dog());
		dogs.add(new Dog());
		dogs.add(new Dog());

		takeAnimals(dogs);<b>



Có 1 vấn đề xãy ra chúng ta sẻ thấy như hình.

d1

Vậy điều gì đả xảy ra ??? mehthod: private static void takeAnimals(ArrayList<Animal> animals)
lại không hiểu tham số là ArrayList<Dog> ???. Rỏ ràng chúng ta củng làm điều này tương tự với Array Dog[] .

Khi chúng ta sử dụng 1 ArrayList<Animal> việc chúng ta add Cat hay add Dog vào thì Animal vẫn là loại Supertype. Vì vậy bạn có thể đặt bất kì loại nào của animal.
Nhưng nếu bạn tạo ra 1 ArrayList<Dog> -> điều này có nghĩa bạn chỉ có thể add ONLY DOG vào trong nó. Điều này xãy ra khi bạn add tham số này vào trong takeAnimals<Animal> . Lúc đó trình biên dịch biết rằng để bạn truyền vào ArrayList<Dog> vào trong methoid này. Vào lúc runtime nếu bạn add một Cat vào trong nó. thì sẻ ra một exception.

(*) Note : Nếu bạn khai báo một method có tham số là ArrayList<Animal> . Thì nó chỉ nhận ONLY ArrayList<Animal> . Không được phép ArrayList<Dog> or ArrayList<Cat>.

Vậy tại sao Array Dog có thể truyền vào trong Array Animal. ???
(*) Array : Được check vào thời điểm Runtime
(*) Collection : được check vào thời điểm compile

Vậy làm sao để cho loại generic cho cac collection check khi runtime:

Giải pháp : sử dụng wildcard.
Khi bạn sử dụng wildcard trong tham số của method của bạn. Thì compiler sẻ STOP .
Ví dụ : public <T extends Animal> void takeAmimals(ArrayList<T> list)
or : public void takAnimals(ArrayList<? extends Animal> list)

Class TestMain_2.java sao khi fix

</b>package thaihoanghai.generic;

import java.util.ArrayList;

public class TestMain_2 {
	public static void main(String[] args) {
		// we create array Animal with 2 cat and 1 dog
		ArrayList<Animal> animals = new ArrayList<Animal>();
		animals.add(new Dog());
		animals.add(new Cat());
		animals.add(new Dog());

		takeAnimals(animals);

		ArrayList<Dog> dogs = new ArrayList<Dog>();
		dogs.add(new Dog());
		dogs.add(new Dog());
		dogs.add(new Dog());

		takeAnimals(dogs);

	}

	private static void takeAnimals(ArrayList<? extends Animal> animals){
		for(Animal a : animals){
			a.eat();
		}
	}

}
<b>


Code sau khi chạy :
d1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: