JavaRush /Java блогу /Random-KY /Жаңы баштаган java программисттердин каталары. 2 бөлүк
articles
Деңгээл

Жаңы баштаган java программисттердин каталары. 2 бөлүк

Группада жарыяланган
Жаңы баштаган java программисттердин каталары. 1-бөлүк

9. main() методунан статикалык эмес класс методдорун чакыруу

Java программасынын кирүү чекити статикалык ыкма болушу керек main:
Жаңы баштаган java программисттердин каталары.  2-1-бөлүк
public static void main(String[] args) {
  ...
}
Бул ыкма статикалык болгондуктан, андан статикалык эмес класс методдорун чакыра албайсыз. Студенттер көбүнчө муну унутуп, класстын инстанциясын түзбөстөн методдорду чакырганга аракет кылышат. Бул ката көбүнчө окуунун эң башында, студенттер чакан программаларды жазганда кетирилет. Туура эмес мисал:
public class DivTest {
    boolean divisible(int x, int y) {
        return (x % y == 0);
    }

    public static void main(String[] args) {
        int v1 = 14;
        int v2 = 9;

        // на следующие строки компилятор выдаст ошибку
        if (divisible(v1, v2)) {
            System.out.println(v1 + " is a multiple of " + v2);
        } else {
            System.out.println(v2 + " does not divide " + v1);
        }
    }
}
Катаны оңдоонун 2 жолу бар: каалаган методду статикалык кылуу же класстын үлгүсүн түзүү. Туура ыкманы тандоо үчүн, метод талааны же класстын башка ыкмаларын колдонобу деп өзүңүздөн сураңыз. Эгер ооба болсо, анда класстын мисалын түзүп, ага методду чакырышыңыз керек, антпесе методду статикалык кылышыңыз керек. Оңдолгон мисал 1:
public class DivTest {
    int modulus;

    public DivTest(int m) {
      modulus = m;
    }

    boolean divisible(int x) {
        return (x % modulus == 0);
    }

    public static void main(String[] args) {
        int v1 = 14;
        int v2 = 9;

        DivTest tester = new DivTest(v2);

        if (tester.divisible(v1) {
            System.out.println(v1 + " is a multiple of " + v2);
        } else {
            System.out.println(v2 + " does not divide " + v1);
        }
    }
}
Оңдолгон мисал 2:
public class DivTest {
    static boolean divisible(int x, int y) {
        return (x % y == 0);
    }

