Java - Những mảnh kiến thức nhỏ

- Class không có constructor thì compiler lấy constructor mặc định - không đối số, các thuộc tính gán giá trị mặc định.
Nếu lớp con không có constructor, compiler gọi 1 constructor mặc định, đồng thời gọi luôn constructor không đối số của lớp cha (lúc này nếu lớp cha có 1 constructor có đối số thì sẽ gây lỗi, thà không có luôn để compiler ban phát miễn phí constructor mặc định)

- Access level of class:
+ Outer class chỉ có thể là public (visible với mọi class) hoặc package private (ngầm định - không có từ khóa public - visible trong package). Điều tương tự với Interface.
+ Ở phạm vị member cũng tương tự, có thêm private - visible trong nội bộ class, protected - visible trong package và các lớp con (khác package).
+ Interface cũng chỉ có thể là public hay package, không thể private hay protected
+ Interface chỉ chứa thành viên public hoặc package private
+ Outer class hoạt động gần giống static, trong khi đó inner class thì không.

- Phân biệt Parameter và Argument
Parameter là tham số lúc khai báo/ định nghĩa method
Argument là giá trị thực truyền vào khi gọi method

- Trong java, không thể truyền method như là 1 parameter tới method khác, thay vào đó, ta có thể truyền đối tượng, sau đó gọi method sau.

- Khi hết sử dụng, tất cả các reference đến 1 object đều phải đặt về null thì mới có thể giải phóng object.

- Một method dùng 1 tên Class làm giá trị trả về, thì giá trị trả về phải là đối tượng của lớp đó, hoặc LỚP CON của lớp đó. Nếu dùng Interface như giá trị trả về, method đó phải trả về đối tượng của lớp implement Interface kia.

- Biến (thuộc tính) static của 1 class ngoài việc được gọi không cần thông qua đối tượng, còn 1 điều đáng lưu ý: Tất cả các lời gọi đến biến đó (từ gọi bằng [ClassName].[Biến static] đến việc gọi qua các đối tượng [DoiTuong1].[Biến static], [DoiTuong2].[Biến static]...) đều trỏ đến 1 vị trí duy nhất trên bộ nhớ  Vì vậy, 1 thay đổi sẽ là thay đổi chung trên các đối tượng khác nhau (nếu có).

Các biến static còn được gọi là class variable, biến không static gọi là instance variable

- Nested class:
+ Chia 2 loại, static nested class và inner class (non-static)
++ Static nested class: (SNC)
    - Giống như static field, SNC không truy cập được bất cứ phần tử instance của lớp cha, nếu muốn phải thông qua object, với các phần tử này, SNC truy cập y như các top-level class khác.
++ Inner class (IC):
    - Truy cập các phần tử của lớp cha như mọi thành phần khác.
    - Không thể chứa bất kỳ static member nào
    - IC có thể chia thành 2 loại nhỏ:
      + Local class:
        - Là class nằm trong 1 block,
        - Có thể truy cập thành viên của lớp ngoài (không nằm trong block) thông qua: [Lớp outer].[Thành viên]
        - Nếu Local class nằm trong static method thì nó chỉ truy cập được các thành viên static của lớp ngoài mà thôi (nhưng ngay cả khi đó, local class vẫn là non-static nhé, nó luôn luôn là vậy :)
        - Truy cập các biến local (bên trong khối block) chỉ khi các biến này là final. Tuy vậy, từ SE 8 trở lên, local class có thể gọi trực tiếp parameter của method chứa nó.
        - Không thể chứa bất kỳ static member nào. Trường hợp duy nhất là constant (constant là biến kiểu primitive hoặc String được khai báo và khởi tạo với compile-time constant expression - là một chuỗi hoặc một biểu thức số học có thể được xác định giá trị ở thời gian biên dịch)
      + Anonymous class:(AC)
        - Xem ví dụ sau:

class Demo {
...
public class CHello {                               // Inner class
        private String sMsg = "hello";
        public void display(String aMsg) {
            Calc.log(aMsg);
        }
    }
    public void FHello() {
        CHello annClass = new CHello() {        // go to ANONYMOUS class - extends CHello
            @Override
            public void display(String aMsg) {
                Calc.log(aMsg);
                Calc.log(aMsg);
            }
        };
        annClass.display("hello");
    }
public static void main(String args[])
    {
        Demo ds = new Demo();
        ds.FHello();
    }

        - AC được xem là 1 phần của biểu, như đã thấy trên ví dụ, nó kết thúc với ";"
        - AC đi với việc extends 1 class hay implement 1 interface nào đó
        - Trong AC, chí có thể là lệnh khai báo, method, chứ không thể chứa 1 statements nào.
        - Trong AC, bạn không thể tạo constructor
        - Các đặc điểm khác giống với Local class

- Enum:
Dạng đơn giản:
public enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY} 
Hay phức tạp hơn:
enum EnumDemo {        // Enum type class
    MERCURY (3.303e+23, 2.4397e6),
    VENUS     (4.869e+24, 6.0518e6),
    EARTH    (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6);
    private double mass;
    private double radius;    

