JavaRush /Java блогы /Random-KK /Абстрактілі класстар мен интерфейстер арасындағы айырмашы...

Абстрактілі класстар мен интерфейстер арасындағы айырмашылық

Топта жарияланған
Сәлеметсіз бе! Бұл дәрісте біз абстрактілі сыныптардың интерфейстерден қалай ерекшеленетіні туралы сөйлесеміз және жалпы абстрактілі сыныптары бар мысалдарды қарастырамыз. Абстрактілі класстар мен интерфейстер арасындағы айырмашылық – 1Біз бөлек дәрісті абстрактілі сынып пен интерфейстің айырмашылығына арнадық, өйткені тақырып өте маңызды. Болашақ сұхбаттардың 90% сізден осы ұғымдар арасындағы айырмашылық туралы сұралады. Сондықтан, оқығаныңызды міндетті түрде түсініңіз, ал егер бір нәрсені толық түсінбесеңіз, қосымша дереккөздерді оқыңыз. Сонымен, біз абстрактілі сыныптың және интерфейстің не екенін білеміз. Енді олардың айырмашылықтарына тоқталайық.
  1. Интерфейс тек мінез-құлықты сипаттайды. Оның байлығы жоқ. Бірақ абстрактілі класстың күйі бар: ол екеуін де сипаттайды.

    BirdМысал ретінде дерексіз класс пен интерфейсті алайық Flyable:

    public abstract class Bird {
       private String species;
       private int age;
    
       public abstract void fly();
    
       public String getSpecies() {
           return species;
       }
    
       public void setSpecies(String species) {
           this.species = species;
       }
    
       public int getAge() {
           return age;
       }
    
       public void setAge(int age) {
           this.age = age;
       }
    }

    Құс класын Mockingjay(мазақшы) жасап, келесіден мұра алайық Bird:

    public class Mockingjay extends Bird {
    
       @Override
       public void fly() {
           System.out.println("Fly, birdie!");
       }
    
       public static void main(String[] args) {
    
           Mockingjay someBird = new Mockingjay();
           someBird.setAge(19);
           System.out.println(someBird.getAge());
       }
    }

    Көріп отырғаныңыздай, біз абстрактілі класстың күйіне – оның айнымалыларына species(түріне) және age(жасына) оңай қол жеткізе аламыз.

    Бірақ интерфейспен де солай істеуге тырыссақ, сурет басқаша болады. Оған айнымалы мәндерді қосуға болады:

    public interface Flyable {
    
       String species = new String();
       int age = 10;
    
       public void fly();
    }
    
    public interface Flyable {
    
       private String species = new String(); // error
       private int age = 10; // also an error
    
       public void fly();
    }

    Біз тіпті интерфейс ішінде жеке айнымалы мәндерді жасай алмаймыз . Неліктен? Жеке модификатор пайдаланушыдан іске асыруды жасыру үшін жасалғандықтан . Бірақ интерфейс ішінде ешқандай іске асыру жоқ: онда жасыратын ештеңе жоқ.

    Интерфейс тек әрекетті сипаттайды. Тиісінше, интерфейс ішінде гетерлер мен орнатушыларды іске асыра алмаймыз. Бұл интерфейстің табиғаты: ол күйге емес, мінез-құлыққа қатысты.

    Java8 іске асырылуы бар әдепкі интерфейс әдістерін ұсынды. Сіз олар туралы бұрыннан білесіз, сондықтан біз оларды қайталамаймыз.

  2. Абстрактілі класс өте тығыз байланысы бар сыныптарды байланыстырады және біріктіреді. Сонымен қатар, бірдей интерфейсті мүлдем ортақ ештеңе жоқ сыныптар жүзеге асыра алады.

    Құстар туралы мысалға оралайық.

    BirdОның негізінде құстарды жасау үшін біздің реферат сыныбымыз қажет. Тек құстар және басқа ешкім емес! Әрине, олар әртүрлі болады.

    Абстрактілі класстар мен интерфейстер арасындағы айырмашылық – 2

    Интерфейспен Flyableбәрі басқаша. Ол тек өз атына сәйкес мінез-құлықты сипаттайды - «ұшу». «Ұшатын», «ұшуға қабілетті» анықтамасы бір-бірімен байланысы жоқ көптеген an objectілерді қамтиды.

    Абстрактілі класстар мен интерфейстер арасындағы айырмашылық – 3

    Бұл 4 нысан бір-бірімен ешқандай байланысы жоқ. Не айтамын, олардың бәрі де жанды емес. Дегенмен, олардың барлығы Flyableұшуға қабілетті.

    Біз оларды дерексіз класс арқылы сипаттай алмас едік. Олардың жалпы күйі немесе бірдей өрістері жоқ. Әуе кемесін сипаттау үшін бізге «модель», «шығару жылы» және «жолаушылар санының максималды саны» өрістері қажет болуы мүмкін. Карлсон үшін бүгін ол жеген барлық тәттілерге арналған өрістер және оның Баламен ойнайтын ойындарының тізімі бар. Москит үшін... у-у... біз тіпті білмейміз... Мүмкін «тітіркену деңгейі»? :)

    Ең бастысы, біз оларды дерексіз класс арқылы сипаттай алмаймыз. Олар тым әртүрлі. Бірақ жалпы мінез-құлық бар: олар ұша алады. Интерфейс әлемдегі ұшуға, жүзуге, секіруге немесе басқа мінез-құлыққа ие болатын барлық нәрсені сипаттауға өте ыңғайлы.

  3. Кластар қалағанша көптеген интерфейстерді жүзеге асыра алады, бірақ олар тек бір сыныптан мұраға алады.

    Біз бұл туралы бірнеше рет айтқанбыз. Java-да бірнеше мұра жоқ, бірақ бірнеше іске асыру бар. Бұл тармақ алдыңғысынан ішінара туындайды: интерфейс көбінесе ортақ ештеңесі жоқ көптеген әртүрлі класстарды байланыстырады және бір-біріне өте жақын класстар тобы үшін абстрактілі класс жасалады. Сондықтан, сіз тек бір сыныптан мұраға алатыныңыз қисынды. Абстрактілі класс «бұл» қатынасты сипаттайды.

