[Tự học lập trình Java] Lớp trong lập trình.

 Với những gì bạn đã biết về cú pháp lập trình cơ bản của ngôn ngữ lập trình Java, bạn có thể học viết các lớp của bạn. Trong phần này, bạn sẽ tìm thấy các thông tin về định nghĩa các lớp của bạn, bao bồm khai báo các thành viên: các biến, các phương thức và các phương thức khởi dựng.

Bạn sẽ học sử dụng các lớp để tạo ra các đối tượng và làm thế nào để sử dụng các đối tượng bạn tạo ra.

Cũng trong chương này bạn cũng được biết các lớp nằm trong lớp khác, và kiểu dữ liệu liệt kê.

Ngôn ngữ lập trình Java - tinhoccoban.net


Lớp (Class)

Khái niệm

Trong phần này trình bày với bạn cấu trúc của một lớp, và làm thế nào để định nghĩa các trường (fields), các phương thức (methods) và các hàm khởi dựng (contructors).

Trong phần giới thiệu về khái niệm lập trình hướng đối tượng ở chương trước có sử dụng lớp bicycle làm ví dụ, với chiếc xe đua, xe đạp leo núi, xe đạp song song với tư cách là lớp con. Ở đây là ví dụ mã nguồn về khả năng thực thi một lớp Bicycle, để cho bạn một cái nhìn tổng quan về khai báo lớp. Tiếp theo phần này sẽ quay về giải thích khai báo lớp từng bước một. Hiện tại, bạn đừng quan tâm đến chi tiết của chúng.

public class Bicycle {
        
    // the Bicycle class has
    // three fields
    public int cadence;
    public int gear;
    public int speed;
        
    // the Bicycle class has
    // one constructor
    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }
        
    // the Bicycle class has
    // four methods
    public void setCadence(int newValue) {
        cadence = newValue;
    }
        
    public void setGear(int newValue) {
        gear = newValue;
    }
        
    public void applyBrake(int decrement) {
        speed -= decrement;
    }
        
    public void speedUp(int increment) {
        speed += increment;
    }
        
}

Một khai báo lớp cho lớp MountainBike là lớp con của lớp Bicycle, có thể thấy như sau:

public class MountainBike extends Bicycle {
        
    // the MountainBike subclass has
    // one field
    public int seatHeight;
 
    // the MountainBike subclass has
    // one constructor
    public MountainBike(int startHeight, int startCadence,
                        int startSpeed, int startGear) {
        super(startCadence, startSpeed, startGear);
        seatHeight = startHeight;
    }   
        
    // the MountainBike subclass has
    // one method
    public void setHeight(int newValue) {
        seatHeight = newValue;
    }   
}

MountainBike kế thừa tất cả các thuộc tính và các phương thức của Bicycle và thêm trường seatHeight và một phương thức thiết lập nó (xe đạp leo núi có chỗ ngooif có thể di chuyển lên và xuống phụ thuộc vào địa hình).

Khai báo lớp (Declaring Classes)

Cú pháp khai báo lớp:

class MyClass {
    // field, constructor, and 
    // method declarations
}

Trong cú pháp khai báo, thân lớp (vùng nằm giữa 2 dấu ngoặc nhọn) bao gồm tất cả mã nguồn cung cấp cho vòng đời (life cycle) của các đối tượng được tạo ra từ lớp này: các phương thức khởi dựng (constructor) để khời gán cho các đối tượng mới, khai báo các trường (field) cung cấp trạng thái cho lớp và các đối tượng (objects) và các phương thức thực thi hành vi của lớp và các đối tượng.

Cách khai báo trước là cách khai báo lớp một cách tối thiểu. Nó chỉ bao gồm thành phần của một lớp được khai báo được yêu cầu. Bạn có thể cung cấp nhiều thông tin hơn về lớp, như tên của lớp cha (superclass), hay khai là lớp thực thi bất kỳ một interface nào đó ở vị trí bắt đầu khai báo lớp, ví dụ như sau:

class MyClass extends MySuperClass implements YourInterface {
    // field, constructor, and
    // method declarations
}

Nghĩa là  lớp MyClass là lớp con của lớp MysuperClass và thực thi interface YourInterface.

Bạn costheer thêm phạm vi tác động như public hoặc private ở đầu, do vậy bạn có thể thấy khi mở dòng đầu tiên của khai báo lớp đã trở lên khá phức tạp. Các phạm vi như public và private quyết định các lớp khác có thể truy cập vào MyClass hay không, được bàn ở sau trong mục này. Bài học về interface và kế thừa sẽ giải thích làm thế nào và tại sao bạn sử dụng từ khóa extendsimplements trong khai báo một lớp. Bây giờ bạn không cần quan tâm lo lắng về các yếu tố này.

Nói chung, khai báo lớp có thể bao gồm các thành phần thứ tự như sau:

·        Các từ bổ nghĩa như public, private và một số phần khác mà bạn sẽ gặp phải sau này (Tuy nhiên, ghi nhớ rằng từ private có thể áp dụng trong lớp lồng.)

·        Tên lớp với ký tự bắt đầu tuân theo quy ước định danh.

·        Tên lớp cha (superclass) bất kỳ nào đều phải được theo trước đó là từ khóa extend cho một cha.

·        Danh sách các interface được thực thi bởi lớp phải cách nhau bởi dấu phẩy và phí trước có từ khóa implements. Một lớp có thể thực thi một hoặc nhiều interface.

·        Thân lớp được bao bọc bởi dấu đóng mở ngoặc nhọn {}.

Khai báo các thành viên thuộc tính (Declaring Member Variables)

Cú pháp khai báo:

Có một vài loại biến sau:

·        Các biến thành viên của một lớp được gọi là các trường (thuộc tính).

·        Các biến của một phương thức hoặc một khối mã nguồn được gọi là các biến cục bộ.

·        Các biến trong khai báo phương thức được gọi là các tham số.

Trong lớp Bicycle sử dụng các dòng code định nghĩa các trường:

public int cadence;
public int gear;
public int speed;

 Khai báo trường (thuộc tính) bao gồm ba thành phần, thứ tự như sau:

1.      Không hoặc có bổ ngữ phạm vi như public hoặc private.

2.      Kiểu của thuộc tính.

3.      Tên thuộc tính.

Các trường trong lớp Bicycle được đặt tên cadencegearspeed  tất cả đều có kiểu dữ liệu số (int). Từ khóa public xác định các thuộc tính là các thành viên công khai, được truy cập từ bất kỳ đối tượng nào có thể truy cập vào lớp.

Phạm vi truy cập (Access Modifiers)

Đầu tiên (ngoài cùng bên trái) cho phép bạn kiểm soát được việc truy cập vào một thành viên của lớp. Trong ví dụ này, chỉ có publicprivate.  Các bổ ngữ quy định truy cập chúng ta sẽ bàn sau.

·        Bổ ngữ public - thuộc tính được truy cập ở tất cả các lớp.

·        Bổ ngữ private – thuộc tính chỉ được truy cập bên trong lớp sở hữu thuộc tính đó.

Dựa trên tinh thần đóng gói thì phổ biến tạo ra các thuộc tính private. Điều này nghĩa là  chúng chỉ có thể được truy cập trực tiếp từ lớp Bicycle. Tuy nhiên, chúng ta vẫn cần truy cập các giá trị đó. Ở đây có thể truy cập gián tiếp bằng cách thêm vào phương thức công khai vẫn lấy được các giá trị thuộc tính cho chúng ta.

public class Bicycle {
        
    private int cadence;
    private int gear;
    private int speed;
        
    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }
        
    public int getCadence() {
        return cadence;
    }
        
    public void setCadence(int newValue) {
        cadence = newValue;
    }
        
    public int getGear() {
        return gear;
    }
        
    public void setGear(int newValue) {
        gear = newValue;
    }
        
    public int getSpeed() {
        return speed;
    }
        
    public void applyBrake(int decrement) {
        speed -= decrement;
    }
        
    public void speedUp(int increment) {
        speed += increment;
    }
}

Kiểu dữ liệu

Tất cả các biến phải có một kiểu dữ liệu nào đó. Bạn cần sử dụng các kiểu dữ liệu nguyên thủy như int, float, boolean, vân vân. Hoặc bạn có thể sử dụng các kiểu dữ liệu tham chiếu, như kiểu chuỗi (strings), kiểu mảng (array) hoặc các đối tượng.

Các tên thuộc tính.

Tất cả các biến, chúng được gọi là các thuộc tính, biến cục bộ, hoặc các tham số, đều theo quy tắc định danh trong phần cú pháp lập trình cơ bản đã giới thiệu.

Trong phần này, tương tự với quy tắc trên cho sử dụng cho tên phương thức và tên lớp, ngoại trừ:

·        ký tự đầu của lớp nên viết hoa và

·        từ đầu tiên (hoặc duy nhất) của phương thức nên là một động từ.

Định nghia các phương thức (Defining Methods)

Định nghĩa các phương thức.

Ở đây có một ví dụ khai báo phương thức điển hình:

public double calculateAnswer(double wingSpan, int numberOfEngines,
                              double length, double grossTons) {
    //do the calculation here
}

Chỉ yêu cầu các thành phần khai báo của phương thức là: Kiểu trả về, tên phương thức, cặp ngoặc đơn, và thân phương thức nằm giữa cặp dấu đóng mở ngoặc nhọn {}.

Khái quát hơn, khai báo phương thức có sáu thành phần theo thứ tự sau:

1.      Bổ ngữ - như public, private và các bổ ngữ khác, bạn sẽ học sau.

2.      Kiểu dữ liệu trả về - kiểu dữ liệu của giá trị trả về bởi phương thức hoặc void nếu là phương thức không trả về giá trị.

3.      Tên phương thức – áp dụng theo quy tắc đặt tên nhưng có một chút khác.

4.      Danh sách tham số trong dấu ngoặc tròn, các tham số đầu vào cách nhau bởi dấu phẩy, trước mỗi tham số là kiểu dữ liệu của phương thức, kết thúc danh sách này là dấu đóng ngoặc tròn. Nếu không có tham số thì phải có dấu đóng mở ngoặc tròn và bên trong bỏ trống.

5.      Một danh sách ngoại lệ - sẽ được bàn sau.

6.      Thân phương thức được bao quanh bởi một cặp mở / đóng ngoặc nhọn, ở đó bao gồm khai báo biến cục bộ, và toàn bộ mã nguồn của phương thức.

Các bổ ngữ, các kiểu dữ liệu trả về và các tham số sẽ được bàn sau. Ngoại lệ cũng sẽ được bàn sau.

Chú ý: Hai thành phần khai báo của một phương thức được gọi là chữ ký phương thức – bao gồm tên phương thức và các kiểu tham số. Ví dụ chữ ký phương thức được khai báo như dưới đây:

calculateAnswer(double, int, double, double)

Tên của phương thức.

Mặc dù tên phương thức có thể là bất kỳ định danh hợp pháp nào, quy tắc mã nguồn hạn chế tên phương thức. Bởi quy ước, tên phương thức nên là một động từ viết thường hoặc gồm tổ hợp từ mà từ đầu tiên của tên phải là động từ được viết thường toàn bộ chữ cái. Theo sau từ đó là một tính từ, danh từ vân vân. Trong các tên tổ hợp từ, chữ cái đầu tiên của các từ thứ 2 trở đi viết hoa. Ví dụ:

run
runFast
getBackground
getFinalData
compareTo
setX
isEmpty

Một cách điển hình, một phương thức có duy nhất một tên trong một lớp (class). Tuy nhiên, một phương thức có thể có tên giống với tên của phương thức khác như các phương thức nạp chồng (method overloading).

Các phương thức nạp chồng.

Ngôn ngữ lập trình Java hỗ trợ các phương thức nạp chồng (method overloading), và Java có thể phân biệt được giữa các phương thức khác nhau thông qua chữ ký phương thức (method signatures). Điều này nghĩa là các phương thức trong một lớp có thể có cùng tên nếu các danh sách tham số khác nhau (là một vài “chứng nhận” sẽ được bàn trong “Giao diện lập trình và kế thừa”).

Có thể hình dung như sau, bạn có một lớp có thể sử dụng nhiều thư pháp để vẽ nhiều kiểu dữ liệu (chuỗi, số, và nhiều kiểu khác) và bao gồm một phương thức cho mỗi kiều dữ liệu. Nó sẽ rất cồng kềnh cho việc sử dụng các tên mới cho mỗi phương thức ví dụ drawStringdrawIntegerdrawFloat và nhiều phương thức khác. Trong ngôn ngữ lập trình Java, bạn có thể sử dụng tên giống nhau cho tất cả các phương thức vẽ nhưng khác nhau ở tham số truyền vào cho mỗi phương thức. Như vậy, lớp vẽ dữ liệu có thể khai báo bốn phương thức draw, mỗi phương thức phân biệt bằng danh sách tham số.

public class DataArtist {
    ...
    public void draw(String s) {
        ...
    }
    public void draw(int i) {
        ...
    }
    public void draw(double f) {
        ...
    }
    public void draw(int i, double f) {
        ...
    }
}