    public static void main(String[] args) {
        int v1 = 14;
        int v2 = 9;

        if (divisible(v1, v2)) {
            System.out.println(v1 + " is a multiple of " + v2);
        } else {
            System.out.println(v2 + " does not divide " + v1);
        }
    }
}

10. String классынын an objectтерин методдун параметрлери катары колдонуу.

Java тorнде класс java.lang.Stringсаптык маалыматтарды сактайт. Бирок, Java тorндеги саптар
  1. туруктуулугу бар (башкача айтканда, аларды өзгөртүү мүмкүн эмес),
  2. an objectилер болуп саналат.
Ошондуктан, аларды жөн гана символдук буфер катары кароого болбойт; алар өзгөрүлгүс an objectтер. Кээде студенттер сап an objectиси шилтеме боюнча символдук массив катары өткөрүлөт деп жаңылыш күтүү менен саптарды өткөрүшөт (C же C++ тилдериндегидей). Компилятор муну адатта ката деп эсептебейт. Туура эмес мисал.
public static void main(String args[]) {
   String test1 = "Today is ";
   appendTodaysDate(test1);
   System.out.println(test1);
}

/* прим. редактора: закомментированный метод должен иметь модификатор
    static (здесь автором допущена ошибка №9)
public void appendTodaysDate(String line) {
    line = line + (new Date()).toString();
}
*/

public static void appendTodaysDate(String line) {
    line = line + (new Date()).toString();
}
Жогорудагы мисалда студент методдогу test1параметрге жаңы маани ыйгаруу менен локалдык өзгөрмөнүн маанисин өзгөрткүсү келет . Албетте, бул иштебейт. Мааниси өзгөрөт, бирок мааниси ошол бойдон калат. Бул ката (1) java an objectтери ар дайым шилтеме аркылуу өткөрүлөт жана (2) javaдагы саптар өзгөрүлгүс экенин түшүнбөстүктөн улам келип чыгат. Сап an objectтери эч качан өз маанисин өзгөртпөсүн жана саптардагы бардык операциялар жаңы an objectти түзөөрүн түшүнүшүңүз керек. Жогорудагы мисалдагы катаны оңдоо үчүн, ыкмадан сапты кайтарышыңыз керек, же an objectти параметр катары методго өткөрүү керек . Оңдолгон мисал 1:lineappendTodaysDatelinetest1StringBufferString
public static void main(String args[]) {
   String test1 = "Today is ";
   test1 = appendTodaysDate(test1);
   System.out.println(test1);
}

public static String appendTodaysDate(String line) {
    return (line + (new Date()).toString());
}
Оңдолгон мисал 2:
public static void main(String args[]) {
   StringBuffer test1 = new StringBuffer("Today is ");
   appendTodaysDate(test1);
   System.out.println(test1.toString());
}

public static void appendTodaysDate(StringBuffer line) {
    line.append((new Date()).toString());
}

болжол менен которуу
Чынында, ката эмне экенин түшүнүү оңой эмес. Объекттер шилтеме аркылуу берилгендиктен, ал lineошол эле жерге тиешелүү дегенди билдирет test1. Бул жаңысын түзүү менен lineбиз жаңысын түзөбүз дегенди билдирет.Туура test1эмес мисалда, баары өткөрүп берүү Stringшилтеме боюнча эмес, мааниси боюнча болуп көрүнөт.

11. Конструкторду метод катары жарыялоо

Javaдагы an object конструкторлору сырткы көрүнүшү боюнча кадимки методдорго окшош. Бир гана айырмачылыктар - конструктор кайтаруучу маанинин түрүн көрсөтпөйт жана аты класстын аталышы менен бирдей. Тилекке каршы, Java методдун аталышы класстын аталышы менен бирдей болууга мүмкүндүк берет. Төмөндөгү мисалда студент Vector listклассты түзүүдө класс талаасын инициализациялоону каалайт. Бул болбойт, анткени метод 'IntList'конструктор эмес. Туура эмес мисал.
public class IntList {
    Vector list;

    // Выглядит How конструктор, но на самом деле это метод
    public void IntList() {
        list = new Vector();
    }

    public append(int n) {
        list.addElement(new Integer(n));
    }
}
NullPointerExceptionКод талаага биринчи жолу киргенде өзгөчөлүктү жаратат list. Ката оңдоо оңой: сиз жөн гана методдун башындагы кайтаруу маанисин алып салышыңыз керек. Оңдолгон мисал:
public class IntList {
    Vector list;

    // Это конструктор
    public IntList() {
        list = new Vector();
    }

