Download presentation
Presentation is loading. Please wait.
1
Методика наставе рачунарства
Владимир Филиповић
2
Улаз и излаз, серијализација
Владимир Филиповић
3
Токови, читачи и писачи Улаз и излаз у Јави су (исто као и мрежна и веб комуникација) реализоване преко токова података. Основу чине две апстрактне класе: InputStream и OutputStream. Из ових класа се изводе поткласе са одговарајућим методама за унос и за излаз. Класе се налазе у пакету java.io. Улаз и излаз се у овом случају организују преко тока бајтова. Поступак је да се креира ток, који ће приликом позива конструктора бити придружен датотеци, конзоли или мрежном порту, а улазно/излазне операције се реализују позивима одговарајућих метода над тако креираним током. Скоро сви улазно-излазни методи могу генерисати изузетке, па они обично у декларацији садрже throw IOException. Стога, при позиву ових метода, морају бити обрађени сви побројани избачени изузетци.
4
Токови, читачи и писачи (2)
Поред токова података, за улаз и излаз се још користе читачи и писачи. Основна разлика у односу на токове података је у томе што читачи и писачи не раде са бајтова, већ са Unicode знацима. Основу чине две апстрактне класе: Reader и Writer, из којих се изводе одговарајуће поткласе. Поступак је да се креира читач/писач, који ће приликом позива конструктора бити придружен датотеци, конзоли или мрежном порту, а улазно/излазне операције се реализују позивима одговарајућих метода над креираним читачем/писачем. Скоро сви улазно-излазни методи могу генерисати изузетке, па они обично у декларацији садрже throw IOException.
5
Токови, читачи и писачи (3)
Дијаграм који следи приказује односе наслеђивања између токова података, читача и писача.
6
Токови, читачи и писачи (4)
Како су InputStream и OutputStream апстрактне класе, то се улаз/излаз обично реализује преко њихових поткласа, као што су: FileInputStream, FileOutputStream, DataInputStream и DataOutputStream. Наравно, често се користе и друге поткласе ових класа (биће побројане касније), чиме се нпр. омогућава филтерисање и/или баферисан улаз/излаз. Како су Reader и Writer апстрактне класе, то се улаз/излаз обично реализује преко њихових поткласа, као што су: InputStreamReader, FileReader, InputStreamWriter и FileWriter. Наравно, често се користе и друге поткласе ових класа (биће побројане касније).
7
Токови, читачи и писачи (5)
Токови који су већ коришћени у ранијим програмима су System.in и System.out, примерци класа InputStream и PrintStream, респективно. „Стандардни“ излазни ток System.out је већ отворен и спреман за прихватање података. Обично овај ток одговара излазу конзоле или другом одредишту за излаз који је одредило окружење домаћина. „Стандардни улазни ток System.in је већ отворен и спреман за прихват улазних података. Обично овај ток одговара улазу са тастатуре или неком другом улазном извору који је одредило Јава окружење домаћина, односно корисник.
8
Улазни токови података
Основни метод у класи InputStream је метод read. Тај метод чита један бајт (број 0-255). Ако се при читању препозна крај тока, метод враће -1. Потпис овог метода је: public abstract int read() throws IOExeption Треба напоменути да се улазне операције обично не реализују директним позивима метода read, већ се користе други објекти, нпр. објекти типа Scanner, o којима ће касније бити више речи. Методи за читање низа бајтова (ни они се директно не позивају много често): public int read(byte b[]) throws IOException public int read(byte b[], int pocetak, int duzina) throws IOException Поред метода read, у овој класи су дефинисани и методи: skip, available, mark, reset и close. Међутим, на њима се нећемо много задржавати.
9
Улазни токови података (2)
Улазне операције реализоване преко класе InputStream су операције тзв. ниског нивоа. Рад на том нивоу није атрактиван ни ефикасан (са тачке гледишта типичног програмера) па је развијен велики број поткласа за организацију улаза „специјалних“ врста података. Дакле, улаз се обично организује преко поткласа као што су: FileInputStream, FilterInputStream, ByteArrayInputStream, ObjectInputStream итд. Наравно, у овим класама се по потреби редефинишу методи класе InputStream, али се уводе и нови методи.
10
Улазни токови података (3)
Следећи дијаграм приказује поткласе класе InputStream:
11
Излазни токови података
У класи OutputStream најчешће се користи метод write. Слично као и у претходном случају, излазне операције се обично не реализују директним позивима метода write. Метод write је преоптерећен у овој класи: public abstract void write(int b) throws IOException public void write(byte b[]) throws IOException public void write(byte b[], int offset, int len) throws IOException Метод flush служи за пражњење излазног бафера: public void flush() throws IOException Метод close затвара излазни ток података, чиме се омогућује боље коришћење ресурса: public void close() throws IOException
12
Излазни токови података (2)
Излазне операције реализоване преко класе OutputStream су операције тзв. ниског нивоа. Рад на том нивоу није атрактиван ни ефикасан (са тачке гледишта типичног програмера) па је развијен велики број поткласа за организацију излаза „специјалних“ врста података. Дакле, излаз се обично организује преко поткласа као што су: FileOutputStream, FilterOutputStream, ByteArrayOutputStream, ObjectOutputStream итд. Наравно, у овим класама се по потреби редефинишу методи класе OutputStream, али се уводе и нови методи.
13
Излазни токови података (3)
Следећи дијаграм приказује поткласе класе OutputStream:
14
Читачи Основни метод у класи Reader је метод read. Тај метод чита један цео број који представља код Unicode знака. Ако се при читању препозна крај улаза, метод враће -1. Потпис овог метода је: public abstract int read() throws IOExeption Методи за читање низа Unicode знакова: public int read(char cbuf[]) throws IOException abstract public int read(char cbuf[], int off, int len) throws IOException Поред метода read, у овој класи су дефинисани и методи: skip, ready, mark, reset и close. Међутим, на њима се нећемо задржавати.
15
Читачи (2) Следећи дијаграм приказује поткласе класе Reader:
16
Писачи Метод write у класи Writer je такође преоптерећен:
public abstract void write(byte b) throws IOException public void write(char cbuf[]) throws IOException abstract public void write(char cbuf[], int off, int len) throws IOException public void write(String str) throws IOException public void write(String str, int off, int len) throws IOException Ту су још следећи методи: Метод append служи за додавање знака/знакова у писач; Метод flush служи за пражњење излазног бафера писача; Метод close затвара писач, чиме се омогућује боље коришћење ресурса.
17
Писачи (2) Следећи дијаграм приказује поткласе класе Writer:
18
Уланчавање токова У Јави се користи паметан механизам за раздвајање две врсте одговорности. Наиме, неки токови (као што је FileInputStream и улазни токови које враће метод openStream класе URL) могу да прибаве бајтове из датотека или из других „егзотичних“ локација. Други токови (као што су DataInputStream и PrintWriter) могу од бајтова да склопе корисније типове података. Јава програмер само треба да комбинује ове два функционалности.
19
Уланчавање токова (2) На пример, да би се могао прочитати реалан број из датотеке, прво треба креирати примрак класе FileInputStream и потом га проследити конструктору класе DataInputStream. FileInputStream fin = new FileInputStream("employee.dat"); DataInputStream din = new DataInputStream(fin); double s = din.readDouble(); На дијаграмима који приказују наслеђивање за FilterInputStream и FilterOutputStream., уочавамо бројне поткласе ове две класе. Те поткласе се користе ради додавања додатних способности на „сирове“ токове бајтова.
20
Уланчавање токова (3) Програмер може, додатним уланчавањем, тј. угњежђавањем филтера, додати више способности. На пример, токови нису баферисани. То значи да сваки позив за читање датотеке од оперативног система захтева да прибави један бајт. Ефикасније је да се захтева блок података и да се они сместе у бафер. Ако су потребни и баферисање улаза и читање структурисаних података, то се постиже на следећи начин: DataInputStream din = new DataInputStream( new BufferedInputStream( new FileInputStream("employee.dat"))); Уочава се да класа DataInputStream мора бити последња у ланцу конструктора, зато што програмер треба директно да позива DataInputStream методе, а да се истовремено користи и метод за баферисано читање.
21
Уланчавање токова (4) Понекад је при уланчавању токова потребно водити рачуна и о токовима у средини. На пример, при читању улазних података, често је потребно „завирити“ у следећи бајт да би се видело да ли он садржи очекивану вредност. У ту сврху Јава обезбеђује класу PushbackInputStream. PushbackInputStream pbin = new PushbackInputStream( new BufferedInputStream( new FileInputStream("employee.dat"))); Сада се, ако је то потребно, може прочитати следећи бајт int b = pbin.read(); и тај прочитани бајт вратити назад уколико није потребан if (b != '<') pbin.unread(b); Наравно, једини методи који се могу применити на улазни ток са враћањем, тј. PushbackInputStream су read и unread.
22
Уланчавање токова (5) Ако је потребно и гледање унапред и читање бројева, тада су потребне референце и на PushbackInputStream и на DataInputStream. DataInputStream din = new DataInputStream( pbin = new PushbackInputStream( new BufferedInputStream( new FileInputStream("employee.dat")))); Наравно, системске библиотеке у другим програмским језицима су се аутоматски побринуле за корисне ствари као што су баферисање и гледање унапред, тако да је на први поглед помало заморно у Јави улагати додатни труд у комбиновање тј. уланчавање филтера за токове. Међутим, способност комбиновања и уклапања класа са филтерима како би се конструисале заиста корисне токова Јава програмеру даје огромну флексибилност.
23
Уланчавање токова (6) На пример, читање бројева из компресоване ZIP датотеке може да се постигне на следећи начин: ZipInputStream zin = new ZipInputStream(new FileInputStream("employee.zip")); DataInputStream din = new DataInputStream(zin); Оваква организација одсликава образац дизајна „Филтер за пресретање“.
24
Датотеке и директоријуми
Подаци у спољашњој меморији рачунарског система су обично организовани помоћу концепта датотека и директоријума. Датотека представљја колекцију података који чине једну логичку целину, а директоријуми (каталози) служе за груписање датотека. У програмском језику Јава, за рад са датотекама и директоријумима се користи класа File.
25
Рад са File објектима Објекат – примерак класе File заправо не представља датотеку, већ енкапсулира путању до нечега што може, а не мора бити датотека или директоријум. Чињеница да је направљен File објекат са путањом до неке датотеке или директоријума не значи да сама та датотека или директоријум постоји. Често се дефинише File објекат који енкапсулира путању до нове датотеке или новог директоријума који ће тек касније да буде креиран.
26
Рад са File објектима (2)
може се користити како би се проверило да ли његова путања одговара стварној датотеци или директоријуму; може се користити за креирање објеката који служе за читање и писање датотека. File објекти су немутирајући. Даклсе, након што је File објекат креиран, није могуће променити путању коју он енкапсулира. Могуће је, коришћењем метода rename, променити име физичке датотеке на који File објекат указује, али сам File објекат и даље енкапсулира оригиналну путању. Дакле, када се методом rename промени име датотеке, File објекат не реферише на постојећу датотеку (са тим новим именом).
27
Креирање File објеката
Први очекује као аргумент стринг са путањом фајла или директоријума: File myDir = new File("C:/jdk1.5.0/src/java/io"); или File myDir = new File("C:\\jdk1.5.0\\src\\java\\io"); Конструктор не врши никакву проверу прослеђене ниске, тако да нема гаранције да датотека/директоријум заиста и постоји. Следећа два конструктора омогућују да се одвојено задају директоријум који садржи датотеку (родитељски директоријум) и име датотеке. Родитељски директоријум се задаје било референцом на File објекат који енкапсулира путању до њега, било ниском. Име датотеке је, наравно ниска.
28
Креирање File објеката (2)
Примери за оба ова конструктора: File myDir = new File("C:/jdk1.5.0/src/java/io"); // Parent directory File myFile = new File(myDir, "File.java"); // The path to the file File myFile = new File("C:/jdk1.5.0/src/java/io", "File2.java"); Коришћење File објекта за задавање директоријума је много корисније од директног коришћења стринга. Када се користи File објекат, могуће је проверити да ли директоријум заиста постоји пре покушаја приступања фајлу или фајловима за које смо заинтересовани. Надаље, у овом случају је могуће и креирати директоријум, ако то ситуација захтева.
29
Креирање File објеката (3)
Последњи, четврти конструктор, омогућује креирање File објекта од објекта типа URI (енг. uniform resource identifier), који енкапсулира униформни идентификатор ресурса на вебу. Најчешћа форма URI-ја је URL (енг. uniform resource locator). Пример: File remoteFile = new File( new URI("
30
Апсолутне и релативне путање
Приликом рада са File објектима, могу се користити и апсолутне и релативне путање. Пример коришћења релативе путање: File myFile = new File("output.txt"); У горњем случају, путања је релативна у односу на текући директоријум (па се датотека "output.txt" налази у истом директоријуму у ком се налази програм). Уместо експлицитног писања / односно \\ може се користити статички члан separator класе File тј. File.separator.
31
Системска својства Системска својства (енг. system properties) одређује вредности параметара системског окружења у коме се програм извршава. Свако системско својство има јединствено име и придружену ниска-вредност. Скуп стандардних системских својстава је увек доступан и могуће им је приступати прослеђивањем имена својства статичком методу getProperty класе System. Пример. Подразумевани основни директоријум за релативне путање за датог корисника одређен је својством чије је име "user.dir", тако да се вредност путање овог директоријума очитава наредбом: String currentDir = System.getProperty("user.dir");
32
Системска својства (2) Тако би се, на пример, користећи:
String currentDir = System.getProperty("user.dir"); File dataFile = new File(currentDir, "output.txt"); постигло исто што и са: File myFile = new File("output.txt"); Вредност системског својства "user.home" дефинише путању до корисниковог home директоријума. Тако се наредбом File dataFile = new File(System.getProperty("user.home"), "output.txt"); задаје референца на датотеку "output.txt" у home директоријуму корисника. Локација овог директоријума је зависна од система, али где год да буде, њој се може приступити без уграђивања у наш програм елемената који зависе од конкретног система.
33
Системска својства (3) Пример.
Следеће наредбе листају имена и вредности за текући скуп системских својстава: java.util.Properties properties = System.getProperties(); properties.list(System.out); Вредност системског својства може се променити позивом статичког метода setProperty класе System. Метод очекује два аргумента, први је ниска којим се задаје својство чија се вредност жели променити, а други је ниска са новом вредношћу својства. Постоји и могућност уклањања текуће вредности која је постављена за својство позивом статичког метода clearProperty класе System. Једини аргумент метода је име системског својства које се уклања.
34
Системска својства (4) Пример.
Следећом наредбом се врши уклањање системског својства "java.class.path" : String oldValue = System.clearProperty("java.class.path"); Метод clearProperty враћа претходну вредност коју је то својство имало. Уколико Јава менаџер за безбедност не допусти уклањање својства, бива избачен изузетак типа Security Exception. Уколико је аргумент позива метода null, избацује се изузетак типа NullPointerException, а уколико је аргумент позива празан стринг избацује се изузетак типа IllegalArgumentException.
35
Системска својства (5) Промена текућег директоријума се може реализовати преко промене системског својства. Пример. Следећом наредбом се мења текући директоријум: System.setProperty("user.dir", "C:/MyProg"); Када се након ове наредбе буде користила релативна путања, она ће бити релативна у односу на директоријум "C:/MyProg". Вредност системског својства које дефинише текући директоријум је могуће мењати у ма ком тренутку рада програма. Наравно, пре промене системског својства "user.dir" треба проверити да ли заиста постоји директоријум који ће се прогласити за нови текући директоријум.
36
Тестирање File објеката
1) Испитивање објеката getName( ) враћа име датотеке, не укључујући путању. Ако објекат представља директоријум, враћа само име директоријума getPath( ) враћа путању, укључујући име датотеке или директоријума isAbsolute( ) враћа true ако је путања апсолутна, false иначе getParent( ) враћа име родитељског директоријума (за датотеку или директоријум). То је оригинална путања без последњег имена. Може вратити null ако није одређен родитељски директоријум (нпр. File објекат је креиран за фајл у текућем директоријуму коришћењем само имена фајла).
37
Тестирање File објеката (2)
getParentFile( ) враћа родитељски директоријум као File објекат или null ако не постоји родитељ. toString( ) враћа исту ниску исти као getPath( ) equals( ) метод се користи за поређење два File објекта. Пореде се путање. 2) Испитивање датотека и директоријума exists( ) isDirectory( ) isFile( ) isHidden( ) canRead( ) canWrite( ) за овај и претходне методе јасно је из имена када враћају true, односно false.
38
Тестирање File објеката (3)
getAbsolutePath( ) враћа апсолутну путању датотеке, односно директоријума реферисаног текућим File објектом. Ако објекат садржи апсолутну путању, враћа се иста ниска коју враће метода getPath( ). getAbsoluteFile( ) враћа File објекат који садржи апсолутну путању за фајл или директоријум реферисан текућим File објектом. За File објекат креиран коришћењем релативне путање која се састоји само од имена фајла, метод getParent( ) враћа null. У том случају може се користити метод getAbsolutePath(), како би се добила апсолутна путања или метод getAbsoluteFile( ) како бисмо добили File објекат за који ће метод getParent( ) вратити ниску која представља комплетну путању до родитељског директоријума. Све операције које укључују приступ фајловима на локалној машини могу избацити изузетак типа SecurityException у случају да приступ није ауторизован.
39
Тестирање File објеката (4)
3) Добијање додатних информација о датотеци или директоријуму list ако текући File објекат представља директоријум, метод враћа низ ниски са именима чланова директоријума. Ако је директоријум празан, враћени низ биће такође празан. Ако је текући File објекат датотека, метод враћа null. При извршавању метода може бити избачен изузетак типа SecurityException. listFiles Ако је текући објекат директоријум, враћа низ File објеката који одговарају датотекама и директоријумима у том директоријуму. Ако је директоријум празан, враћени низ биће такође празан. Метод враћа null ако објекат није директоријум или се деси I/O грешка. при извршавању може бити избачен изузетак типа SecurityException.
40
Тестирање File објеката (5)
length враћа вредност типа long, која је дужина, у бајтовима, датотеке на коју реферише текући File објекат. Ако се ради о датотеци који не постоји, враћена дужина биће 0. Ако објекат реферише на директоријум, није дефинисано шта је повратна вредност метода. lastModified враћа вредност типа long, која представља време када је датотека или директоријум реферисан текућим објектом последњи пут измењен. Време је изражено бројем милисекунди протеклих од поноћи 1. јануара по Гриничу. Ако фајл не постоји, метод враћа 0. listRoots Статички метод класе Filе враћа низ Filе објеката, при чему сваки елемент у низу одговара кореном директоријуму текућег система датотека. Путања сваке од датотека у систему почиње неким од корених директоријума. На Unix систему враћени низ имаће само један елемент који одговара једином кореном директоријуму /. под Windows-ом, низ садржи по елемент за сваки логички уређај који имамо, укључујући floppy, CD, DVD. Стандардно системско својство "java.home" одређује корени директоријум за Java окружење за извршавање.
41
Тестирање File објеката (6)
4) Филтрирање листе Постоје и верзије метода list и listFiles класе File које очекују аргумент за филтрирање листе. То омогућује добијање листе елемената са задатом екстензијом или чија имена почињу задатом секвенцом карактера. Пример. Траже се све датотеке/директоријуми чија имена почињу словом Т. Аргумент који се прослеђује методу list мора бити типа FilenameFilter, док метод listFiles прихвата аргумент типа FilenameFilter или FileFilter. И FilenameFilter и FileFilter су интерфејси који садрже апстрактни метод accept.
42
Тестирање File објеката (7)
Оба интерфејса су дефинисана у пакету java.io са: public interface FilenameFilter { public abstract boolean accept(File directory, String filename); } public interface FileFilter { public abstract boolean accept(File pathname); Филтрирање листе коју враћају list и listFiles врши се тако што се за сваки елемент листе позива метод accept објекта прослеђеног као аргумент метода list, односно listFiles. Ако accept врати true, елемент остаје у листи, а иначе се искључује из ње. Избор начина на који се имена филтрирају је потпуно препуштен програмеру.
43
Тестирање File објеката (8)
5) Креирање и модификовање датотека и директоријума Датотека се може преименовати или учинити доступним само за читање. Могу се креирати или обрисати фајлови и директоријуми. Методи који то омогућују су следећи: renameTo(File path) датотека-директоријум реферисан текућим објектом бива преименован у складу са аргументом. Текући објекат се не мења, већ само физичка датотека/директоријум. Датотека/директоријум на који реферише текући објекат, након овога више не постоји, јер сада има ново име, а можда је и у другом директоријуму. Ако је операција успешна, метод враћа true, а иначе false (не постоји директоријум дефинисан новом путањом или немамо право писања у њега). setReadOnly враћа true ако је операција успела
44
Тестирање File објеката (9)
mkdir креира директоријум са путањом одређеном текућим објектом. Метод не успева ако родитељски директоријум не постоји. Враћа true ако је операција успела. mkdirs за разлику од претходног, креира неопходне родитељске директоријуме. Враћа true ако је операција успела. Чак и ако операција не успе, могуће је да су креирани неки од родитељских директоријума. createNewFile креира нову празну датотеку са путањом задатом текућим објектом, ако такав не постоји. Метод креира датотеку само у постојећем директоријуму (не креира директоријуме одређене путањом). Враћа true ако је успео. createTempFile статички метод који креира привремени фајл у задатом директоријуму (трећи аргумент), са именом које одређују прва два аргумента метода. При томе, први аргумент одређује почетни део имена фајла, а други његову екстензију.
45
Тестирање File објеката (10)
delete брише датотеку/директоријум представљен текућим објектом и враћа true ако је брисање успело. Не брише директоријуме који нису празни. Да би се обрисао директоријум, најпре се мора обрисати сав његов садржај. deleteOnExit датотека/директоријум представљен текућим објектом биће избрисан по завршетку рада програма. Метод нема повратну вредност. Брисање ће бити покушано само ако се JVM заврши нормално. Једном када се овај метод позове за File објекат, операција је неповратна. Датотеке који се креирају коришћењем метода createTempFile нису нужно привремени јер се не бришу аутоматски. Стога се мора користити delete или deleteOnExit како би се уклониле датотеке које више нису потребне.
46
Тестирање File објеката (11)
Пример. Да би привремени фајл био аутоматски обрисан на крају програма, може се позвати метод deleteOnExit: File tempFile = File.createTempFile("list", null); tempFile.deleteOnExit(); Прва наредба ће креирати привремени фајл са именом облика listxxxxx.tmp у подразумеваном привременом директоријуму. Део имена xxxxx генерише се аутоматски. Метод deleteOnExit се може применити на било који File објекат, не само на оне који одговарају привременим фајловима, али то треба радити са опрезом. Као што је већ истакнуто, брисање је неповратна операција.
47
Класа Scanner Користи се за парсирање примитивних типова и стрингова.
Налази се у пакету java.util, наслеђује класу java.lang.Object Раставља свој улаз на токене коришћењем регуларних израза, при чему за подразумеванe знаке раздвајања сматра белине (’ ’, ’\n’, ’\t’, итд.). Примерак класе Scanner може читати из ма ког објекта који имплементира интерфејс Readable и он претпоставља да се дошло до краја улаза када се избаци изузетак типа IOException. Резултујући токени се могу конвертовати у вредности различитих типова користећи разне варијанте next методе. Пример. Читање наредног целог броја из тока System.in: Scanner sc = new Scanner(System.in); int i = sc.nextInt();
48
Класа Scanner (2) Пример.
Читање целих бројева типа long из дате датотеке, све док их има: Scanner sc = new Scanner(new File(”myNumbers”)); while( sc.hasNextLong() ) long aLong=sc.nextLong(); Читање из ниске: String input = ”1 2 java san”; Scanner s = new Scanner(input); System.out.println(s.nextInt()); // 1 System.out.println(s.nextInt()); // 2 System.out.println(s.next()); // java System.out.println(s.next()); // san Када примерак класе Scanner избаци изузетак типа InputMismatchException, он неће проћи преко токена који је изазвао изузетак, тако да се тај токен може обрадити или прескочити применом неког другог метода.
49
Класа Scanner (3) java.util.Scanner
useDelimiter() поставља друге знаке као знаке раздвајања при парсирању регуларних израза (уместо белина). next() nextInt() nextXXX (где је XXX име примитивног типа Boolean, Double, Float, ...) најпре прескачу знакове раздвајања, а затим парсирају наредни токен и покушавају да врате вредност циљног типа која одговара парсираном токену. hasNext() hasNextInt() hasNextXXX (где је XXX име примитивног типа Boolean, Double, Float, ...) најпре прескачу знакове раздвајања, а затим парсирају наредни токен и покушавају да враћају true уколико парсирани токен представља вредност циљног типа. У супротном враће false. findInLine() findWithinHorizon() траже задати образац (у опсегу) не узимајући у обзир знаке за раздвајање.
50
Класа Scanner (4) java.util.Scanner public Scanner(InputStream source)
public Scanner(File source) public Scanner(String source) креира објекат типа Scanner на основу задатог аргумента. public boolean hasNext(); враћа true ако постоји наредни токен на улазу. public String next(); проналази и враће цео наредни токен. Цео токен је окружен знацима раздвајања (и испред токена и иза њега су знаци за раздвајање). public boolean hasNext(String pattern); враће true ако наредни токен одговара обрасцу pattern. public String next(String pattern); враће наредни токен ако он одговара обрасцу pattern. public boolean hasNextLine(); враће true ако постоји следећа линија на улазу. public String nextLine(); враће остатак текуће линије искључујући ознаку за крај реда са њеног краја.
51
Класа Scanner (5) java.util.Scanner
public Scanner skip(String pattern); прескаче улаз који одговара обрасцу pattern, игноришући знаке за раздвајање.
52
Серијализација Серијализација је процес писања објеката у датотеку и читања објеката из датотеке. Поступак је веома једноставан. Неопходно је да класа објеката које треба писати у датотеку или читати из датотеке имплементира интерфејс Serializable. У већини случајева довољно је само декларисати да класа имплементира овај интерфејс и није неопходан никакав додатни код. Ситуација када то није довољно је када постоји директна или индиректна надкласа која не имплементира Serializable интерфејс. Тада та надкласа мора имати јавни подразумевани конструктор, а изведена класа се мора побринути о прослеђивању чланова базне класе у излазни ток.
53
Серијализација (2) Уколико постоје чланови тј. поља објекта који су референце на објекте неких других класа, те друге класе такође морају имплементирати интерфејс Serializable и онда ће се њихова серијализација вршити аутоматски. Писање објеката у фајл обавља се позивом метода writeObject за објекат типа ObjectOutputStream. При том треба предузети мере да се ухвате изузеци који могу бити избачени.
54
Серијализација (3) Пример.
Фрагмент кода који креира ObjectOutputStream објекат и пише објекат imenik типа HashMap<Osoba,Unos> у датотеку "C:\temp\Imenik.bin": try { ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( new File("C:/temp/Imenik.bin"))); out.writeObject(imenik); out.close(); } catch (IOException e) e.printStackTrace(); System.exit(1);
55
Серијализација (4) Следећи дијаграм показује објектни граф (лево) и начин на који ови објекти бивају серијализовани (десно).
56
Серијализација (5) Читање објеката из датотеке је подједнако једноставно као и писање у датотеку. Креира се ObjectInputStream објекат за читање из жељене датотеке, а потом се објекти из те датотеке читају позивима метода readObject. Такође као и код читања објеката, потребно је побринути се да се обраде изузеци који могу бити избачени. Метод readObject враћа референцу на прочитани објекат као вредност типа Object, па је неопходно извршити експлицитну конверзију (кастовање) у одговарајући тип објекта. Низови у Јави такође представљају објекте, па се правило о кастовању односи и на њих.
57
Серијализација (6) Пример.
Фрагмент кода који следи креира примерак класе ObjectInputStream и чита објекат типа HashMap<Osoba,Unos> из датотеке "C:\temp\Imenik.bin": try { ObjectInputStream in = new ObjectInputStream( new FileInputStream( new File("C:/temp/Imenik.bin"))); imenik = (HashMap<Osoba, Unos>) in.readObject(); in.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); System.exit(1); } catch (IOException e) { }
58
Напредна серијализација
Већ је истакнуто који услови који морају бити испуњени како би се серијализација објеката класе одвијала аутоматски: класа мора бити public; мора имплементирати интерфејс Serializable; ако има атрибуте који су класних типова, ти типови такође морају имплементирати Serializable интерфејс; наткласе морају имплементирати Serializable интерфејс; класе чланова морају имплементирати Serializable интерфејс; у случају да постоји наткласа која не имплементира Serializable интерфејс, она мора имати public подразумевани конструктор, а класа која се серијализује се мора побринути о прослеђивању чланица те наткласе у излазни ток.
59
Напредна серијализација (2)
Редак пример класе из Јава библиотечке класе која није серијабилна је класа Graphics из пакета java.awt. Ако класа има поља која нису серијабилна, или која не треба да буду уписана у излазни ток, могу се декларисати као transient. Пример. public class MyClass implements Serializable { transient protected Graphics g; // Transient class member // Rest of the class definition } Метод writeObject не покушава да упише transient чланове (обићно се називају пролазним члановима) у излазни ток. Када се објекат чита, он ће бити креиран исправно, укључујући и све чланове који су декларисани као transient, једино њихове вредности неће бити постављене јер нису ни биле уписане у ток. Ти чланови ће имати подразумеване вредности (null за објекте).
60
Напредна серијализација (3)
Типичан пример када се неку чланица проглашава да буде пролазна је када она нема значење на дуже стазе или ван контекста - нпр. текући датум или време. У том случају се мора: или обезбедити код за експлицитну реконструкцију пролазних чланица приликом читања објекта који их садржи или прихватити подразумеване вредности за њих.
61
Напредна серијализација (4)
У случају да је потребно да се преузме контрола над серијализацијом, неопходно је да се имплементирају два приватна метода у класи, један за читање објекта, а други за писање: // Serialized input method private void readObject(ObjectInputStream in) throws IOException { // Code to do the serialized input... } // Serialized output method private void writeObject(ObjectOutputStream out) throws IOException, ClassNotFoundException // Code to do the serialized output...
62
Напредна серијализација (5)
Методи морају имати исти потпис као у горњем фрагменту кода и морају бити декларисани као private. Њих ће позивати методи readObject и writeObject тока како би извршили неопходне улазно-излазне операције. Типично се користи подразумевана серијализацију и додаје се само код за поправку чланова о којима желимо да се побринемо (пролазни чланови), или о којима морамо да се побринемо (у случају несеријабилне базне класе). За извршавање подразумеване серијализације на улазу, позива се метод defaultReadObject: private void readObject(ObjectInputStream in) throws IOException { in.defaultReadObject(); // Default serialized input // Your code to do serialized input... }
63
Напредна серијализација (6)
Слично читању, код уписивања објекта за подразумевану серијализацију служи метод defaultWriteObject. Очигледно, подаци морају бити прочитани потпуно истим редоследом којим су писани, тако да ће методи readObject и writeObject имати симетричне операције над истом секвенцом података. Треба имати у виду да је, сходно Јава документацији, механизам серијализације првенствено намењен за краткотрајну перзистенцију података, а не за њихово дуготрајно чување.
64
Проблеми код серијализације
За већину класа и примена, серијализација тече праволинијски. Међутим, конфузија може настати приликом покушаја писања у фајл неколико верзија истог објекта. Наиме, процес серијализације прати који објекти су уписани у ток и сваки покушај поновног писања објекта не резултује стварним писањем дупликата објекта, већ се у ток уписује само руковалац (енг. handle), што је нека врста референце која указује на прву појаву објекта у току. Ако је заиста потребно да се упишу различите верзије истог објекта у датотеку, пре писања сваке нове верзије потребно је позвати метод reset за ток података тј. примерак класе ObjectOutputStream, којим се бришу информације о томе шта је претходно уписано.
65
Проблеми код серијализације (2)
Даље компликације настају када се дефиниција класе на неки начин промени између писања и читања објекта. Приликом писања објекта у датотеку, уписује се и информација која идентификује класу, тзв. идентификатор верзије, односно вредност статичког поља serialVersionUID. Ова информација служи како би се проверило да је дефиниција класе која се користи приликом читања објекта из датотеке компатибилна са оном која је коришћена приликом његовог уписа. Ако у класи није експлицитно дефинисана вредност овог статичког атрибута, компајлер је аутоматски додаје, а вредност рачуна на основу поља декларисаних у класи. Чак и козметичке промене између писања и читања, могу променити идентификатор верзије, због чега операција читања не успева, па долази до избацивања изузетка типа InvalidClassException.
66
Проблеми код серијализације (3)
Постоји могућност да се експлицитно зада вредност за serialVersionUID, чиме се добија већа контрола. Наиме, подразумевани начин генерисања идентификатора верзије је понекад превише строг. Понекад можда има потребе да се из неког разлога забрани десеријализација старих серијализованих објеката и у том случају се мора променити вредност статичког поља serialVersionUID у дефиницији класе. Неопходно је мењати serialVersionUID (нпр. увећати га за 1) сваки пут када се дефиниција класе промени тако да више није компатибилна са претходном.
67
Проблеми код серијализације (4)
Промене које доводе до некомпатибилности су: брисање поља када се објекат пише, неће садржати вредности обрисаних поља. По читању објеката претходном верзијом класе, вредност поља биће постављена на подразумевану, јер не постоји у току. Међутим, та подразумевана вредност може нарушити функционисање претходне верзије померање класе навише или наниже кроз хијерархију промена поља из нестатичког у статичко или поља које није било пролазно у пролазно поље еквивалентно брисању поља промена типа поља
68
Проблеми код серијализације (5)
Компатибилне промене су: додавање поља промена приступних атрибута поља (public, private...) промена поља из статичког у нестатичко или из пролазног да не буде више пролазно У комплекснијим ситуацијама, могуће је преузети потпуну контролу над поступком серијализације унутар датих класа имплементирањем интерфејса Externalizable. То је важно када дефиниција класе укључује промене током времена. Пажљивим програмирањем могуће је прилагодити модификације класе тако да постојећи серијализовани објекти могу и даље да се користе, што излази из оквира овог курса.
69
Захвалница Велики део материјала који је укључен у ову презентацију је преузет из презентације коју је раније (у време када је он држао курс Објектно орјентисано програмирање) направио проф. др Душан Тошић. Хвала проф. Тошићу што се сагласио са укључивањем тог материјала у садашњу презентацији, као и на помоћи коју ми је пружио током конципцирања и реализације курса. Надаље, један део материјала је преузет од колегинице Марије Милановић. Хвала Марији Милановић на помоћи у реализацији ове презентације.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.