Header Ads Widget

Responsive Advertisement

Nổi bật

6/recent/ticker-posts

Constructor trong Java

Tôi tin rằng nếu bạn hiểu đúng về Java Core, bạn có thể học bất kỳ framework nào một cách dễ dàng. Rốt cuộc, mọi framework đều được xây dựng trên nền tảng của các tính năng Java Core. Dưới đây là bài viết về Constructor trong Java




Constructor
trong java được sử dụng để tạo thể hiện của lớp. Các constructor gần như tương tự với các phương thức ngoại trừ hai điều - tên của nó giống với tên lớp và nó không có kiểu trả về. Đôi khi các constructor cũng được coi là các phương thức đặc biệt để khởi tạo một đối tượng.


Constructor trong Java

        Bất cứ khi nào chúng ta sử dụng từ khóa new để tạo một thể hiện của một lớp, constructor được gọi và đối tượng của lớp được trả về. Vì constructor chỉ có thể trả về đối tượng cho lớp, nó được thực hiện ngầm bởi Java runtime và chúng ta không nên thêm kiểu trả về cho nó.


        Nếu chúng ta thêm một kiểu trả về vào một phương thức Constructor, thì nó sẽ trở thành một phương thức của lớp. Đây là cách Java runtime phân biệt giữa phương thức bình thường và phương thức Constructor. Giả sử chúng ta có mã sau trong lớp Employee

public Employee() {
   
System.out.println("Employee Constructor");
}

public
Employee Employee() {
   
System.out.println("Employee Method");
   
return new Employee();
}


    Ở đây cái đầu tiên là một constructor, hãy lưu ý rằng không có kiểu trả về và không có câu lệnh trả về. Phương thức thứ hai là một phương thức bình thường, trong đó chúng ta lại gọi phương thức khởi tạo đầu tiên để lấy cá thể Employee và trả về nó. Bạn không nên đặt tên phương thức giống với tên lớp vì nó tạo ra sự nhầm lẫn.


Các loại mã lệnh trong Java

Có ba loại phương thức khởi tạo trong java.
👉  Default Constructor
👉  No-Args Constructor
👉  Parameterized Constructor

Hãy xem xét tất cả các loại phương thức khởi tạo này với các chương trình ví dụ.


Default Constructor trong Java

        Không bắt buộc phải luôn cung cấp một triển khai phương thức Constructor trong mã lớp. Nếu chúng tôi không cung cấp một constructor, thì java sẽ cung cấp triển khai Default constructor để chúng tôi sử dụng. Hãy xem xét một chương trình đơn giản mà Default constructor đang được sử dụng vì chúng ta sẽ không xác định rõ ràng một constructor.

package com.hn.constructor;
public class Data {
   
public static void main(String[] args) {
       
Data d = new Data();
   
}
}


👉  Default constructor chỉ có vai trò là khởi tạo đối tượng và trả nó về mã gọi.
👉  Default constructor luôn không có đối số và chỉ được cung cấp bởi trình biên dịch java khi không có constructor nào được xác định.
👉  Hầu hết thời gian chúng ta đều ổn với chính phương thức Default constructor vì các thuộc tính khác có thể được truy cập và khởi tạo thông qua các phương thức getter setter.


No-Args Constructor

    Constructor không có bất kỳ đối số nào được gọi là no-args constructor. Nó giống như ghi đè default constructor và được sử dụng để thực hiện một số công việc tiền khởi tạo như kiểm tra tài nguyên, kết nối mạng, ghi nhật ký, v.v. Hãy xem nhanh no-args constructor trong java.

package com.hn.constructor;

public class Data {
   
//no-args constructor
   
public Data() {
       
System.out.println("No-Args Constructor");
   
}
    public
static void main(String[] args) {
       
Data d = new Data();
   
}
}



Bây giờ khi chúng ta sẽ gọi new Data(), thì phương thức no-args constructor của chúng ta sẽ được gọi. Hình ảnh dưới đây minh họa hành vi này, hãy kiểm tra đầu ra giao diện điều khiển của chương trình.


Parameterized Controller

        Constructor với các đối số được gọi là Parameterized Constructor( constructor tham số hóa). Hãy xem ví dụ về Parameterized Constructor trong java.

package com.hn.constructor;

public class Data {

   
private String name;
   
public Data(String n) {
       
System.out.println("Parameterized Constructor");
       
this.name = n;
    }
   
public String getName() {
       
return name;
    }
   
public static void main(String[] args) {
       
Data d = new Data("Java");
       
System.out.println(d
.getName());
    }

}