Các phương thức nạp chồng khác nhau bởi số tham số, kiểu tham số truyền vào trong phương thức. Trong ví dụ này draw(String s)draw(int i) là các phương thức riêng biệt và duy nhất bởi vì chúng yêu cầu kiểu dữ liệu tham số khác nhau.

Bạn không thể khai báo nhiều hơn một phương thức cùng tên và cùng số tham số, cùng kiểu tham số bởi trình biên dịch không thể phân biệt được chúng riêng biệt.

Trình biên dịch không coi kiểu dữ liệu trả về khi xét các phương thức khác nhau, do vậy bạn không thể khai báo hai phương thức cùng tên, cùng chữ ký và chúng chỉ khác nhau kiểu trả về.

Ghi nhớ: Các phương thức nạp chồng có thể làm cho bạn tiết kiệm việc viết mã nguồn hơn.

Cung cấp các phương thức khởi dựng (Contructors) cho lớp.

Một lớp bao gồm các phương thức khởi dựng (contructor) được gọi để tạo ra các đối tượng từ các lớp sử dụng chúng (blueprint). Khai báo các phương thức khởi dựng (Contructor) giống như khai báo các phương thức khác ngoại trừ tên phương thức chính là tên lớp và không có kiểu dữ liệu trả về. Ví dụ trong lớp Bicycle có phương thức khởi dựng:

public Bicycle(int startCadence, int startSpeed, int startGear) {
    gear = startGear;
    cadence = startCadence;
    speed = startSpeed;
}

Tạo ra một đối tượng thuộc lớp Bicycle có tên là myBike, gọi một phương thức khởi dựng bởi toán tử new:

Bicycle myBike = new Bicycle(30, 0, 8);

new Bicycle(30, 0, 8) tạo một không gian bộ nhớ cho đối tượng và khởi gán các giá trị ban đầu cho các thuộc tính.

public Bicycle() {
    gear = 1;
    cadence = 10;
    speed = 0;
}
Bicycle yourBike = new Bicycle();

Gọi phương thức khởi dựng không tham số tạo ra một đối tượng Bicycle có tên là yourBike.

Tất cả các phương thức khởi dựng đều được khai báo trong lớp Bicycle bởi vì chúng khác nhau về các danh sách tham số. Giống như phương thức, các phương thức khởi dựng trong nền tảng Java phân biệt nhau bởi các yếu tố cơ bản như số lượng tham số trong danh sách tham số  và kiểu của chúng. Bạn không thể viết hai phương thức khởi dựng (contructors) có số và kiểu tham số giống nhau, bởi vì nền tảng này không thể hiểu các thành phần này. Và sẽ bị lỗi biên dịch.

Bạn không phải cung cấp bất kỳ phương thức khởi dựng nào cho lớp của bạn, nhưng phải cẩn thận khi dùng lớp này. Trình biên dịch tự động cung cấp phương thức khởi dựng mặc định không tham số cho bất kỳ lớp nào không khai báo phương thức khởi dựng. Phương thức khởi dựng mặc định này sẽ được gọi là phương thức khởi dựng không tham số cho lớp cha (superclass) của nó. Trong tình huống mà trình biên dịch không tìm thấy phương thức khởi dựng không tham số của lớp cha thì bạn phải xác nhận. Nếu lớp của bạn không có lớp cha rõ ràng nào thì một nó sử lớp cha của lớp Object có hàm khởi dựng không tham số.

Bạn có thể sử dụng một phương thức khởi dựng mặc định của lớp cha cho lớp của bạn. Lớp MountainBike bắt đầu học trong phần này đã sử dụng nó. Sẽ bàn sâu hơn ở phần giao diện lập trình và kế thừa sau này.

Bạn có thể sử dụng bổ ngữ truy cập trong khai báo phương thức khởi dựng để kiểm soát các lớp khác có thể gọi phương thức khởi dựng.

Ghi nhớ: Nếu lớp khác không gọi được một phương thức khởi dựng trong lớp MyClass, nó không thể tạo trực tiếp các đối tượng MyClass.

Truyền giá trị tham số cho phương thức hoặc hàm khởi dựng.

Khái niệm về truyền giá trị.