    public append(int n) {
        list.addElement(new Integer(n));
    }
}

12. Объектти керектүү түргө чыгарууну унутуп калдыңыз

Бардык башка an objectиге багытталган тилдер сыяктуу эле, Java тorнде an objectке анын суперклассы катары кайрыла аласыз. 'upcasting'Бул Java тorнде автоматтык түрдө аткарылат деп аталат . Бирок, эгерде өзгөрмө, класс талаасы же метод кайтаруу мааниси суперкласс катары жарыяланса, субкласстын талаалары жана ыкмалары көрүнбөйт. Субкласс деп аталат 'downcasting', сиз аны өзүңүз катташыңыз керек (б.а. an objectти керектүү класска алып келиңиз). Студенттер көбүнчө an objectти субклассификациялоону унутуп калышат. Бул көбүнчө an objectтердин массивдерин жана пакеттеги коллекцияларды колдонууда болот java.util( Жыйнактын алкагы дегенди билдирет ). Төмөндөгү мисал Stringan objectти массивге салып, андан кийин аны башка сап менен салыштыруу үчүн массивден алып салат. Компилятор катаны аныктайт жана cast түрү ачык көрсөтүлмөйүнчө codeду түзбөйт. Туура эмес мисал.
Object arr[] = new Object[10];
arr[0] = "m";
arr[1] = new Character('m');

String arg = args[0];
if (arr[0].compareTo(arg) < 0) {
    System.out.println(arg + " comes before " + arr[0]);
}
Типти кастингдин мааниси кээ бирөөлөр үчүн кыйын. Динамикалык ыкмалар өзгөчө көп кыйынчылыктарды жаратат. Жогорудагы мисалда, методдун equalsордуна колдонулган болсо compareTo, компилятор ката кетирмек эмес жана code туура иштемек, анткени equalsкласстын ыкмасы деп аталмак String. Сиз динамикалык шилтемеден башкача экенин түшүнүшүңүз керек downcasting. Оңдолгон мисал:
Object arr[] = new Object[10];
arr[0] = "m";
arr[1] = new Character('m');

String arg = args[0];
if ( ((String) arr[0]).compareTo(arg) < 0) {
    System.out.println(arg + " comes before " + arr[0]);
}

13. Интерфейстерди колдонуу.

Көптөгөн студенттер үчүн класстар менен интерфейстердин айырмасы так эмес. Ошондуктан, кээ бир студенттер интерфейстерди ишке ашырууга аракет кылышат, мисалы , Observerextensions ачкыч сөзүнRunnable колдонушат . Катаны оңдоо үчүн, сиз жөн гана ачкыч сөздү туурага тууралашыңыз керек. Туура эмес мисал:
public class SharkSim extends Runnable {
    float length;
    ...
}
Оңдолгон мисал:
public class SharkSim implements Runnable {
    float length;
    ...
}
Тиешелүү ката: блокторду кеңейтүү жана ишке ашыруунун туура эмес тартиби . Java спецификациясына ылайык, класс кеңейтүү декларациялары интерфейсти ишке ашыруу декларацияларынан мурун келиши керек. Ошондой эле, интерфейстер үчүн implements ачкыч сөзү бир гана жолу жазылышы керек; бир нече интерфейстер үтүр менен бөлүнгөн. Дагы бир нече ката мисалдар:
// Неправильный порядок
public class SharkSim implements Swimmer extends Animal {
    float length;
    ...
}

// ключевое слово implements встречается несколько раз
public class DiverSim implements Swimmer implements Runnable {
    int airLeft;
    ...
}
Оңдолгон мисалдар:
// Правильный порядок
public class SharkSim extends Animal implements Swimmer {
    float length;
    ...
}

// Несколько интерфейсов разделяются запятыми
public class DiverSim implements Swimmer, Runnable {
    int airLeft;
    ...
}

14. Суперкласс методунун кайтаруу маанисин колдонууну унутуп калдым

Java сизге ачкыч сөздү колдонуу менен субкласстан окшош суперкласс ыкмасын чакырууга мүмкүндүк берет. Кээде студенттер суперкласс ыкмаларын чакырышы керек, бирок көбүнчө кайтаруу маанисин колдонууну унутуп калышат. Бул, айрыкча, методдорду жана алардын кайтарым баалуулуктарын түшүнө элек студенттер арасында көп кездешет. Төмөндөгү мисалда студент toString()суперкласс ыкмасынын натыйжасын субкласс методунун натыйжасына киргизгиси келет toString(). Бирок, ал суперкласс ыкмасынын кайтаруу маанисин колдонбойт. Туура эмес мисал:
public class GraphicalRectangle extends Rectangle {
      Color fillColor;
      boolean beveled;
      ...
      public String toString() {
          super();
          return("color=" + fillColor + ", beveled=" + beveled);
      }
}
Катаны оңдоо үчүн, адатта, локалдык өзгөрмөгө кайтаруу маанисин ыйгаруу жетиштүү, андан кийин субкласс методунун натыйжасын эсептөөдө ошол өзгөрмөнү колдонуу керек. Оңдолгон мисал:
public class GraphicalRectangle extends Rectangle {
      Color fillColor;
      boolean beveled;
      ...
      public String toString() {
          String rectStr = super();
          return(rectStr + " - " +
         "color=" + fillColor + ", beveled=" + beveled);
      }
}

15. AWT компоненттерин кошууну унутуп калдым

AWT жөнөкөй GUI дизайн моделин колдонот: ар бир интерфейс компоненти алгач өзүнүн конструктору аркылуу түзүлүшү керек, андан кийин add()ата-энелик компонент ыкмасын колдонуу менен колдонмо терезесине жайгаштырылышы керек. Ошентип, AWT интерфейси иерархиялык түзүлүштү алат. Студенттер кээде бул 2 кадамды унутуп коюшат. Алар компонентти түзүшөт, бирок аны чоңойтуу терезесине коюуну унутушат. Бул компиляция стадиясында каталарды жаратпайт; компонент жөн гана колдонмо терезесинде көрүнбөйт. Туура эмес мисал.
public class TestFrame extends Frame implements ActionListener {
    public Button exit;