Constructor overloading trong Java

        Khi chúng ta có nhiều hơn một constructor, thì đó là constructor overloading trong java. Hãy xem một ví dụ về phương thức Constructor Overloading trong chương trình java.

package com.hn.constructor;
public class Data {

   
private String name;
   
private int id;
   
//no-args constructor
   
public Data() {
       
this.name = "Default Name";
    }
   
//one parameter constructor
   
public Data(String n) {
       
this.name = n;
    }
   
//two parameter constructor
   
public Data(String n, int i) {
       
this.name = n;
       
this.id = i;
    }

   
public String getName() {
       
return name;
    }

   
public int getId() {
       
return id;
    }

   
@Override
   
public String toString() {
       
return "ID="+id+", Name="+name;
    }
   
public static void main(String[] args) {
        
Data d = new Data();
       
System.out.println(d);

        d =
new Data("Java");
       
System.out.println(d);

        d =
new Data("HN", 25);
       
System.out
.println(d);
    }
}



Private constructor trong Java

        Lưu ý rằng chúng ta không thể sử dụng từ khóa abstractfinal, tĩnh synchronized với các constructor. Tuy nhiên, chúng ta có thể sử dụng access modifiers để điều khiển việc khởi tạo đối tượng lớp. Sử dụng publicdefault truy cập vẫn ổn, nhưng việc đặt một phương thức khởi tạo ở chế độ private thì có ích lợi gì? Trong trường hợp đó, bất kỳ lớp nào khác sẽ không thể tạo cá thể của lớp.

    Một phương thức khởi tạo được đặt ở chế độ riêng tư trong trường hợp chúng ta muốn triển khai singleton design pattern . Vì java tự động cung cấp default constructor, chúng ta phải tạo một cách rõ ràng một constructor và giữ nó ở chế độ private. Các lớp máy khách được cung cấp một phương thức static tiện ích để lấy thể hiện của lớp. Dưới đây là một ví dụ về phương thức private constructor cho lớp Data

// private constructor
private Data() {
   
//empty constructor for singleton pattern implementation
    //can have code to be used inside the getInstance() method of class
}



Constructor Chaining trong Java

Khi một constructor gọi một constructor khác của cùng một lớp, nó được gọi là constructor chaining. Chúng ta phải sử dụng từ khóa this để gọi một phương thức constructor khác của lớp. Đôi khi nó được sử dụng để đặt một số giá trị mặc định của các biến lớp.


Lưu ý rằng một lệnh gọi constructor khác phải là câu lệnh đầu tiên trong khối mã. Ngoài ra, không nên gọi đệ quy sẽ tạo ra một vòng lặp vô hạn. Hãy xem một ví dụ về constructor chaining trong chương trình java.

package com.hn.constructor;

public class Employee {

   
private int id;
   
private String name;

   
public Employee() {
       
this("Nhan vien", 999);
       
System.out.println("Default Employee Created");
    }

   
public Employee(int i) {
       
this("
Nhan vien", i);
       
System.out.println("Employee Created with Default Name");
    }
   
public Employee(String s, int i) {
       
this.id = i;
       
this.name = s;
       
System.out.println("Employee Created");
    }
   
public static void main(String[] args) {

       
Employee emp = new Employee();
       
System.out.println(emp);
       
Employee emp1 = new Employee(10);
       
System.out.println(emp1);
       
Employee emp2 = new Employee("HN", 20);
       
System.out.println(emp2);
    }

   
@Override
   
public String toString() {
       
return "ID = "+id+", Name = "+name;
    }
   
public int getId() {
       
return id;
    }

   
public void setId(int id) {
       
this.id = id;
    }

   
public String getName() {
       
return name;
    }

   
public void setName(String name) {
       
this.name
= name;
    }
}


Tôi đã ghi đè phương thức toString() để in một số thông tin hữu ích về đối tượng Employee

Chú ý cách một constructor đang được gọi từ một constructor khác, đó được gọi là quá trình constructor chaining.


Java Super Constructor

        Đôi khi một lớp được kế thừa từ lớp cha, trong trường hợp đó, nếu chúng ta phải gọi constructor lớp cha thì chúng ta có thể thực hiện việc đó bằng cách sử dụng từ khóa super. Hãy xem một ví dụ về việc sử dụng super constructor.

        Lưu ý rằng lệnh gọi super constructor phải là câu lệnh đầu tiên trong constructor lớp con. Ngoài ra, khi khởi tạo phương thức constructor lớp con, java đầu tiên khởi tạo lớp super và sau đó là lớp con. Vì vậy, nếu phương thức super constructor không được gọi rõ ràng thì phương thức default hoặc no-args constructor được gọi bằng java runtime. Chúng ta hãy hiểu những khái niệm này thông qua một số chương trình ví dụ.

Giả sử chúng ta có hai lớp như dưới đây. 

package com.journaldev.constructor;

public class Person {

   
private int age;
   
public Person() {
       
System.out.println("Person Created");
    }
   
public Person(int i) {
       
this.age = i;
       
System.out.println("Person Created with Age = "
+ i);
    }
}



package com.journaldev.constructor;

public class Student extends Person {

   
private String name;
   
public Student() {
       
System.out.println("Student Created");
    }
   
public Student(int i, String n) {
       
super(i); // super class constructor called
       
this.name = n;
       
System.out.println("Student Created with name = "
+ n);
    }
}



Bây giờ nếu chúng ta tạo một đối tượng Student như bên dưới:

Student st = new Student();



 Đầu ra của đoạn mã trên sẽ là:

Person Created
Student Created



Vì vậy, lời gọi đã chuyển đến constructor no-args của lớp Student vì không có lệnh gọi super nào trong câu lệnh đầu tiên mà hàm no-args hoặc default constructor của lớp Person được gọi. Do đó đầu ra. Điều gì sẽ xảy ra nếu chúng ta đang sử dụng parameterized constructor tham số hóa của lớp Student Student st = new Student(34, "Pankaj");, kết quả đầu ra sẽ là: 

Person Created with Age = 34
Student Created with name
= Pankaj



Ở đây đầu ra là rõ ràng vì chúng ta đang gọi super constructor một cách rõ ràng, vì vậy Java không cần phải thực hiện thêm bất kỳ công việc nào từ phía của chúng.

Java Copy Constructor

        Phương thức Java Copy Constructor lấy đối tượng của cùng một lớp làm đối số và tạo một bản sao của nó. Đôi khi chúng ta cần một bản sao của một đối tượng khác để thực hiện một số xử lý. Chúng ta có thể làm điều này bằng những cách sau:
👉  thực hiện cloning
👉  cung cấp một phương thức tiện ích cho deep copy của đối tượng.
👉  Có một copy constructor

Bây giờ chúng ta hãy xem cách viết một copy constructor. Giả sử chúng ta có một lớp Fruits như dưới đây. 

public class Fruits {

   
private List<String> fruitsList;
   
public List<String> getFruitsList() {
       
return fruitsList;
    }
   
public void setFruitsList(List<String> fruitsList) {
       
this.fruitsList = fruitsList;
    }
   
public Fruits(List<String> fl) {
       
this.fruitsList = fl;
    }
   
public Fruits(Fruits fr) {
        List<
String> fl = new ArrayList<>();
       
for (String f : fr.getFruitsList()) {
           
fl.add(f);
        }
       
this.fruitsList = fl
;
    }
}



    Lưu ý rằng Fruits(Fruits fr) đang thực hiện một deep copy để trả lại bản sao của đối tượng. Chúng ta hãy xem xét một chương trình thử nghiệm để hiểu tại sao tốt hơn nên có copy constructor để sao chép một đối tượng.

public class ConstructorTest {

   
public static void main(String[] args) {
        List<
String> fl = new ArrayList<>();
       
fl.add("Mango");
       
fl.add("Orange");

        Fruits
fr = new Fruits(fl);

       
System.out.println(fr.getFruitsList());

        Fruits fr = fr;
        fr.getFruitsList().add(
"Apple");

       
System.out.println(fr.getFruitsList());

        fr =
new Fruits(fr);
        fr.getFruitsList().add(
"Banana");
       
System.out.println(fr.getFruitsList());
       
System.out
.println(fr.getFruitsList());
    }
}



Kết quả của chương trình trên là: 
[Mango, Orange] [Mango, Orange, Apple] [Mango, Orange, Apple] [Mango, Orange, Apple, Banana]


Lưu ý rằng khi sử dụng copy constructor, cả đối tượng gốc và bản sao của nó đều không liên quan đến nhau và bất kỳ sửa đổi nào ở một trong số chúng sẽ không phản ánh thành đối tượng khác.

Đó là tất cả đối với constructor trong java.



Bài viết được dịch lại từ journaldev.com. 
Cảm ơn bạn đã xem bài viết! Nếu có bất cứ lỗi sai nào trong bài bạn có thể góp ý cho chúng tôi bằng cách bình luận bên dưới.

Đăng nhận xét

0 Nhận xét