Khai báo một phương thức hoặc hàm khởi tạo/ khởi dựng (contructor) khai báo số lượng và kiểu dữ liệu của các đối số cho phương thức hoặc hàm khởi dựng. Ví dụ, khai báo một phương thức tính toán tiền phải trả hàng tháng khi vay tiền mua nhà, dựa trên số tiền vay và lãi suất, thời hạn vay (một giai đoạn nào đó), và giá trị vay trong tương lai.

public double computePayment(
                  double loanAmt,
                  double rate,
                  double futureValue,
                  int numPeriods) {
    double interest = rate / 100.0;
    double partial1 = Math.pow((1 + interest),
                      - numPeriods);
    double denominator = (1 - partial1) / interest;
    double answer = (-loanAmt / denominator)
                    - ((futureValue * partial1) / denominator);
    return answer;
}

Ghi nhớ: Các tham số (Parameters) tham chiếu là một danh sách biến trong khai báo phương thức. Các đối số (Arguments) là các giá trị thật được truyền vào khi gọi phương thức. Khi bạn gọi một phương thức, các đối số phải được khớp với các tham số khai báo cả về kiểu và thứ tự.Phương thức này có bốn tham số: số tiền vay (loanAmt), lãi suất (rate), giá trị tương lai (futureValue) và giai đoạn vay (numPeriods). Ba tham số đầu tiên có kiểu double, tham số thứ bốn có kiểu số int. Các tham số được sử dụng trong thân phương thức và sẽ chạy với các giá trị truyền vào cho các tham số.

Các kiểu tham số.

Bạn có thể sử dụng bất kỳ kiểu dữ liệu nào cho một tham số của một phương thức hay hàm khởi tạo (phương thức khởi dựng). Bao gồm các kiểu dữ liệu nguyên thủy, như double, float, int giống như bạn nhìn thấy trong phương thức computePayment trong ví dụ trên, và các kiểu dữ liệu tham chiếu giống như các đối tượng và các mảng.

Ở đây có một ví dụ về một phương thức chấp nhận một mảng như một đối số. Trong ví dụ này, phương thức tạo đối tượng mới Polygon khởi gán một mảng đối tượng Point (Point là một lớp có hai tọa độ đại diện là x, y).

public Polygon polygonFrom(Point[] corners) {
    // method body goes here
}

Số lượng đối số tùy ý - .Ghi nhớ: Nếu bạn muốn truyền một phương thức vào một phương thức thì sử dụng biểu thức lambda hoặc tham chiếu phương thức sẽ được bàn ở phần lớp lồng trong chương này.

Bạn có thể xây dựng phương thức theo một cách được gọi là kỳ đà (varargs) để truyền vào bất kỳ số nào cho giá trị của một phương thức. Bạn sử dụng kỳ đà khi không biết bao nhiêu kiểu của đối dố sẽ truyền vào cho phương thức. Một đường tắt được tạo ra cho mảng thực (phương thức trước đó có thể sử dụng kỳ đà hơn là dùng mảng).

Để sử dụng kỳ đà, bạn sử dụng các kiểu của tham số cuối bằng dấu chấm lửng (ba chấm, …), sau đó là dấu cách, và tên tham số. Phương thức có thể được gọi với bất kỳ số lượng tham số nào bao gồm cả không cần tham số.

public Polygon polygonFrom(Point... corners) {
    int numberOfSides = corners.length;
    double squareOfSide1, lengthOfSide1;
    squareOfSide1 = (corners[1].x - corners[0].x)
                     * (corners[1].x - corners[0].x) 
                     + (corners[1].y - corners[0].y)
                     * (corners[1].y - corners[0].y);
    lengthOfSide1 = Math.sqrt(squareOfSide1);
 
    // more method body code follows that creates and returns a 
    // polygon connecting the Points
}

Bạn thường sẽ sử dụng phương pháp kỳ đà với các phương thức in, ví dụ phương thức printf sau:Bạn có thể thấy rằng, bên trong phương thức, corners được coi như là một mảng. Phương thức này có thể được gọi với một mảng hoặc một thứ tự các đối số. Mã nguồn trong thân phương thức sẽ coi tham số như là một mảng trong trường hợp này.

public PrintStream printf(String format, Object... args)

Cho phép bạn in bao nhiêu đối tượng cũng được. Nó có thể được gọi như:

System.out.printf("%s: %d, %s%n", name, idnum, address);

Hoặc được gọi như:

System.out.printf("%s: %d, %s, %s, %s%n", name, idnum, address, phone, email);

Hoặc gọi phương thức với không đối số.

Các tên tham số.

Khi bạn khai báo tham số cho phương thức hoặc hàm tạo, bạn cung cấp một cái tên cho tham số. Tên này được sử dụng trong thân phương thức và tham chiếu để truyền đối số.

Tên của tham số phải là duy nhất trong một phạm vi. Nó không thể giống với tên của một tham số khác ở cùng một phương thức hoặc hàm tạo, và không thể cùng tên với một biến cục bộ trong phương thức hoặc hàm tạo.

Một tham số có thể giống một thuộc tính của lớp. Nếu trong trường hợp, tham số được gọi là ánh xạ (shadows) của thuộc tính. Các ánh xạ của trường có thể được tạo trong mã nguồn của bạn sẽ khó đọc và được quy ước sử dụng chỉ với các hàm khởi tạo và các phương thức thiết lập cho thuộc tính. Ví dụ, trong lớp Circle có phương thức thiết lập setOrigin.

public class Circle {
    private int x, y, radius;
    public void setOrigin(int x, int y) {
        ...
    }
}

Truyền các đối số có kiểu dữ liệu nguyên thủy.Lớp Circle có ba thuộc tính: x, y và radius. Phương thức setOrigin có hai tham số, mỗi tham số có tên giống với một trong các thuộc tính. Mỗi tham số là ánh xạ (shadows) của thuộc tính tương ứng cùng tên. Cũng sử dụng tên x hoặc y trong thân phương thức tham số tham chiếu, không phải thuộc tính. Truy cập vào các thuộc tính, bạn phải sử dụng một tên chuẩn. Sẽ bàn sau trong phần này.

Các đối số nguyên thủy, như một số kiểu int hoặc double, được truyền qua giá trị của phương thức. Điều này có nghĩa là bất kỳ thay đổi nào với các giá trị cho các tham số chỉ  tồn tại trong phạm vi phương thức. Khi trả phương thức trả về, các tham số sẽ biến mất và bất kỳ thay đổi nào của chúng cũng biến mất. Ví dụ:

public class PassPrimitiveByValue {
 
    public static void main(String[] args) {
           
        int x = 3;
           
        // invoke passMethod() with 
        // x as argument
        passMethod(x);
           
        // print x to see if its 
        // value has changed
        System.out.println("After invoking passMethod, x = " + x);
           
    }
        
    // change parameter in passMethod()
    public static void passMethod(int p) {
        p = 10;
    }
}

Khi chạy chương trình này, kết quả trả về:

After invoking passMethod, x = 3

Các tham số kiểu dữ liệu tham chiếu, giống như các đối tượng, là cũng truyền vào các phương thức bằng giá trị. Điều  này có nghĩa là khi trả về các giá trị, các các tham chiếu truyền vào vẫn tham chiếu đến các đối tượng trước đó. Tuy nhiên, các giá trị của các thuộc tính đối tượng có thể được thay đổi trong phương thức, nếu chúng truy cập ở mức độ phù hợp.Truyền các đối số kiểu dữ liệu tham chiếu (Passing Reference Data Type Arguments).

Trong ví dụ, xem xét phương thức bất kỳ trong lớp Circle chuyển đổi các đối tượng Circle:

public void moveCircle(Circle circle, int deltaX, int deltaY) {
    // code to move origin of circle to x+deltaX, y+deltaY
    circle.setX(circle.getX() + deltaX);
    circle.setY(circle.getY() + deltaY);
        
    // code to assign a new reference to circle
    circle = new Circle(0, 0);
}

Hãy gọi phương thức với các đối số như sau:

moveCircle(myCircle, 23, 56)

Bên trong phương thức, cicrle ban đầu tham chiếu đến myCircle. Phương thức thay đổi tọa độ x và tọa độ y của circle mà nó tham chiếu đến (đó là myCircle) với 23 và 56 tương ứng. Sự thay đổi sẽ vẫn tồn tại khi hàm trả về giá trị. Sau đó circle được gán một tham chiếu đối tượng Circle mới với x=y=0. Sự gán lại này không lâu dài, bởi vì tham chiếu đã truyền vào bằng giá trị không thể thay đổi. Bên trong phương thức, thuộc tính điểm của đối tượng circle đã thay đổi, tuy nhiên, khi phương thức trả về giá trị myCircle vẫn tham chiếu đến đối tượng Circle đó như trước khi phương thức được gọi.


Mới hơn Cũ hơn

Biểu mẫu liên hệ