Shallow Copy và Deep Copy

Chào mừng các bạn đã quay trở lại với thachleblog. Trước khi bắt đầu với chủ đề ngày hôm nay, mình có 1 câu hỏi muốn hỏi các bạn “Các bạn đã bao giờ tạo một object mà không dùng toán tử new() chưa?”. Nếu câu trả lời là chưa, thì bài viết về shallow copy và deep copy này chắc chắn là dành cho bạn. Tuy nhiên, các bạn đã biết cũng có thể đọc và cho nhận xét để chúng ta có thể trao đổi thêm. Nào, chúng ta cùng bắt đầu với chủ Shallow Copy và Deep Copy nhé.

Clone object

Trước khi đến với Shallow Copy và Deep Copy, chúng ta cùng tìm hiểu về clone object

Thông thường, chúng ta tạo object bằng lệnh new Object(). Object này sẽ được tạo mới trong vùng nhớ của JVM. Khác với new, clone object là quá trình tạo object từ object đã tồn tại trong vùng nhớ. Trong java, phương thức clone(), dùng để clone 1 object từ object có sẵn. Để 1 object có thể clone, object đó cần phải implement Clonable interface.

Shallow Copy và Deep Copy là các quá trình tạo object bằng phương pháp clone. Mặc định của method clone() là Shallow Copy. Để 1 object được Deep Copy. Chúng ta cần override method clone. Chúng ta cùng xem Shallow Copy và Deep Copy là như nào nhé.

Shallow Copy 

Shallow Copy là quá trình tạo object copy mà trong đó nếu object đó có chứa object chứa trong khác thì quá trình copy chỉ copy reference (địa chỉ vùng nhớ) của object chứa trong đó.

Hình minh họa shallow copy

Hình minh họa shallow copy 

Điều đó cả nghĩa là ContainObject1 của 2 object MainObject1 và MainObject2 cùng trỏ tới một giá trị. Khi thay đổi giá trị của ContainObject1 trên MainObject1, giá trị của ContainObject2 trên MainObject2 sẽ thay đổi theo.

Code minh họa Shallow Copy 

Class Student

package shallow.copy;
 
/**
 *
 * @author thachlp
 */
public class Student implements Cloneable{
 
    private String name;
    private Course course;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Student(String name, Course course){
        this.course = course;
        this.name = name;
    }
 
    public Course getCourse() {
        return course;
    }
 
    public void setCourse(Course course) {
        this.course = course;
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); //To change body of generated methods
    }
 
}

 

Để có thể clone object, Student cần implement Cloneable interface. Trong Student object sẽ có Course object.

Class Course

package shallow.copy;
 
/**
 *
 * @author thachlp
 */
public class Course {
    private String name;
    private int lenght;
 
    public int getLenght() {
        return lenght;
    }
 
    public void setLenght(int lenght) {
        this.lenght = lenght;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Course(String name, int lenght){
        this.name = name;
        this.lenght = lenght;
    }
 
}

 

Class Test

package shallow.copy;
 
/**
 *
 * @author thachlp
 */
public class TestShallowCopy {
 
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student("Thach", new Course("Java programming", 4));
        System.out.println(student1.getCourse().getName());
 
        Student student2 = (Student) student1.clone();
        student2.getCourse().setName("Python programming");
        System.out.println(student1.getCourse().getName());
 
    }
 
}

 

Kết quả : khi update giá trị cho course object ở student1, giá trị của course ở object2 cũng sẽ thay đổi theo, kết quả khi chạy chương trình:

Java programming
Python programming

Deep Copy

Khác với Shallow Copy, Deep Copy sẽ tạo ra object mới với reference độc lập với object gốc. Mọi thay đổi object chứa trong sẽ không ảnh hưởng đến nhau.

Hình minh hạo Deep Copy

Hình minh họa deep copy

Code minh họa Deep Copy 

Class Student

package deep.copy;
 
 
/**
 *
 * @author thachlp
 */
public class Student implements Cloneable {
 
    private String name;
     Course course;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Student(String name, Course course) {
        this.course = course;
        this.name = name;
    }
 
    public Course getCourse() {
        return course;
    }
 
    public void setCourse(Course course) {
        this.course = course;
    }
 
    @Override
    public Object clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.course = (Course) course.clone();
 
        return student; //To change body of generated methods
    }
 
}

 

Class Course 

package deep.copy;
 
 
/**
 *
 * @author thachlp
 */
public class Course implements Cloneable{
    private String name;
    private int lenght;
 
    public int getLenght() {
        return lenght;
    }
 
    public void setLenght(int lenght) {
        this.lenght = lenght;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public Course(String name, int lenght){
        this.name = name;
        this.lenght = lenght;
    }
 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); //To change body of generated methods, choose Tools | Templates.
    }
 
}

 

Cần chú ý là để Deep Copy, class Course cũng cần implement Cloneable interface.

Class Test

package deep.copy;
 
/**
 *
 * @author thachlp
 */
public class TestDeepCopy {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student1 = new Student("Thach", new Course("Java programming", 4));
 
        System.out.println(student1.getCourse().getLenght());
 
        Student student2 = (Student) student1.clone();
        student2.getCourse().setLenght(3);
        System.out.println(student1.getCourse().getLenght());
 
    }
 
}

 

Kết quả : object course bên trong object student1 và student2 là độc lập. Thay đổi course bên student1 sẽ không ảnh hưởng đến course của student2.

Java programming
Java programming

Kết luận

Vừa rồi mình vừa trình bày về clone() method, Shallow Copy và Deep Copy. Tùy theo trường hợp cụ thể mà ta sử dụng Shallow hoặc Deep. Sắp tới mình sẽ viết bài về prototype design pattern sẽ liên quan đến clone() method, các bạn nhớ đón đọc nhé. Mọi góp ý về bài viết này xin vui lòng comment bên dưới, mình sẽ follow.

Xin cảm ơn.

Xem thêm:

http://javaconceptoftheday.com/difference-between-shallow-copy-vs-deep-copy-in-java/ 

http://www.jusfortechies.com/java/core-java/deepcopy_and_shallowcopy.php

Quản lý session trong Java Servlet

Chào mừng các bạn đã quay trở lại với thachleblog. Bài viết hôm nay, mình sẽ cùng các bạn tìm hiểu về session và cách quản lý session trong Java servlet. Qua bài viết này, hy vọng các bạn có thể hiểu được session là gì và các cách để quản lý session trong các ứng dụng servlet. Nào, chúng ta cùng bắt đầu nhé.

Giới thiệu

Session có thể được hiểu là một “phiên làm việc” của user trên ứng dụng web, bao gồm nhiều request và response giữa client – server.

Ví dụ, từ lúc user đăng nhập vào web, xem hàng, chọn hàng, thanh toán, kiểm tra hóa đơn…  Thì toàn bộ quá đó có thể xem là một session. Nếu user logout hoặc tắt trình duyệt, đăng nhập lại, thì đã là session khác.

Cơ chế

Cơ chế của session về cơ bản là khi user đăng nhập và bắt đầu sử dụng ứng dụng, chúng ta sẽ có thể lấy thông tin duy nhất xác định session (có thể là user id hoặc session id). Thông tin này sẽ được giữ và đính kèm theo các request và reponse để xác định user và session. Khi user logout hoặc thoát chương trình, chúng ta có thể xóa thông tin này để kết thúc session.

Hình minh họa cơ chế của Session

Hình minh họa cơ chế của Session

Quản lý session

Để quản lý session, chúng ta có thể sử dụng HttpSession, Cookies, URL Rewriting, Hidden form field.

  • HttpSession: là object dùng để lưu trữ thông tin cho mỗi user. Sau khi nhận request đầu tiên từ client, Web Container sẽ tạo ra một session ID duy nhất dùng để xác định user và trả lại cho client. Session ID này sẽ được sử dụng trong suốt quá trình làm việc giữa client và server

HttpSession session = request.getSession(); // get session

session.invalidate(); // destroy a sesion

Các bạn có thể xem thêm HttpSession API tại đây

  • Cookies là thông tin có thể được tạo và đính kèm theo response được gửi từ webserver đến client. Thông tin này sẽ được lưu trữ trong trình duyệt bên phía client. Với mỗi request từ client, thông tin này cũng sẽ được đính kèm, phía server có thể sử dụng và kiểm tra để xác định thông tin user

Cookie cookie = new Cookie(“id” , “1234”); //create cookie on server

Cookies[] cookies = request.getCookies(); // get cookies from request

Các bạn có thể xem thêm các Cookie API tại đây

        Tuy sử dụng cookie đơn giản nhưng vì lưu trữ phía client nên sẽ có trường hợp              browser phía client không support cookie. Cần lưu ý trường hợp này

  • URL Rewriting: là thông tin kèm theo url trong mỗi request bằng query param hoăc path param. Cái này quá quen thuộc rồi, mình sẽ không nói thêm nữa
  • Hidden form field: là các field (thường là input) có thuộc tính là hidden để đính kèm thông tin mà không cho user nhìn thấy. Dạng này thường được sử dụng trong các trường hợp form submit. (Bản thân mình thì không thường xài cách này lắm, chỉ tìm hiểu cho biết thôi).

Kết

Session được sử dụng hầu như trong tất cả các ứng dụng client – server. Thông qua bài viết này, mình hy vọng các bạn rõ hơn về khái niệm session và hiểu được ưu nhược điểm của các cách quản lý session qua đó có thể ứng dụng hiệu quả trong từng trường hợp cụ thể. Bài viết này có thể có nhiều thiếu sót, do đó mình mong nhận được ý kiến đóng góp của tất cả các bạn. Hẹn gặp lại các bạn ở các bài viết sau.

Tham khảo thêm

http://www.studytonight.com/servlet/session-management.php

http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url-rewriting