11 thg 4, 2010

Exception trong java - Ngoại lệ trong java

1.1 Khái niệm và mục đích sử dụng
Exception là một đối tượng được tạo ra khi chương trình gặp lỗi được java trả về nhằm mục đích dò tìm và sửa lỗi chương trình
1.2 Các kiểu exception
Có ba kiểu exception trong java là checked exception, error và unchecked exception (runtime exception)
Checked exception là loại ngoại lệ phổ biến sử dụng để kiểm tra những lỗi phổ biến trong lúc biên dịch ví dụ bạn truy xuất một tập tin không tồn tại trên ổ đĩa thì bạn sẽ nhận được một java.io.FileNotFoundException. Checked exception kế thừa từ java.lang.Exception và chúng được dùng trong try-catch-finally.
Error là một loại lỗi nằm ngoài phạm vi ứng dụng, được java trả về trong đối tượng java.io.IOError. Ví dụ ứng dụng mở một tập tin thành công nhưng khi đọc dữ liệu lại không đọc được do ổ cứng bị hỏng một vài sector vật lý, …
Unchecked exception thường được hiểu là những exception được sinh ra do lỗi logic khi lập trình và được trả về lúc runtime. Unchecked exception kế thừa từ java.lang.RuntimeException
1.3 Bắt giữ và xử lý các exception
Để xử lý một exception ta dùng lệnh try-catch-finally, throw hoặc throws
Try chứa các dòng lệnh thực hiện một chức năng nào đó mà có thể gây ra exception
Catch chứa các dòng lệnh để xử lý kết quả khi nhận được một exception từ java sau khi khối try tạo ra exception.
Finally các dòng lệnh trong khối này luôn luôn được thưc thi khi thoát khối try
Ví dụ:
int a = 0;
int b = 1;
int c;

try {
c = b/a;
}
catch (ArithmeticException e)
{
System.out.println("Arithmetic Exception");
}
finally {
System.out.println("Finally");
}
Với đoạn code trên ta sẽ có kết quả in ra màn hình là:
Arithmetic Exception
Finally
throws
Ví dụ:
public static int getEndMember(int[] a) throws ArrayIndexOutOfBoundsException {
return a[a.length];
}
public static void main(String[] args) {
int[] a = {1, 2, 3};
try {
getEndMember(a);
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndexOutOfBoundsException");
}
}
Đoạn code trên sẽ in ra ArrayIndexOutOfBoundsException bởi vì hàm getEndMember đã truy xuất phần tử a[3] không có trong mảng.
throw
Chúng ta cũng có thể dùng throw để quăng ra một exception Object
Ví dụ:
public static int getEndMember(int[] a) throws ArrayIndexOutOfBoundsException {
return a[a.length-1];
}
public static void main(String[] args) {
int[] a = {1, 2, 0};
int j;

try {
int i = getEndMember(a);
if (i == 0) {
throw new ArithmeticException();
}
else{
j = 10/i;
}
}
catch(ArithmeticException e) {
System.out.println("ArithmeticException");
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndexOutOfBoundsExceptionkkkk");
}
}
Đoạn code trên sẽ in ra ArithmeticException bởi vì giá trị nhận được i = 0

1.4 Exception tự định nghĩa
Chúng ta có thể tự định nghĩa ra những lớp ngoại lệ riêng nếu chúng ta thấy java cung cấp chưa đủ thông tin ngoại lệ như chúng ta mong muốn.
Ví dụ về cách sử dụng exception tự định nghĩa:
class MyException extends Exception {
MyException() {

}
}

public class ExceptionDemo {
public static void executeHasException() throws MyException {
throw new MyException();
}

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
executeHasException();
} catch (MyException e) {
e.printStackTrace();
}
}
}
Và kết quả in ra màn hình sẽ là
exception_2.MyException
at exception_2.ExceptionDemo.executeHasException(ExceptionDemo.java:18)
at exception_2.ExceptionDemo.main(ExceptionDemo.java:27)

1.5 Một số exception đơn giản
a. NullPointerException (java.lang)
Xảy ra khi chúng ta tham khảo đến một đối tượng rỗng
Ví dụ:
• Gọi phương thức instance của một đối tượng rỗng
• Truy cập thuộc tính của một đối tượng rỗng
• …
int[] a = null;
int b;

try {
b = a[10];
}
catch (NullPointerException e)
{
System.out.println("NullPointerException"); //In ra NullPointerException
}
Đoạn code trên sinh ra một exception NullPointerException bởi vì đối tượng a là rỗng mà chúng ta vẫn truy cập thuộc tính của nó.

b. NumberFormatException (java.lang)
Một exception cũng khá thường gặp là khi biến đổi string sang số
Ví dụ:
String s = "Luvina";

try {
int i = Integer.parseInt(s);
}
catch (NumberFormatException e)
{
System.out.println("NumberFormatException"); //In ra NumberFormatException
}
Đoạn code trên sẽ xảy ra exception vì chuỗi s không thể biến đổi thành số nguyên i được

c. ArayIndexOutOfBoundsException (java.lang)
Truy xuất phần tử ngoài phạm vi của mảng
int[] a = {1, 2, 3};
int b;

try {
b = a[10];
}
catch (ArrayIndexOutOfBoundsException e)
{
System.out.println("ArrayIndexOutOfBoundsException");
}

d. ArithmeticException (java.lang)
Lỗi do các biểu thức toán học, thường là do chia cho 0
Ví dụ:
int a = 0;
int b = 1;
int c;

try {
c = b/a;
}
catch (ArithmeticException e)
{
System.out.println("Arithmetic Exception");
}

Lập trình java và kỹ năng căn bản

1.1 Giới thiệu
Java là một ngôn ngữ lập trình hướng đối tượng, là một ngôn ngữ vừa biên dịch và thông dịch. Mã nguồn java được biên dịch ra dạng ByteCode (tập tin với phần mở rộng .class) bằng trình biên dịch ví dụ javac. Sau đó sẽ đem đi thực thi trên từng platform khác nhau bằng một cộng cụ thông dịch thường gọi là JVM

1.2 Môi trường java
JDK (java development kit) là bộ công cụ phát triển phần mềm cho java, nó bao gồm nhiều công cụ tiện ích như trình biên dịch (javac), chương trình phát sinh tài liệu (javadoc), đóng gói dữ liệu (jar), chương trình tìm lỗi (jdb),…
JVM (Java Virtual Machine) là một phần mềm dùng để biên dịch các mã ByteCode java sang mã máy. Máy ảo java giống như một kênh liên kết phần cứng thiết bị, hệ điều hành và chương trình java để làm sao có thể chuyển chương trình java thành mã thực thi trên thiết bị đó.
Java API (Java Application Programming Interface) là một thư viện chứa các tiện ích giúp hỗ trợ việc lập trình bằng ngôn ngữ java, các tiện ích thường được đóng thành các gói (package). Java API thường được chia thành 2 phần Core API và Extension API. Core API thường gồm các package như java.lang, java.io, java.apple, java. awt, java.net, java.sql… Extension API chứa các gói dữ liệu tiện ích để bổ sung cho Java Core API như javax.crypto… Chú ý tùy từng phiên bản jdk mà có hỗ trợ gói extension API đó hay không.
Java compiler là compiler dùng để biên dịch mã nguồn java sang dạng bytecode (.class file). Những file này muốn thực thi thì cần dùng bộ JRE (Java Runtime Environment) trong JVM

Ví dụ cách thực thi một file java từ dòng lệnh dùng trình biên dịch có sẵn trong bộ jdk là javac.exe



1.3 Các kiểu dữ liệu cơ bản
Java cung cấp các kiểu dữ liệu cơ bản nguyên thủy (primitive) như:
Kiểu dữ liệu Độ dài theo số bit Phạm vi Mô tả
byte 8 -128 đến 127 Chúng được sử dụng rộng rãi khi xử lý một file văn bản
Char 16 ‘\uoooo’ to ’u\ffff ’ Kiểu Char sử dụng để lưu tên hoặc các dữ liệu ký tự
Boolean 1 “True” hoặc “False” Dữ liệu boolean dùng để lưu các giá trị “Đúng” hoặc “sai”
short 16 -32768 đến 32767 Kiểu short dùng để lưu các số nguyên có giá trị nhỏ.
Int 32 -2,147,483,648 đến +2,147,483,648 Kiểu int dùng để lưu một số nguyên có giá trị lớn đến 2,147,483,648
Long 64 -9,223,372,036’854,775,808 đến +9,223,372,036’854,775,808 Kiểu này dùng để lưu các số nguyên có giá trị cực lớn
Float 32 -3.40292347E+38 đến +3.40292347E+38 Kiểu float dùng để lưu các số thập phân đến 3.40292347E+38 Ví dụ : giá thành sản phẩm
double 64 -1,79769313486231570E+308 đến +1,79769313486231570E+308 Kiểu double dùng để lưu các số thập phân có giá trị lớn đến
1,79769313486231570E+308 Ví dụ giá trị tín dụng của ngân hàng nhà nước.

Ngoài ra java còn có 3 kiểu dữ liệu khác gọi là kiểu dữ liệu tham chiếu (reference)
Kiểu dữ liệu Giải thích
Mảng (Array) Tập hợp các dữ liệu cùng loại. Ví dụ : tên sinh viên
Lớp (Class) Tập hợp các biến và các phương thức.Ví dụ: lớp “Sinhviên” chứa toàn bộ các chi tiết của một sinh viên và các phương thức thực thi trên các chi tiết đó.
Giao diện (Interface) Là một lớp trừu tượng được tạo ra để bổ sung cho các kế thừa đa lớp trong Java.


1.4 Biến và toán tử
a. Biến
Như các ngôn ngữ lập trình khác, java sử dụng các biến để lưu dữ liệu cần thiết trong lúc chương trình thực thi. Các biên luôn đươc phân biệt bằng tên và phạm vi tác động. Khai báo biến: Kiểu dữ liệu, tên biến, giá trị ban đầu (không bắt buộc)
Datatype indentifier [=value] [, indentifier[=value]… ];
Ví dụ:
int count=0;
float salary;

Java định nghĩa hai loại biến:
• Biến không có từ khóa static: tức là biến khai báo bình thường như ví dụ trên. Và muốn truy xuất biến thì bạn cần tạo ra một đối tượng của class chứa biến đó là truy xuất biến bình thường
• Biến có từ khóa static: Trong khai báo biến bạn thêm từ khóa static ở đầu lệnh khai báo. Bạn có thể truy xuất biến này bằng cách như biến không có từ khóa static hoặc bằng cách dùng tên lớp gọi (.) biến.
VD:
class MyStaticVariables {
static int count = 10;
}
Truy cập
int mySVCount = MyStaticVariables.count; //Se tra ve gia tri la 10

Phân biệt giữa biến static và non-static: biến non-static chỉ có thể truy cập khi bạn có đối của lớp và mỗi đối tượng sẽ có những vùng nhớ khác nhau để lưu giữ biến. Biến static không bắt buộc phải tạo ra đối tượng mới có thể truy cập vào biến và sẽ chỉ có một vùng nhớ duy nhất cho biến trong chương trình cho dù bạn tao nhiều đối tượng.

Trong java các biến cũng sẽ được phân biệt phạm vi như các ngôn ngữ lập trình khác đó là khai báo phạm vi nào thì dùng trong phạm vi đó. Ví dụ bạn khai báo biến trong hàm f thì chỉ sử dụng được trong hàm f

b. Toán tử
Java hỗ trợ rất nhiều toán tử phổ biến như các ngôn ngữ lập trình khác:
Gán Giải thích
= Gán bằng
+= Cộng rồi gán
-= Trừ rồi gán
*= Nhân rồi gán
/= Chia rồi gán
%= Lấy dư rồi gán
<<= Dịch trái rồi gán
>>= Dịch phải rồi gán
>>>= Dịch phải rồi gán (không dấu)
&= AND bằng
^= XOR bằng
|= OR bằng
Số học căn bản
+ Cộng
- Trừ
* Nhân
/ Chia
% Lấy phần dư
Quan hệ
== So sánh bằng
> Lớn hơn
>= Lớn hơn hoặc bằng
< Nhỏ hơn
<= Nhỏ hơn hoặc bằng
!= So sánh khác
instanceof Kiểm tra loại dữ liệu
Logic và điều kiện
&& AND
|| OR
?: Kiểm tra và lấy giá trị
Đơn nhất
+ Giá trị dương
- Giá trị âm
! Giá trị phủ định
++ Tăng 1 đơn vị
-- Giảm một đơn vị
Dịch bit
~ Phủ định
<< Dịch trái 1 bit
>> Dịch phải 1 bit
>>> Dịch phải 1 bit (không dấu)
& AND
^ XOR
| OR
Khác
[] Truy cập phần tử mảng
. Truy cập vào thành viên lớp
new Tạo ra một đối tượng mới

Và thứ tự ưu tiên giữa các toán tử như sau:
Thứ tự Toán tử
1 Các toán tử đơn nhất như +,-,++,--
2 Các toán tử số học và các toán tử dịch bit như *,/,+,-,<<,>>
3 Các toán tử quan hệ như >,<,>=,<=,= =,!=
4 Các toán tử logic và Bit như &&,II,&,I,^
5 Các toán tử gán như =,*=,/=,+=,-=



1.5 Cấu trúc điều khiển
Trong java sử dụng các cấu trúc điều khiển sau:

Điều khiển rẽ nhánh
• if-else
/*Print i < j*/
int i = 0;
int j = 1;
if (i < j)
{
System.out.println("i < j");
}
else
{
System.out.println("i > j");
}

• switch-case
/*Print Thursday*/
int day =4;
switch(day) {
case 0 :
System.out.println("Sunday");
break;

case 1 :
System.out.println("Monday");
break;

case 2 :
System.out.println("Tuesday");
break;

case 3 :
System.out.println("Wednesday");
break;

case 4 :
System.out.println("Thursday");
break;

case 5 :
System.out.println("Friday");
break;

case 6 :
System.out.println("Satuday");
break;

case 7 :
System.out.println("Saturday");
break;

default :
System.out.println("Invalid day of week");
break;
}
Vòng lặp
• while
VD:
int[] a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i = 0;
while(i < 10) {
System.out.println(a);
i++;
}

• do-while
int[] a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int i = 0;
do {
System.out.println(a);
i++;
} while (i < 10);

• for
VD1:
int[] a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int i = 0; i < 10; i++){
System.out.println(a);
}

VD2:
int[] a = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for(int i : a){
System.out.println(i);
}

1.6 Các hàm toán học cơ bản
Package java.lang chứa những phương thức cơ bản nhất trong lập trình java và các hàm toán học cơ bản được đặt trong package java.lang.Math
• abs()
Trả về giá trị tuyệt đối của một số
int num = -1;
Math.abs(num); //Tra ve 1
• ceil()
Trả về số nguyên lớn hơn tham số truyền vào
Math.ceil(10.009); //Tra ve 11
• floor
Trả về số nguyên nhỏ hơn tham số truyền vào
Math.abs(num); //Tra ve 1
• pow(a, b)
Trả về một số double có giá trị là ab
Math.pow(2, 3); //Tra ve 8.0
• max()
Tìm giá trị lớn nhất trong hai giá trị được truyền vào
int a = -1;
int b = 1;
Math.max(a, b); //Tra ve 1
• min
Tìm giá trị nhỏ nhất trong hai giá trị được truyền vào
int a = -1;
int b = 1;
Math.min(a, b); //Tra ve -1
• round()
Làm tròn số có dấy chấm động và trả về một số kiểu long
double a = 1.2;
Math.round(a); //Tra ve 1

• random()
Trả về một số ngẫu nhiên có kiểu double trong khoảng 0.0-1.0
• sqrt()
Trả về căn bậc 2 của một số
double a = 1.44;
Math.sqrt(a); //Tra ve 1.2
• sin()
Trả về sine của một số

Math.sin(Math.PI/2); //Tra ve 1.0

• cos()
Trả về cosin của một số

Math.cos(Math.PI/2); //Tra ve 0.0

• tan()
Trả về tang của một số

Math.tab(-Math.PI); //Tra ve 0.0

1.7 Cấu trúc chương trình java

Một chương trình java được được chia thành các gói, lớp riêng biệt. Tất cả các biến, hàm phải được thực thi trong phạm vi của lớp. Chúng ta hãy xem một chương trình java đơn giản:

public class HelloLuvina {
public static void main(String[] args) {
System.out.println("Hello Luvina"); //Tra ve Hello Luvina
}
}

Đầu tiên là chúng ta có một lớp tên là HelloLuvina, trong lớp có một phương thức main. Phương thức main là điểm bắt đầu để thực thi ứng dụng, mỗi ứng dụng phải chứa một phương thức main có dạng public static void main(String[] args). Sau đây chúng ta sẽ phân tích các thành phần chính của phương thức main:
• public chỉ ra rằng phương thức main có thể được gọi bởi bất kỳ đối tượng nào.
• static chỉ ra rắng phương thức main là một phương thức lớp và có duy nhất một vùng nhớ lưu giữ nó và không cần tạo một đối tượng của lớp thì JVM vẫn có thể gọi tới phương thức main này để thực thi.
• void chỉ ra rằng phương thức main sẽ không trả về bất kỳ một giá trị nào.
• args là một mảng các chuỗi là những tham số mà bạn có thể truyền vào khi thực thi ứng dụng java
Dòng lệnh System.out.println("Hello Luvina"); dùng để in ra màn hình chuỗi “Hello Luvina”
Trong đầu mỗi chương trình java thường có thêm những thông tin để chương trình xác định thông tin môi trường, những thông tin này được chỉ dẫn bằng phát biểu “import”, ví dụ: import java.io.*; là để chỉ dẫn chương trình sử dụng tất cả các lớp trong gói nhập xuất. Khái niệm gói (package) ra đời từ ý nghĩa cần tổ chức quản lý tốt hơn, linh hoạt hơn, từ các thông tin, yêu cầu chúng ta đóng gói thành lớp, và để quản lý nhiều lớp có cùng một số điểm chung nào đó chúng ta nhóm chúng thành các gói và khi cần sử dụng phần nào hay toàn bộ gói chúng ta dùng lệnh “import”

Đối với ứng dụng applet thì cấu trúc chương trình sẽ khác ứng dụng java thông thường, chúng thường gồm các phương thức public void init(), public void start(), public void paint(Graphics g), public void destroy() … Chúng ta sẽ tìm hiểu applet trong các phần sau.
1.8 Cách đọc tham số và chuẩn hóa code convention
a. Tham số dòng lệnh
Chúng ta sẽ xem chương trình sau:
public class HelloLuvina {
public static void main(String[] args) {
System.out.println("Hello Luvina"); //Tra ve Hello Luvina
int length = args.length;
for(int i = 0; i < length; i++) {
System.out.println(args); //Tra ve cac tham so
}
}
}
Kết quả thực thi như sau:


Nhìn vào kết quả ta thấy các tham số được phân biệt với nhau bằng dấu khoảng trắng (white space)
b. Truyền tham số
Như trong phần các kiểu dữ liệu cơ bản, chúng ta thấy trong java có 2 kiểu là primitive và reference. Các tham số được truyền theo lời gọi hàm thì được thực hiện theo nguyên tắc: tham trị (pass-by-value) dùng cho 8 kiểu dữ liệu primitive, tham biến (pass-by-reference) dùng cho 3 kiểu dữ liệu reference.
Chúng ta xem ví dụ sau:
class Parameter {
public void passByValue(int a) {
a = 0;
}
public void passByReference(int[] array) {
array[0] = 0;
array[1] = 10;
}
}

public class HelloLuvina {
public static void main(String[] args) {
int number = 10;
int[] arrayOfStaffId = {1, 2};
Parameter p = new Parameter();
p.passByValue(number);
p.passByReference(arrayOfStaffId);

System.out.println(number); //In ra 10
for(int Id : arrayOfStaffId) {
System.out.println(Id); //In ra 0 va 10
}
}
}
Vì number sau lời gọi hàm không thay đổi giá trị vì nó là kiểu primitive nên tham số truyền sẽ là tham trị. Còn mảng arrayOfStaffId là kiểu reference nên tham số truyền là tham biến và giá trị của nó sẽ bị thay đổi.
• Truyền tham số kiểu Varargs (variable arguments)
Chúng ta hãy xem ví dụ sau:
public class HelloLuvina {
public static int makeSum(int... array) {
int sum = 0;
for (int i : array) {
sum += i;
}
return sum;
}

public static void main(String[] args) {
int sum = makeSum(1);
System.out.println(sum); //In ra 1

sum = makeSum(1, 2, 3);
System.out.println(sum); //In ra 6

int[] array = {1, 2, 3, 4, 5};
sum = makeSum(array);
System.out.println(sum); //In ra 15


}
}
Chúng ta hãy nhìn tham số array khai báo trong phương thức makeSum, kiểu khai báo … này được gọi là varargs và có từ java 5. Tiếp đến chúng chúng ta sẽ xem 3 dòng gọi hàm makeSum trong hàm main. Với các gọi có thể truyền như một mảng hay một chuỗi các tham số và Tính năng varargs sẽ tự động thực hiện việc tạo ra mảng tham số cho ta và đồng thời che dấu nó khỏi chương trình. Điều này giúp code trông tự nhiên và gọn gàng hơn.
Một lưu ý là trong một hàm ta chỉ có thể khai báo duy nhất một tham số kiểu varargs và phải là tham số cuối cùng, nếu không trình biên dịch sẽ báo lỗi. Ví dụ
public static int makeSum(int... array, int index) {…} //Sai
public static int makeSum(int index, int... array, int... array1) {…} //Sai
public static int makeSum(int index, int... array) {…} //Dung

1.9 Khái niệm kế thừa, đa hình, interface, constructor, final, overload, override
Trong phần này tôi sẽ giới thiệu về các khái niệm cơ bản của lập trình hướng đối tượng trong java. Các đặc điểm của lập trình hướng đối tượng thì chúng ta đã biết, trong phần này chúng ta sẽ nghiên cứu trực tiếp sự thể hiện hướng đối tượng trong java như thế nào
Kế thừa trong java sử dụng từ khóa extends, ví dụ bạn có lớp Car và một lớp Toyota kế thừa từ lớp Car, bạn sẽ viết như sau:
class Car {

}

class Toyota extends Car {

}
Và khi lớp Toyota được kế thừa từ Car thì nó sẽ nhận tất cả các thông tin được phép của lớp Car làm của mình hoặc có thể thay thế các phương thức này bằng các khai báo chồng.
Lớp trừu tượng là lớp không cụ thể, chứa những method nhưng không có dòng lệnh thi hành phương thức đó, việc thi hành method được giao lại cho các lớp kế thừa lớp đó, ví dụ:
abstract class Vehicle {
abstract void move(int x, int y);
abstract void setSize(int x, int y);
abstract void setColor(Color pColor);
}

class Car extends Vehicle{
void move(int x, int y) {
System.out.println("Method [move] from class [Car]");
}
void setSize(int x, int y) {
System.out.println("Method [setSize] from class [Car]");
}
void setColor(Color pColor) {
System.out.println("Method [setColor] from class [Car]");
}
}

Lưu ý là một lớp chỉ được kế thừa duy nhất từ một lớp cha (kể cả abstract class)
Interface là một khái niệm mới trong các ngôn ngữ lập trình hiện đại, thường được hiểu là giao diện của lớp đối tượng. Tức là interface chứa những thành phần (phương thức) để các lớp khác kế thừa, và các phương thức trong interface không có phần cài đặt mà chỉ có phần khai báo.
Một class kế thừa một interface nào thì bắt buộc phải cài đặt tất cả các method của interface đó. Một đối tượng có thể đưa ra nhiều interface của mình, và như vậy chúng java không có đa kế thừa nhưng chúng ta cũng có thể làm bằng các interface.
Chúng ta dùng từ khóa implements để kế thừa từ một interface, ví dụ ta có một interface là QualityAssurance và một lớp là Car để kế thừa những phương thức kiểm tra chất lượng từ interface đó:

interface QualityAssurance {

}

class Car implements QualityAssurance{

}

Constructor là một phương thức dùng để khởi tạo lớp và truyền tham số để khởi tạo giá trị cho một đối tượng. Constructor trong java cũng có tên giống với tên lớp, không có kiểu trả về và không có cả từ khóa void, một lớp có thể có nhiều constructor và constructor không được kế thừa.



1.10 Ép kiểu và generic type
Java cung cấp các loại ép kiểu sau:
• Implicit Casting (automatic casting) là loại tự động ép kiểu khi phép gán giữa hai kiểu khác nhau và được thực hiện bởi trình biên dịch. Ví dụ:
int a = 1;
double b = a;
System.out.println(b); //In ra 1.0
Một quy tắc đơn giản trong ép kiểu là ép từ kiểu bé sang kiểu lớn thì được, vì kiểu lớn mới có thể chứa hết kiểu bé và không mất dữ liệu. Và quy tắc cho các kiểu cơ bản là:
byte -> short-> int -> long -> float -> double
Tương tự cho các đối tượng, ép từ đối tượng con sang đối tượng cha thì được. Ví dụ ta có lớp Car và lớp Ferrary kế thừa từ Car, và một đối tượng thuộc lớp Ferrary có thể được ép kiểu thành đối tượng thuộc lớp Car, ngược lại thì không thể.

Explicit casting là dạng ép kiểu được ghi tường minh trong chương trình. Ví dụ:
double b = 1.9;
short c = (short)b;
System.out.println(c); //In ra 1

Generic
Generic là một khái niệm mới và bắt đầu có từ java 5, nếu ai lập trình nhiều về template trong c++ thì Generic trong java cũng tương tự. Ưu điểm của Generic là linh động trong việc truyền tham số, và một ưu điểm người ta hay nhắc tới của Generic là làm cho chương trình ổn định hơn và tránh các lỗi ép kiểu.
Chúng ta xem ví dụ:
List l = new ArrayList();
l.add(1);
Integer i = (Integer)l.get(0);
System.out.println(i); //In ra 1

Ví dụ trên chạy tốt và in ra 1. Tuy nhiên chúng ta chỉnh một chút là add một chuỗi vào danh sách như sau:
List l = new ArrayList();
l.add("nice");
Integer i = (Integer)l.get(0);
System.out.println(i);
Chương trình chỉ bị lỗi lúc runtime, và do đó đôi khi không để ý là chúng ta có thể mắc lỗi này. Generic ra đời để giúp chúng ta có thể thấy tường minh lỗi trong khi code, tránh trường hợp lỗi tiềm tàng khi runtime. Ví dụ:
List l = new ArrayList();
l.add(1);
Integer i = (Integer)l.get(0);
System.out.println(i); //In ra 1
Chương trình chạy và in ra 1. Còn khi bạn viết như dưới bạn sẽ bị một lỗi ngay lúc compiler là không tương thích kiểu và như vậy là chúng ta có thể nhận được lỗi lúc biên soạn tránh được lỗi tiềm tàng.
List l = new ArrayList();
l.add("nice"); //Báo lỗi khi biên dịch
Integer i = (Integer)l.get(0);
System.out.println(i);