Стандартты InputStream & OutputStream интерфейстері

Біз қазірдің өзінде ағынды енгізу мен шығаруға жауапты әртүрлі сыныптардан өттік. InputStreamжәне қарайық OutputStream. Жалпы, бұл интерфейстер емес, нақты дерексіз класстар. Енді сіз олардың не екенін білесіз, сондықтан олармен жұмыс істеу әлдеқайда жеңіл болады :) InputStream- бұл byte енгізуге жауапты дерексіз класс. Java-да мұраға қалдырылатын сыныптар қатары бар InputStream. Олардың әрқайсысы әртүрлі көздерден деректерді алу үшін конфигурацияланған. Ол ата-ана болғандықтан InputStream, ол деректер ағындарымен ыңғайлы жұмыс істеудің бірнеше әдістерін ұсынады. Әр баланың мынадай әдістері бар InputStream:
  • int available()оқуға қолжетімді byte санын қайтарады;
  • close()кіріс көзін жабады;
  • int read()ағындағы келесі қол жетімді byteтың бүтін көрінісін қайтарады. Егер ағынның соңына жетсе, -1 саны қайтарылады;
  • int read(byte[] buffer)byteтарды буферге оқу әрекеті, оқылған byteтардың санын қайтарады. Файлдың соңына жеткенде -1 қайтарады;
  • int read(byte[] buffer, int byteOffset, int byteCount)byte блогының бір бөлігін оқиды. Деректер блогының толық толтырылмау мүмкіндігі болған кезде қолданылады. Файлдың соңына жеткенде -1 қайтарады;
  • long skip(long byteCount)өткізіп жіберу byteCount, енгізу byteы, еленбеген byteтардың санын қайтарады.
Мен сізге әдістердің толық тізімін зерттеуге кеңес беремін . Іс жүзінде оннан астам сабақтас сыныптар бар. Міне, бірнеше мысал:
  1. FileInputStream: ең көп таралған түрі InputStream. Файлдан ақпаратты оқу үшін қолданылады;
  2. StringBufferInputStream: басқа пайдалы түрі InputStream. Ол жолды кіріс деректер ағынына айналдырады InputStream;
  3. BufferedInputStream: буферленген кіріс ағыны. Ол көбінесе тиімділікті арттыру үшін қолданылады.
BufferedReaderБіз өтіп бара жатып , оны пайдаланудың қажеті жоқ деп айтқанымыз есіңізде ме ? Біз жазған кезде:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
... BufferedReaderоны пайдаланудың қажеті жоқ: InputStreamReaderол тапсырманы орындайды. Бірақ BufferedReaderол мұны тиімдірек етеді және сонымен қатар деректерді жеке таңбалардан гөрі, бүкіл жолдар бойынша оқи алады. Бәрі BufferedInputStreamбірдей! Класс кіріс деректерін енгізу құрылғысына үнемі қатынаусыз арнайы буферде жинақтайды. Мысал қарастырайық:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;

public class BufferedInputExample {