    public TestFrame() {
        super("Test Frame");
        exit = new Button("Quit");
    }
}
Бул катаны оңдоо үчүн, жөн гана алардын ата-энелерине компоненттерди кошуу керек. Төмөндөгү мисал муну кантип жасоону көрсөтөт. Белгилей кетчү нерсе, көп учурда колдонмо терезесине компонентти кошууну унуткан студент ошол компонентке окуя угуучуларды дайындоону да унутуп калат. Оңдолгон мисал:
public class TestFrame extends Frame implements ActionListener {
    public Button exit;

    public TestFrame() {
        super("Test Frame");

        exit = new Button("Quit");

        Panel controlPanel = new Panel();
        controlPanel.add(exit);

        add("Center", controlPanel);

        exit.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        System.exit(0);
    }
}

17. Агымды баштоону унутуп калдым

Java тorндеги көп агым java.lang.Thread. Жиптин жашоо цикли 4 этаптан турат: инициализацияланган, башталган, блоктолгон жана токтогон. Жаңы түзүлгөн жип инициализацияланган абалда. Аны иштеп жаткан абалга келтирүү үчүн, аны чакырышыңыз керек start(). Кээде студенттер жиптерди түзүшөт, бирок аларды баштоону унутуп калышат. Адатта ката студенттин параллелдүү программалоо жана көп агым боюнча бorми жетишсиз болгондо пайда болот. (болжол менен котормосу: Мен байланышты көрбөй жатам) Катаны оңдоо үчүн жипти башташыңыз керек. Төмөндөгү мисалда студент интерфейсти колдонуп сүрөттүн анимациясын түзгүсү келет Runnable, бирок жипти баштоону унутуп калыптыр. Туура эмес мисал
public class AnimCanvas extends Canvas implements Runnable {
        protected Thread myThread;
        public AnimCanvas() {
                myThread = new Thread(this);
        }

        // метод run() не будет вызван,
        // потому что поток не запущен.
        public void run() {
                for(int n = 0; n < 10000; n++) {
                   try {
                     Thread.sleep(100);
                   } catch (InterruptedException e) { }

                   animateStep(n);
                }
        }
        ...
}
Оңдолгон мисал:
public class AnimCanvas extends Canvas implements Runnable {
        static final int LIMIT = 10000;
        protected Thread myThread;

        public AnimCanvas() {
                myThread = new Thread(this);
                myThread.start();
        }

        public void run() {
                for(int n = 0; n < LIMIT; n++) {
                        try {
                          Thread.sleep(100);
                        } catch (InterruptedException e) { }

                        animateStep(n);
                }
        }
        ...
}
Жиптин жашоо цикли жана интерфейсти ишке ашырган жиптер менен класстардын ортосундагы байланыш RunnableJava программалоонун абдан маанилүү бөлүгү болуп саналат жана буга көңүл буруу пайдалуу болмок.

18. Java.io.DataInputStream классынын тыюу салынган readLine() ыкмасын колдонуу

Java 1.0 versionсында тексттин саптарын окуу үчүн readLine()класс ыкмасын колдонушуңуз керек болчу java.io.DataInputStream. Java versionсы 1.1 текст үчүн киргизүү/чыгаруу операцияларын камсыз кылуу үчүн I/O класстарынын бүтүндөй топтомун кошту: Readerжана Writer. Ошентип, 1.1 versionсынан тексттин бир сабын окуу үчүн readLine()класс ыкмасын колдонушуңуз керек java.io.BufferedReader. Студенттер бул өзгөрүүнү билбеши мүмкүн, айрыкча, алар эски китептерден окутулган болсо. (болжол менен котормосу: иш жүзүндө мындан ары актуалдуу эмес. Эми 10 жаштагы китептерди эч ким окуй алbyte). Эски ыкма readLine()ЖДКда сакталып калган, бирок мыйзамсыз деп жарыяланган, бул көбүнчө студенттерди чаташтырат. Сиз түшүнүшүңүз керек болгон нерсе, readLine()класстык ыкманы колдонуу java.io.DataInputStreamтуура эмес, жөн гана эскирген. Сиз классты колдонушуңуз керек BufferedReader. Туура эмес мисал:
public class LineReader {
    private DataInputStream dis;