    private EnumDemo(double aMass, double aRadius) {
        mass = aMass;
        radius = aRadius;
    }
    public double getMass() {
        return mass;
    }
    public double getRadius() {
        return radius;
    }

}
...
    public static void main(String args[])
    {

    EnumDemo ed = EnumDemo.MERCURY;
        if (ed.equals(EnumDemo.MERCURY)) {
            log("Mercury !");
            log("Mass: " + EnumDemo.MERCURY.getMass());
            log("Radius: " + ed.getRadius());
            //EnumDemo.MERCURY = EnumDemo.EARTH;    // Error
        }
        for (EnumDemo e : EnumDemo.values()) {
            switch (e) {
                case EARTH:
                    log(e + ": " + e.getMass() + " - " + e.getRadius() + " - We are here !");
                    break;
                default:
                    log(e + ": " + e.getMass() + " - " + e.getRadius());
            }
        }

    }
    public static void log(Object aMsg){
        System.out.println(String.valueOf(aMsg));
    }

Có thể coi là 1 dạng class/ interface đặc biệt với 1 số đặc điểm sau:
+ Có thể định nghĩa constructor, method, variable...
+ Như ví dụ trên, bạn có thể gán các giá trị với từng constant của Enum, trong trường hợp này bạn phải khai báo biến và constructor vì MERCURY(3.303e+23, 2.4397e6) thực chất gọi 1 constructor 2 đối số double để gán giá trị. Constructor phải là private. Chúng ta không dùng new để tạo instance cho enum.
+ Mỗi constant đều ngầm định là static final, vì vậy, lệnh sau sẽ sai:
      EnumDemo.MERCURY = EnumDemo.EARTH;    // Error
+ Như chúng ta thấy, ta có thể dùng switch .. case để làm việc với Enum.
+ Enum ngầm định extends lớp java.lang.Enum, vậy nên nó không thể extends thêm class nào khác. Đồng thời nó có sẵn nhiều method như toString(), values() như ta đã sử dụng trong ví dụ.
+ Chúng ta cũng hoàn toàn có thể Override các method như toString()


- Vài thứ về interface và inheritance:
+ Giả sử ta có interface InterfaceDemo và class ClassDemo implements interface này.
Chú ý về việc dùng interface như 1 kiểu dữ liệu sau:
ClassDemo cd = new ClassDemo();
InterfaceDemo id = (InterfaceDemo)cd;
khi đó cd bắt buộc phải là object của lớp implements Interface này.
+ Ta có thể mở rộng 1 interface đã có bằng cách viết 1 interface khác extends nó (không nên thêm cập nhật vào interface cũ vì sẽ khiến các class implement phải triển khai thêm):
public interface DoItPlus extends DoIt {
   boolean didItWork(int i, double x, String s);
}
+ Trnog interface:
   - field ngầm định luôn là public static final,
   - method ngầm định là public abstract
+ Modifier - khả năng truy cập của các method Override luôn >= các method được override trong superclass.
+ Overloading - nạp chồng (giống tên method, khác signature) và Override - ghi đè (giống signature) không thể thể cùng xảy ra trên 1 method ở subclass
+ Override method ở subclass có thể có kiểu giá trị trả về là subtype của kiểu trả về của method được override superclass, khi đó gọi là covariant return type

+ Chúng ta xem ví dụ sau về triển khai 1 interaface:


- java.lang.Object class - superclass of all - một vài method:
+ clone():
   - Nếu object không thuộc lớp implements của Cloneable interface thì sẽ báo lỗi: CloneNotSupportedException.
   - Nếu muốn dùng được, hoặc override, hoặc thêm "implements Cloneable" vào class mà ta sẽ dùng,
   - Đối với các object có tham chiếu các object khác, ta phải override method này để nó clone cả object ngoài kia.
+ equals()
   - Chỉ so sánh đúng với primitive data type, reference data type gần như phải override lại,
   - Khi override equals(), cần override cả hashCode()
+ finalize()
   - Không dựa vào hàm này để cleanup object

- Method nào được gọi bởi constructor, nên đặt với final để nó "cố định" !

- Abstract class:
+ Tương tự interface, ngoại trừ:
   - Có thể chứa các field không phải final, static
   - Có 1 hay nhiều abstract method (chỉ ở dạng khai báo - chưa implement - giống interface)
   - Có thể có hoặc không method được implement (cho phép các subclass kế thừa 1 số method định sẵn giống nhau, còn các method khác thì implement các kiểu khác nhau, linh hoạt hơn interface)
   - Được dùng trong trường hợp chia sẻ với lớp con nhiều method (đã implemt) và có 1 số method khác nhau (abstract method)
+ Các subclass phải implment hết đống abstract đó, nếu không chính các subclass cũng phải là abstract

- Generics:
+ Chú ý rằng:
Integer là lớp con của Number, nhưng
Box<Integer> thì KHÔNG phải là lớp con của Box<Number>. Do đó:
Number number = new Number();
Integer integer = new Integer();
number = integer; // OK
integer = number; // NO

Box<Number> boxNum = new Box();
Box<Integer> boxInt = new Box();
boxNum = boxInt; // NO

public void someMethod(Number n) { /* ... */ }
someMethod(new Integer(10));   // OK
someMethod(new Double(10.1));   // OK
Box<Number> box = new Box<Number>();
box.add(new Integer(10));   // OK
box.add(new Double(10.1));  // OK
Nhưng:
public void boxTest(Box<Number> n) { /* ... */ }
Box<Integer> boxInt = new Box<Integer>();
boxTest(boxInt);  // NO

Chú ý điều sau:
ArrayList<?> : là supertype của ArrayList<Integer>, ArrayList<String>,...
Trong khi ArrayList<Object> thì không phải. Do vậy, với method sau:
public static void printList(List<Object> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}
 Không chấp nhận List<Integer>, List<String>..., nhưng
public static void printList(List<?> list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}
thì chấp hết

Nhận xét