Мурастоо (Наследования)
Объектке багытталган программалоонун негизги аспектилеринин бири – мурастоо. Мурастоону колдонуу менен, сиз жаңы функцияларды кошуу же эскисин өзгөртүү менен учурдагы класстардын функцияларын кеңейте аласыз. Мисалы, жеке адамды сүрөттөгөн төмөнкү Person классы бар:
class Person {
String name;
public String getName(){ return name; }
public Person(String name){
this.name=name;
}
public void display(){
System.out.println("Name: " + name);
}
}
Балким, кийинчерээк биз ишкананын кызматкерин сүрөттөгөн дагы бир классты - Кызматкер классын кошкубуз келет. Бул класс Person классындагыдай эле функцияны ишке ашыргандыктан, кызматкер дагы инсан болгондуктан, Кызматкер классын Person классынан (мураскор, подкласс) алуу рационалдуу болмок, ал өз кезегинде базалык класс деп аталат. , ата-эне же суперкласс:
class Employee extends Person{
public Employee(String name){
super(name); // эгерде базалык класс конструкторду аныктаса
// анда туунду класс аны чакырышы керек
}
}
Бир классты экинчисинин мураскери деп жарыялоо үчүн, мурастоочу класстын атынан кийин, андан кийин базалык класстын аталышынан кийин extensions ачкыч сөзүн колдонуңуз. Employee классы үчүн базалык класс Person болуп саналат, ошондуктан Кызматкер классы Person классындагы бардык талааларды жана ыкмаларды мурастайт.
Эгерде конструкторлор базалык класста аныкталса, анда туунду класстын конструкторунда супер ачкыч сөзү менен базалык класстын конструкторлорунун бири чакырылышы керек. Мисалы, Person классында бир параметрди алган конструктор бар. Ошондуктан, конструктордогу Employee классында Person классынын конструкторун чакыруу керек. Башкача айтканда, super(name) чалуу Person классынын конструкторуна чалууну билдирет.
Конструкторду чакырганда, кашаанын ичиндеги super сөзүнөн кийин өткөн аргументтердин тизмеси болот. Бул учурда, базалык класстын конструкторуна чакыруу туунду класстын конструкторунун эң башында болушу керек. Ошентип, кызматкердин атын коюу базалык класстын конструкторуна берилет.
Мындан тышкары, жогорудагы мисалдагыдай, туунду класс конструктордо башка иш аткарбаса дагы, базалык класстын конструкторун чакыруу керек.
Класстарды колдонуу:
public class Program{
public static void main(String[] args) {
Person tom = new Person("Tom");
tom.display();
Employee sam = new Employee("Sam");
sam.display();
}
}
class Person {
String name;
public String getName(){ return name; }
public Person(String name){
this.name=name;
}
public void display(){
System.out.println("Name: " + name);
}
}
class Employee extends Person{
public Employee(String name){
super(name); // если базовый класс определяет конструктор
// то производный класс должен его вызвать
}
}
Туунду класс жеке модификациялоочу менен аныкталгандардан башка, базалык класстын бардык ыкмаларына жана талааларына (негизги класс башка пакетте болсо да) кире алат. Ошол эле учурда, алынган класс өзүнүн талааларын жана ыкмаларын кошо алат:
public class Program{
public static void main(String[] args) {
Employee sam = new Employee("Sam", "Microsoft");
sam.display(); // Sam
sam.work(); // Sam works in Microsoft
}
}
class Person {
String name;
public String getName(){ return name; }
public Person(String name){
this.name=name;
}
public void display(){
System.out.println("Name: " + name);
}
}
class Employee extends Person{
String company;
public Employee(String name, String company) {
super(name);
this.company=company;
}
public void work(){
System.out.printf("%s works in %s \n", getName(), company);
}
}
Бул учурда, Кызматкер классы кызматкердин иштеген жерин, ошондой эле иш ыкмасын сактаган компания талаасын кошот.
Өткөрүүчү методдор
Туунду класс өзүнүн методдорун аныктай алат же базалык класстан мураска калган методдорду жокко чыгара алат. Мисалы, Кызматкер классындагы көрсөтүү ыкмасын жокко чыгаралы:
public class Program{
public static void main(String[] args) {
Employee sam = new Employee("Sam", "Microsoft");
sam.display(); // Sam
// Works in Microsoft
}
}
class Person {
String name;
public String getName(){ return name; }
public Person(String name){
this.name=name;
}
public void display(){
System.out.println("Name: " + name);
}
}
class Employee extends Person{
String company;
public Employee(String name, String company) {
super(name);
this.company=company;
}
@Override
public void display(){
System.out.printf("Name: %s \n", getName());
System.out.printf("Works in %s \n", company);
}
}
Өткөрүлгөн ыкманын алдында @Override аннотациясы турат. Бул аннотация негизинен милдеттүү эмес.
Методду жокко чыгарууда, анын жеткиликтүүлүк деңгээли базалык класстын жеткиликтүүлүк деңгээлинен кем эмес болушу керек. Мисалы, эгерде базалык класстагы методдун жалпы өзгөрткүчү бар болсо, анда туунду класстагы методдун жалпы өзгөрткүчү болушу керек.
Бирок, бул учурда, биз Кызматкердин дисплей ыкмасы бөлүгү негизги класстын дисплей ыкмасынан аракеттерди кайталай турганын көрө алабыз. Ошентип, биз Кызматкерлер классын кыскарта алабыз:
class Employee extends Person{
String company;
public Employee(String name, String company) {
super(name);
this.company=company;
}
@Override
public void display(){
super.display();
System.out.printf("Works in %s \n", company);
}
Супер ачкыч сөз менен биз базалык класстын ыкмаларын ишке ашырууга да кайрылсак болот.
Наследованияга тыюу салуу
Мурас абдан кызыктуу жана күчтүү механизм болуп саналат, ал эми кээ бир жагдайларда каалаган эмес болушу мүмкүн. Жана бул учурда, сиз акыркы ачкыч сөздү колдонуп мурасты өчүрө аласыз. Мисалы:
public final class Person {
}
Эгерде Person классы ушундай жол менен аныкталган болсо, анда төмөнкү код ката болуп калат жана иштебейт, анткени биз мураска тыюу салганбыз:
class Employee extends Person{ {
}
Мурастоону өчүрүүдөн тышкары, сиз жеке ыкмаларды жокко чыгарууну да алдын ала аласыз. Мисалы, жогорудагы мисалда, display() ыкмасы жокко чыгарылды, келгиле, аны жокко чыгарууну өчүрөлү:
public class Person {
//........................
public final void display(){
System.out.println("Имя: " + name);
}
}
Бул учурда, Кызматкер классы дисплей ыкмасын жокко чыгара албайт.
Динамикалык ыкманы жөнөтүү
Мурас жана ыкмаларды жокко чыгаруу мүмкүнчүлүгү бизге чоң мүмкүнчүлүктөрдү ачат. Биринчиден, биз субкласстын объектисине шилтемени суперкласс өзгөрмөсүнө өткөрүп алабыз:
Person sam = new Employee("Sam", "Oracle");
Кызматкер Адамдан мурас алгандыктан, Кызматчы объекти да Персон объекти болуп саналат. Орой айтканда, ишкананын ар бир кызматкери да адам.
Бирок, өзгөрмө Person объектисин көрсөтсө да, виртуалдык машина ал чындыгында Кызматкер объектисин көрсөтүп жатканын көрөт. Ошондуктан, бул объект боюнча методдорду чакырганда, Person эмес, Employee классында аныкталган методдун версиясы чакырылат. Мисалы:
public class Program{
public static void main(String[] args) {
Person tom = new Person("Tom");
tom.display();
Person sam = new Employee("Sam", "Oracle");
sam.display();
}
}
class Person {
String name;
public String getName() { return name; }
public Person(String name){
this.name=name;
}
public void display(){
System.out.printf("Person %s \n", name);
}
}
class Employee extends Person{
String company;
public Employee(String name, String company) {
super(name);
this.company = company;
}
@Override
public void display(){
System.out.printf("Employee %s works in %s \n", super.getName(), company);
}
}
Бул программанын консолдук натыйжасы:
Person Tom
Employee Sam works in Oracle
Өчүрүлгөн ыкма чакырылганда, виртуалдык машина подкласста аныкталган методдун версиясын динамикалык түрдө табат жана чакырат. Бул процесс динамикалык ыкма издөө же динамикалык ыкма издөө же динамикалык ыкманы жөнөтүү деп да аталат.