   public static void main(String[] args) throws Exception {
       InputStream inputStream = null;
       BufferedInputStream buffer = null;

       try {

           inputStream = new FileInputStream("D:/Users/UserName/someFile.txt");

           buffer = new BufferedInputStream(inputStream);

           while(buffer.available()>0) {

               char c = (char)buffer.read();

               System.out.println("Character was read" + c);
           }
       } catch(Exception e) {

           e.printStackTrace();

       } finally {

           inputStream.close();
           buffer.close();
       }
   }
}
Бұл мысалда біз компьютерде "D:/Users/UserName/someFile.txt" мекенжайында орналасқан файлдан деректерді оқимыз . Біз 2 нысанды жасаймыз - FileInputStreamжәне BufferedInputStreamоның «орауы» ретінде. Осыдан кейін біз файлдан byteтарды оқып, оларды таңбаларға түрлендіреміз. Файл аяқталмайынша. Көріп отырғаныңыздай, мұнда күрделі ештеңе жоқ. Сіз бұл codeты көшіріп, оны компьютеріңізде сақталған кейбір нақты файлда іске қоса аласыз :) Класс OutputStream- byte ағынының шығысын анықтайтын дерексіз класс. Сіз түсінгеніңіздей, бұл «а» антиподы InputStream. Ол деректерді қайдан оқуға емес, оны қайда жіберуге жауапты . Мысалы InputStream, бұл абстрактілі класс барлық ұрпақтарды ыңғайлы жұмыс үшін әдістер тобымен қамтамасыз етеді:
  • int close()шығыс ағынын жабады;
  • void flush()барлық шығыс буферлерін тазартады;
  • abstract void write (int oneByte)шығыс ағынына 1 byte жазады;
  • void write (byte[] buffer)шығыс ағынына byte массивін жазады;
  • void write (byte[] buffer, int offset, int count)позицияның ығысуынан бастап массивтен санау byteтарының ауқымын жазады.
Міне, сыныптың кейбір ұрпақтары OutputStream:
  1. DataOutputStream. Стандартты Java деректер түрлерін жазу әдістерін қамтитын шығыс ағыны.

    Қарапайым Java түрлері мен жолдарын жазуға арналған өте қарапайым класс. Сіз жазбаша codeты түсіндірместен де түсінесіз:

    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           DataOutputStream dos = new DataOutputStream(new FileOutputStream("testFile.txt"));
    
           dos.writeUTF("SomeString");
           dos.writeInt(22);
           dos.writeDouble(1.21323);
           dos.writeBoolean(true);
    
       }
    }

    Оның әрбір түрі үшін бөлек әдістері бар - writeDouble(), writeLong(), writeShort()және т.б.

  2. Сынып FileOutputStream . Дискідегі файлға деректерді жіберу механизмін жүзеге асырады. Айтпақшы, біз оны алдыңғы мысалда қолдандық, байқадыңыз ба? Біз оны DataOutputStream ішіне жібердік, ол «орау» рөлін атқарды.

  3. BufferedOutputStream. Буферленген шығыс ағыны. BufferedInputStreamЕштеңе де күрделі емес, мәні (немесе 'a) дегенмен бірдей BufferedReader. Әдеттегі дәйекті деректерді жазудың орнына арнайы «сақтау» буфері арқылы жазу қолданылады. Буферді пайдалану арқылы деректер тағайындалған жерге баратын сапарлар санын азайтуға және осылайша тиімділікті арттыруға болады.

    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           FileOutputStream outputStream = new FileOutputStream("D:/Users/Username/someFile.txt");
           BufferedOutputStream bufferedStream = new BufferedOutputStream(outputStream);
    
           String text = "I love Java!"; // we will convert this string into an array of bytes and write it to a file
    
           byte[] buffer = text.getBytes();
    
           bufferedStream.write(buffer, 0, buffer.length);
           bufferedStream.close();
       }
    }

    Тағы да, сіз бұл codeпен өзіңіз «ойнауға» және оның компьютердегі нақты файлдарда қалай жұмыс істейтінін тексеруге болады.

Сондай-ақ мұрагерлер туралы « InputStreamInput /Output SystemOutputStream » материалынан оқуға болады . О , бізде де бөлек дәріс болады, сондықтан олар туралы алғашқы танысу үшін жеткілікті ақпарат бар. Осымен болды! Сіз интерфейстер мен дерексіз сыныптар арасындағы айырмашылықтарды жақсы түсіндіңіз және кез келген сұраққа, тіпті қиын сұраққа жауап беруге дайынсыз деп үміттенеміз :) FileInputStreamFileOutputStreamBufferedInputStream
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION