Câu hỏi về override trong Java

Hôm bữa e có đi phỏng vấn về Java, anh kia hỏi e thế nào là Override, e trả lời Override là phương thức đã xuất hiện ở lớp Cha được dùng ở lớp con nhưng đã bị sửa đổi. Anh hỏi tiếp: Vậy sao em không viết luôn phương thức đó trong lớp con luôn, sao lại phải viết trong lớp cha rồi lại phải đi viết lại tiếp trong lớp con làm gì?
E chưa tìm được câu trả lời mong mn giúp ạ. Thanks

Trả lời:
Vì em lười, nên em tận dụng triệt để tái sử dụng code. Em chỉ cần khai báo method toTinh() nhận param là thuộc kiểu interface NuGioi. Sau đó em có thể truyền nhiều bạn gái vào, cùng thừa kế NuGioi, như: HàngXóm, BạnCơQuan, CôGiáo,… vào method toTinh()

Do em khá là nhạt và lười, nên chỉ biết 1 cách tỏ tình thôi. :heart_eyes:

5 Likes

Hi Lam Nguyen Thanh.
Theo mình nó thể hiện tính đa hình.

3 Likes

mình biết là tính đa hình r nhưng hỏi câu kia hơi khó trả lời

Thì trả lời vẫn là đa hình thôi :v

2 Likes

khai báo trong lớp base để lớp extends sử dụng là tính kế thừa
lớp extends override method thì nó là tính đa hình

3 Likes

Câu hỏi của a đó không phải là muốn hỏi xem em trả lời gì mà là trả lời như thế nào. Đa hình thì em biết, nhiều bạn cũng biết.
Biết là 1 chuyện còn vận dụng lại là 1 chuyện khác, cho nên với câu hỏi đó không có câu trả lời trọn vẹn, tùy vào tư duy lập trình của em thôi. Vd như muốn tận dụng xử lý đã có ở class cha đã có chỉ cần tinh chinh nhỏ cho class con, v.v

1 Like

Câu chuyện kể rằng 1 ngày họ, Vua sư tử kêu gọi tất cả loài thù ra ăn mừng vì ngày kỉ niệm vua đăng ngôi
Sư tử kêu rằng: “Tất cả loài thú hãy cùng kêu lên 1 phát cho có không khí”. Tuy nhiên chỉ có loài thỏ biết kêu, còn loài rắn, loài sói câm nín. Hỏi ra mới biết tinh linh thần rừng chỉ định nghĩa method Speak cho class Rabbit, các class như Snake, Wolf chưa định nghĩa. Nếu chỉ có loài thỏ kêu được thì bất công quá, nên thần rừng tạo 1 method Speak ở ngoài class Animal, tất cả các loài còn lại chỉ cần override lại là biết kêu hết, đã vậy mỗi loại động vật còn kêu khác nhau. Sau đó, vua sư tử vui mừng vì các loài thú có thể chung vui hát hò với nhau, họ sống mãi trong khung rừng xanh đến hết cuộc đời.
:penguin: :penguin: :penguin: :penguin: :penguin: :penguin:

8 Likes

theo mình thì do đang sử dụng đặc tính thừa kế nên cấu trúc của 1 class lúc này nó giống như 1 viên kẹo bọc nhiều lớp , và cái lõi của viên kẹo chính là 1 class cha (trong java là class object , trong các ngôn ngữ như ruby ,php cũng tương tự) , lúc này mỗi class con extend class cha, chính là tạo ra 1 loại kẹo mới từ việc bọc thêm 1 lớp đường lên trên cái lõi kẹo là class cha , từ sự liên tưởng đó thì cũng thấy đc lúc này lớp con có 2 sự lựa chọn hoặc là override lại method của lớp cha hoặc là dùng trực tiếp method của lớp cha , dùng trực tiếp >> ko có gì để nói, override thực chất là viết 1 hàm có phần chữ ký hàm tương tự như class cha nhưng phần thân lại thay đổi , vậy sao anh ko viết luôn trong class con đi kiểu gì chả viết lại , đúng nếu method đó chỉ xuất hiện ở 1 class con thì chả rãnh mà viết 2 lần , nhưng bản chất thằng class cha là sự tổng quát hóa của các thằng con nên khi tui viết 1 method ở thằng cha là tui biết chắc các thằng khác cùng loại với thằng cha kiểu gì cũng có method đó chỉ có thể là cách xử lý nó khác của thằng cha , nếu cách xử lý nó khác nó có thể override còn không thì cứ dùng đồ thừa kế từ thằng cha . Ồ vậy thì có ích gì nhỉ giờ tin tui ko dùng override tui vẫn gọi đúng method ko ? tất nhiên là đc rồi cứ dùng 1 đống if else , if đối tượng là con thì dùng method con , if đối tượng là cha thì dùng method cha quá là điều bình thường nun , nhưng nếu đang làm ngon lành code compile hết rồi sếp bảo thêm đối tượng này vào cho anh đối tượng này sẽ có hành động là abc , lật đật chạy đi thêm 1 cái if else vào rồi lại phải test hết đống code cũ rồi phải mò lại xem thằng nào chổ nào mình dùng if else để kiểm tra kiểu dữ liệu , trong khi nếu tui dùng override thì mấy cái việc if else đó để máy làm nhé tui chỉ cần truyền vào đối tượng còn chọn cho đúng method là chuyện của máy, nhà bao việc … cho nên nếu được viết 1 chương trình trong mơ là xuất ra màn hình chuỗi hellloword thì thôi đừng oop gì cho mệt , nhưng đời ko là mơ lòng dạ khách hàng thay đổi thất thường lưỡi ko xương nhiều đường lắt léo hôm qua thì còn nói thế này mai lại bảo thế khác dùng toàn if else để chết à , cho nên đẻ ra oop để chuyên trị mấy cái chương trình mà hay có sự thay đổi nhiều , nhưng đó là trước khi mình biết đến ngôn ngữ thông dịch như php,ruby,python,js chứ nếu đã biết các ngôn ngữ đó thì thực sự oop trong nó khác với oop trong java,c#,c++ lắm , linh hoạt hơn mềm dẻo hơn …:smiley:

3 Likes

Hi undersun.
Theo mình hiểu thì bọc ra ngoài giống như mặc nhiều áo. Có thay thế cái trong đâu nhỉ ?

Tại vì phương thức đó có thể thực hiện trên lớp cha. Khi lớp con kế thừa lại thì sẽ có 2 khả năng xảy ra, 1 là thực hiện lại hành động đã đc định nghĩa sẵn ở lớp cha; 2 là thực hiện 1 hành động hoàn toàn khác nhưng lại có tên giống vs hành động cha.

@LamNT : Về tổng quát, cách hiểu của bạn là đúng rồi. Tuy nhiên vì bạn chưa có kinh nghiệm thực tế nhiều nên không trả lời được câu hỏi trên. Đừng lo, khi bạn đã làm việc một thời gian thì câu trả lời sẽ rõ hơn nhiều.

Cách đặt vấn đề của người phỏng vấn của bạn đã bỏ qua một chi tiết quan trọng: đó là ngữ cảnh (context). Dĩ nhiên đó là mẹo của người phỏng vấn để biết rõ bạn có kinh nghiệm lập trình đối tượng thật sự hay không. Câu trả lời cho câu hỏi này phải luôn luôn có kèm theo context, có nghĩa là trong điều kiện nào thì chúng ta cần phải sử dụng overload.

Để giản lược hóa câu trả lời, tôi có thể đưa ra hai ví dụ đơn giản mà chúng ta cần dùng overload:

  1. Giả sử bạn có một chương trình sử dụng đến các đối tượng thuộc lớp Animal và các lớp con của nó (ví dụ như Dog, Cat, Cow, …) - tôi xin phép được lấy lại câu chuyện của bạn @EternalRerosu. Khi bạn viết chương trình, bạn không biết trước sẽ có chính xác bao nhiêu con vật sẽ được dùng trong chương trình của bạn. Giả sử bạn chỉ có 3 con vật lúc đầu như trên, và mỗi con vật phát ra tiếng kêu khác nhau. Nếu không dùng override, khi cần phát ra tiếng kêu của con vật, đại khái bạn sẽ phải tạo ra một hàm như thế này trong chương trình chính của bạn:

      function animalSpeak (Animal animal) {
          if (animal is Dog) { Dog.woof() }
          if (animal is Cat) { Cat.meow() }
          if (animal is Cow) { Cow.moo() }
      }
    

Dĩ nhiên là hàm này chạy được. Nhưng điều gì sẽ xảy ra nếu trong tương lai bạn cần phải thêm các con vật khác vào chương trình? Nếu làm theo cách ở trên, mỗi lần bạn thêm một class mới kế thừa từ class Animal, bạn sẽ phải cập nhật hàm animalSpeak ở trên và thêm một lệnh if nữa. ĐIều này có thể tạm chấp nhận được nếu như chương trình nhỏ và bạn không có kinh nghiệm lập trình, nhưng nếu chương trình của chúng ta trở nên phức tạp và bạn là người đã lập trình lâu năm thì chúng ta có cách giải quyết tốt hơn nhiều với Override bằng cách như sau:

class Animal {
   void speak()
}

class Dog :  Animal {
   void speak() { sayWoof() }
}

class Cat : Animal {
  void speak() { sayMeow() }
}

class Cow: Animal {
  void speak() { sayMoo() }
}

... 
function animalSpeak (Animal animal) {
    animal.speak()
}

Như bạn đã thấy, ở đây override giúp chúng ta rất nhiều trong hàm animalSpeak(), chúng ta sẽ không phải sửa đổi nó ngay cả khi chúng ta thêm một con vật mới vào trong danh sách các con vật của chúng ta và nó vẫn sẽ hoạt động giống nhau. Điều này đặc biệt hữu ích khi chúng ta muốn tổng quát hóa để chương trình của chúng ta có thể hoạt động ngay cả khi chúng ta không biết số lượng các object có thể được sử dụng trong thời gian thực thi (runtime) hoặc chúng ta không được phép thay đổi mã trong chương trình chính trong tương lai.

  1. Một ví dụ nữa là khi bạn có một số lớn các class có cùng một số đặc tính cơ bản nhưng chỉ có một hoặc vài khác biệt nhỏ. Khi đó, chúng ta việc override các method trong các subclass giúp chúng ta có thể thay đổi các đối tượng của chúng ta phù hợp với những khác biệt này nhưng vẫn sử dụng lại được phần lớn mã trong baseclass. Một ví dụ thường gặp của trường hợp này là khi bạn có một method trong subclass cần làm tất cả các công việc của method nó override và thêm một số tác vụ khác như trong ví dụ sau:

     class SuperClass {
          methodOne() { this.foo = 99 }
     }
    
     class SubClass1: SuperClass {
        methodOne() {
          super() // gán foo = 99
          this.foo++ // và cộng thêm 1
        }
     }
    
     class SubClass2: SuperClass {
        methodOne() {
          super() // gán foo = 99
          this.foo-- // và trừ đi 1
        }
     }
    

Hy vọng là các ví dụ này phần nào giải đáp được thắc mắc của bạn.

7 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?