    public LineReader(InputStream is) {
        dis = new DataInputStream(is);
    }

    public String getLine() {
        String ret = null;

        try {
          ret = dis.readLine();  // Неправильно! Запрещено.
        } catch (IOException ie) { }

        return ret;
    }
}
Оңдолгон мисал:
public class LineReader {
    private BufferedReader br;

    public LineReader(InputStream is) {
        br = new BufferedReader(new InputStreamReader(is));
    }

    public String getLine() {
        String ret = null;

        try {
          ret = br.readLine();
        } catch (IOException ie) { }

        return ret;
    }
}
1.0ден кийинки versionларда тыюу салынган башка ыкмалар бар, бирок бул эң кеңири таралганы.

19. Дубалды флот катары колдонуу

Көпчүлүк башка тилдер сыяктуу эле, Java калкылуучу чекиттик сандар (бөлчөк сандар) менен иштөөнү колдойт. Javaда калкыма чекиттүү сандар үчүн эки примитивдүү тип бар: doubleIEEE 64 биттик тактык жана floatIEEE 32 биттик тактык. 1.75, 12.9e17 же -0.00003 сыяктуу ондук сандарды колдонуудагы кыйынчылык - компилятор аларды терүүгө дайындайт double. Java тактыктын жоголушу мүмкүн болгон операцияларда типтеги таштарды аткарbyte. Бул түрдөгү кастинг программист тарабынан жасалышы керек. Мисалы, Java төмөндөгү мисалда көрсөтүлгөндөй, типтеги intөзгөрмөлөргө типтин маанисин ыйгарууга уруксат бербейт .byte
byte byteValue1 = 17; /* неправильно! */
byte byteValue2 = (byte)19; /* правильно */
Бөлчөк сандар түрү менен берилгендиктен doubleжана doubleтүрдөгү өзгөрмөгө ыйгаруу floatтактыкты жоготууга алып келиши мүмкүн, ошондуктан компилятор бөлчөк сандарды колдонуу аракетине нааразы болот float. Ошентип, төмөндөгү тапшырмаларды колдонуу класстын түзүлүшүнө жол бербейт.
float realValue1 = -1.7;          /* неправильно! */
float realValue2 = (float)(-1.9); /* правильно */
Бул тапшырма C же C++ тилдеринде иштемек, бирок Javaда бул бир топ катаал. Бул катадан кутулуунун 3 жолу бар. doubleСиз түрүн ордуна колдоно аласыз float. Бул эң жөнөкөй чечим. Чынында, 64-биттин ордуна 32-биттик арифметиканы колдонуунун мааниси аз; ылдамдыктагы айырма дагы деле JVM тарабынан жеп жатат (андан тышкары, заманбап процессорлордо бардык бөлчөк сандар 80-биттик процессордун форматына айландырылат. кандайдыр бир операциядан мурун катталуу). Аларды колдонуунун бирден-бир артыкчылыгы float- алар азыраак эстутумду ээлейт, бул көп сандагы бөлчөк өзгөрмөлөр менен иштөөдө пайдалуу. Сиз компиляторго номерди кантип сактоону айтуу үчүн сандын түрүн өзгөрткөнү колдоно аласыз. Түр үчүн өзгөрткүч float - 'f'. doubleОшентип, компилятор 1.75 түрүн , жана үчүн дайындайт 1.75f - float. Мисалы:
float realValue1 = 1.7;    /* неправильно! */
float realValue2 = 1.9f;   /* правильно */
Сиз ачык түрдөгү кастингди колдоно аласыз. doubleБул эң аз элеганттуу жол, бирок ал түр өзгөрмөсүн түргө айландырганда пайдалуу float. Мисал:
float realValue1 = 1.7f;
double realValue2 = 1.9;
realValue1 = (float)realValue2;
Сиз калкыма чекиттер тууралуу кененирээк бул жерден жана бул жерден окуй аласыз.

-- котормочунун комментарийи --
Болду.
10-мисалыда 9 ката кетирилген.Мен аны дароо байкадым, бирок эскертүү жазууну унутуп калыпмын. бирок баштапкы булак менен эч кандай карама-каршылыктар болбошу үчүн аны оңдогон эмес.

Author: A.Grasoff™ Булакка шилтеме: Жаңы баштаган Java программисттеринин каталары
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION