Основы программирования на языке Java Средства ООП Java (С) Всеволод Рылов, все права защищены Новосибирск, 2004 1 Ключевые слова – статус Ключевые слова, которые уже известны на текущий момент: abstractdefault do double else extends if implements import instanceof int private protected public return short this boolean throw break throws byte transient case try catch char class final finally float interface long native static strictfp super void volatile while const goto for package new synchronized switch continue Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 2 Виды переменных переменные классов (class variable - переменная-член объявленная static ) переменные экземпляра (instance variable – переменная-член класса объявленная без static) компоненты массивов: int ia[] = new int[3]; ia[0] параметры методов: void doSome(int i, Object o) {…} параметры конструкторов: MyClass(Object param) {…} параметры перехватчиков исключений: catch(Exception ex) {…} локальные переменные, объявленные внутри методов, блоков, и в операторе for Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 3 Модификатор final Переменная объявленная final может быть проинициализирована ровно один раз, после этого ее значение изменить нельзя. Если ссылка объявлена с модификатором final, то это не значит, что нельзя изменить состояние объекта на который она ссылается! Нельзя изменить лишь саму переменную ссылочного типа. void unflow(boolean flag) { final int k; if (flag) { k = 3; System.out.println(k); } else { k = 4; System.out.println(k); } } // all ok Новосибирск, 2004 void unflow(boolean flag) { final int k; if (flag) { k = 3; System.out.println(k); } if (!flag) { k = 4; System.out.println(k); } } //compile-time error! (С) Всеволод Рылов, все права защищены 4 Объекты и значения ссылочного типа Объекты - экземпляры классов (class instance) и массивы. ClassInstanceCreationExpression: new ClassOrInterfaceType ( ArgumentListopt ) ClassBodyopt Primary.new Identifier ( ArgumentListopt ) ClassBodyopt ArgumentList: Expression ArgumentList , Expression //Создание объектов – экземпляров классов class MyClass implements MyInterface {…} MyClass myObj = new MyClass(); MyInterface anotherObj = new MyClass(“parameter”); MyClass reflObj = (MyClass)Class.forName(“MyClass”).newInstance(); Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 5 Операции над ссылками доступ к полю: obj.x = 10; super.y = 20; вызов метода: obj.doSome(); super.doAnother(); преобразование типа: (Object)obj строковый оператор + : String s = “one” + obj; //вызывается метод obj.toString(); оператор проверки типа instanceof: if (obj instanceof MyClass) {…} //Проверяется тип obj операторы сравнения ссылок == и !=: if (obj == obj2 && obj != obj3) {…} условный тернарный оператор ? : obj = ( obj2.size() < obj3.size() ) ? obj2: obj3; Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 6 Объекты – массивы: грамматика ArrayCreationExpression: new PrimitiveType DimExprs Dimsopt new TypeName DimExprs Dimsopt new PrimitiveType Dims ArrayInitializer new TypeName Dims ArrayInitializer DimExpr: [ Expression ] Dims: [] Dims [ ] DimExprs: DimExpr DimExprs DimExpr Индексация элементов массива начинается с 0 а не с 1 !!! Диапазон допустимых значений индекса – от 0 до length - 1 Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 7 Создание и инициализация массивов // Создание массивов примеры: // Создание объекта – массива из трех ссылок на объекты типа MyClass MyClass array[] = new MyClass[3]; // Инициализация элемента массива (ссылки): array[0] = new MyClass(); // Создание объекта – массива из двух ссылок на объекты-массивы //ссылок на объекты класса MyClass MyClass array2[][] = new MyClass[2][]; // Инициализация элементов 0 и 1 массива array2 array2[0] = new MyClass[5]; //объект – массив из 5 ссылок array2[1] = new MyClass[4]; //объект – массив из 4 ссылок // Объект - массив из трех элементов типа int int array3[] = new int[3]; array3[0] = 0; // Создание и инициализация массива из четырех элементов int int array4 [] = new int [] {1,2,3,4}; // Создание и инициализация объекта-массива ссылок на объекты //класса MyClass MyClass array5[] = {new MyClass(“a”), new MyClass(“b”)}; Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 8 Особенности использования массивов Члены объектов-массивов: public final int length это поле содержит длину массива public Object clone() – создает копию массива + все методы класса Object. Любой массив можно привести к классу Object или к массиву совместимого типа. class Test { public static void main(String[] args) throws Throwable { int ia[][] = { { 1 , 2}, null }; int ja[][] = (int[][]) ia.clone(); System.out.print( (ia == ja) + " "); System.out.println(ia[0] == ja[0] && ia[1] == ja[1]); } } // this program prints: false true Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 9 Особенности использования массивов class Point { int x, y; } class ColoredPoint extends Point { int color; } class Test { public static void main(String[] args) { ColoredPoint[] cpa = new ColoredPoint[10]; Point[] pa = cpa; System.out.println(pa[1] == null); try { pa[0] = new Point(); } catch (ArrayStoreException e) { System.out.println(e); } } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 10 Классы Классы объявляют новый ссылочный тип и определяют его реализацию Вложенный (nested) класс – это класс объявленный внутри другого класса или интерфейса (в том числе класс объявленный внутри метода или блока): member class – объявленный внутри класса local class – объявленный внутри метода anonymous class – не имеющий имени Верхнеуровневый (top-level) класс – это класс, не являющийся вложенным Именованные (named) классы могут быть абстрактными Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 11 Классы Каждый класс кроме Object является наследником другого класса и может реализовывать (implements) произвольное количество интерфейсов Тело класса может содержать: члены (members): поля методы вложенные классы и интерфейсы инициализаторы экземпляра статические инициализаторы конструкторы Видимость членов и конструкторов регулируется модификаторами доступа public, private, protected Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 12 Классы и наследование Членами класса являются унаследованные и определенные в классе члены Вновь объявленные поля могут скрывать поля суперклассов и суперинтерфейсов Вновь объявленные методы могут скрывать, реализовывать или перегружать методы, объявленные в суперклассе или суперинтерфейсе Вложенные классы бывают статическими и внутренними (inner), в зависимости от контекста в котором они объявлены (если в точке объявления имеет смысл ссылка this – то вложенный класс будет внутренним) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 13 Методы Методы описывают участки кода, которые могут быть вызваны с помощью выражения вызова метода Метод класса исполняется в контексте переменных класса (static context) Метод экземпляра исполняется в контексте конкретного объекта, доступного по this Методы не имеющие реализации должны быть объявлены abstract Допускается перегрузка методов по списку и типам аргументов Метод может иметь платформенно-зависимую реализацию (native method) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 14 Статический контекст public class MyClass MyClass.s == 10 { Static data private int a,b; private static int s =10; public MyClass(int arg1, int arg2) { a = arg1; b = arg2; } public void changeA(int v) { a = v; } public static void changeS(int v) { s = v; } public static void main(String args[]) { MyClass mc1 = new MyClass(2,3); MyClass mc2 = new MyClass(4,5); mc1.changeA(100); mc2.changeA(200); MyClass.changeS(25) ; mc1.changeS(30); mc2.changeS(40); MyClass.s == 40 } Static data } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены :MyClass a == 2 b == 3 :MyClass a == 4 b == 5 HEAP :MyClass a == 100 b == 3 :MyClass a == 200 b == 5 HEAP 15 Конструкторы и инициализаторы Инициализаторы экземпляра – блоки кода {…} выполняемые при инициализации объекта. Выполняются перед вызовом конструктора. Статические инициализаторы – статические блоки кода static {…} выполняемые при первом использовании класса (после его загрузки но перед созданием первого объекта или доступом к полю) Конструкторы в отличие от методов не могут быть вызваны непосредственно с помощью выражения вызова метода. Конструкторы вызываются при создании экземпляров объектов и могут быть перегружены Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 16 Грамматика объявления класса ClassDeclaration: ClassModifiersopt class Identifier Superopt Interfacesopt ClassBody ClassModifiers: ClassModifier ClassModifiers ClassModifier ClassModifier: one of public protected private abstract static final strictfp Super: //Определяет «прямой суперкласс» extends ClassType Interfaces: //Определяет «прямые суперинтерфейсы» implements InterfaceTypeList InterfaceTypeList: InterfaceType InterfaceTypeList , InterfaceType Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 17 Пример объявления класса public abstract class MyClass extends Parent implements MyInterface, AnotherInterface { static { //Static initializer } { //Non static initializer } public MyClass() { super(); //Вызов конструктора супер класса } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 18 Модификаторы объявления класса public – класс доступен извне пакета. abstract – класс является абстрактным (в нем есть абстрактные методы) final – класс является конечным в иерархии наследования. От него нельзя унаследовать другой класс strictfp – для всех методов класса действуют правила строгой проверки арифметических выражений во время вычислений Для вложенных(внутренних) классов дополнительно действуют следующие модификаторы: static – класс является статическим (вложенный класс) protected – к классу имеют доступ только классы наследники объемлющего класса или классы в том же пакете private – к классу имеет доступ только объемлющий класс Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 19 Строгое определение абстрактного класса Класс C является абстрактным, если: C явно содержит объявление абстрактного метода Какой-либо класс-родитель C содержит объявление абстрактного метода, который не был реализован в классе C или в его родительских классах «Прямой суперинтерфейс» C определяет или наследует метод, который не реализован (и поэтому является абстрактным) т.е. ни C ни его родительские классы не определяют реализацию этого метода Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 20 Внутренние (inner) классы Внутренний (inner) класс – это класс который ни явно, ни неявно не является static Внутренний класс не может содержать блоков статической инициализации или членов-интерфейсов Внутренний класс не может содержать статических членов за исключением полей-констант времени компиляции Внутренние классы могут наследовать статические члены, не являющиеся константами времени компиляции Члены-интерфейсы всегда являются static по умолчанию Вложенные классы могут свободно содержать статические члены как и обычные классы Java Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 21 Пример вложенности классов class HasStatic { static int j = 100; } class Outer { class Inner extends HasStatic { static final int x = 3; //ok - compile-time constant static int y = 4; //compile-time error, an inner class } static class NestedButNotInner{ static int z = 5; // ok, not an inner class } interface NeverInner{} // interfaces are never inner } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 22 Статический контекст Выражение находится в статическом контексте, тогда и только тогда, когда наиглубочайший включающий его метод, конструктор, блок инициализации или инициализатор поля является статическим методом, статическим инициализатором или инициализатором статической переменной соответсвенно. Проще говоря, если в точке объявления класса имеет семантику ссылка this на объект объемлющего класса, то контекст объявления является динамическим (non static) и класс будет внутренним. Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 23 Immediately enclosing instance Внутренний класс C является непосредственным внутренним классом (direct inner class of) класса O если O непосредственно лексически включает класс C, и декларация C не находится в статическом контексте. Класс C является внутренним классом (inner class) класса O если это непосредственный внутренний класс класса O либо является внутренним классом внутреннего класса O. Класс O является лексически объемлющим классом порядка 0 (zeroth enclosing class of itself) для самого себя. Класс O является лексически объемлющим классом порядка n (nth lexically enclosing class) класса C если он является непосредственным объемлющим классом для лексически объемлющего класса порядка n – 1 класса C. Экземпляр объекта i непосредственного внутреннего класса C класса O всегда связан с объектом класса O, известным как непосредственно объемлющий объект для i (the immediately enclosing instance of i). Непосредственно объемлющий объект, если таковой имеется, связывается с объектом при его создании. Объект o является лексически объемлющим объектом порядка 0 (zeroth lexically enclosing instance) самого себя. Объект o является лексически объемлющим объектом порядка n для объекта i, если он является непосредственно объемлющим объектом для лексически объемлющего объекта порядка n – 1 объекта i. Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 24 Immediately enclosing instance Анологично, если суперкласс S класса C является непосредственным внутренним классом класса SO, то существует экземпляр SO, связанный с объектом i класса C, известный как непосредственно объемлющий экземпляр по отношению к S (the immediately enclosing instance of i with respect to S). Непосредственно объемлющий экземпляр объекта по отношению к его прямому суперклассу, если таковой имеет место быть, определяется в момент вызова конструктора суперкласса посредством вызова конструктора суперкласса по умолчанию. Когда внутренний класс ссылается на переменную экземпляра являющуюся членом лексически объемлющего класса, используется переменная (поле) соответствующего лексически объемлющего объекта. Неинициализированное final поле объемлющего класса не может быть использовано в контексте внутреннего класса. Любая локальная переменная, формальный параметр метода, или параметр перехватчика исключения используемые во внутреннем классе, но объявленные в объемлющем, должны быть объявлены со спецификатором final, и должны быть явно проинициализированы до их использования в теле внутреннего класса. Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 25 Пример – ограничение доступа class Outer { int i = 100; static void classMethod() { final int l = 200; class LocalInStaticContext { int k = i; // compile-time error int m = l; // ok } } void foo() { class Local { // a local class int j = i; } } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 26 Пример – глубокая вложенность class WithDeepNesting { boolean toBe; WithDeepNesting(boolean b) { toBe = b;} class Nested { boolean theQuestion; class DeeplyNested { DeeplyNested(){ theQuestion = toBe || !toBe; } } } } Каждый экземпляр WithDeepNesting.Nested.DeeplyNested имеет объемлющий объект класса WithDeepNesting.Nested (его непосредственно объемлющий объект) и объемлющий объект – экземпляр класса WithDeepNesting (объемлющий объект ранга 2). Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 27 Суперклассы и подклассы Класс C является суперклассом класса A если верно одно из следующих утверждений: A является непосредственным подклассом C. Существует класс B такой , что A является подклассом B, и B является подклассом C, применяя это правило рекурсивно. class Point { int x, y; } class ColoredPoint extends Point { int color; } final class Colored3dPoint extends ColoredPoint { int z; } Класс Point является суперклассом класса ColoredPoint. Класс Point является суперклассом класса Colored3dPoint. Класс ColoredPoint является подклассом класса Point. Класс ColoredPoint является суперклассом класса Colored3dPoint. Класс Colored3dPoint является подклассом класса ColoredPoint. Класс Colored3dPoint является подклассом класса Point. Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 28 Зависимость между классами Классы и интерфейсы зависят по загрузке от других типов (классов и интерфейсов), приведенных в декларации наследования (extends и implements) Зависимость типов друг от друга может формировать цепочку: A зависит от B, B зависит от C тогда A зависит от C. class B implements C {…} class A extends B {…} … A theA = new A(); // Будут загружены интерфейс C и //классы B и A Циклические зависимости вызывают ошибку времени компиляции: class Point extends ColoredPoint { int x, y; } class ColoredPoint extends Point { int color; } Если цикл обнаружен во время исполнения программы и загрузки классов в JVM, то выбрасывается ошибка ClassCircularityError Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 29 Суперинтерфейсы класса Суперинтерфейсами (родительскими интерфейсами) для класса являются: Прямые суперинтерфейсы (объявленные implements) Суперинтерфейсы прямых суперинтерфейсов Суперинтерфесы родительского класса Говорят, что класс реализует все свои суперинтерфейсы У класса может быть несколько прямых суперинтерфейсов: interface One { void doIt();} interface Two { void doIt(); void doAnother();} class MyClass implements One, Two { void doIt() {} //Общая реализация для One и Two void doAnother{} } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 30 Грамматика объявления тела класса ClassBody: { ClassBodyDeclarationsopt } ClassBodyDeclarations: ClassBodyDeclaration ClassBodyDeclarations ClassBodyDeclaration ClassBodyDeclaration: ClassMemberDeclaration InstanceInitializer StaticInitializer ConstructorDeclaration ClassMemberDeclaration: FieldDeclaration MethodDeclaration ClassDeclaration InterfaceDeclaration ; Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 31 Члены класса Областью видимости члена m, объявленного или унаследованного классом C, является тело класса C, включая тела всех типов объявленных внутри C. Если C сам по себе является вложенным классом, то объявления одноименных членов (полей, методов или типов) m в объемлющих областях видимости (блоках, классах или пакете) будут сокрыты данным членом m класса С. Членами класса являются: Члены, унаследованные от его прямого суперкласса (исключением является класс Object не имеющий суперклассов) Члены, унаследованные от его прямых суперинтерфейсов Члены, объявленные в теле класса Члены класса объявленные private не наследуются подклассами. Конструкторы и инициализаторы не являются членами и не наследуются Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 32 Пример наследования членов class Point { int x, y; private Point() { reset(); } Point(int x, int y) { this.x = x; this.y = y; } private void reset() { this.x = 0; this.y = 0; } } class ColoredPoint extends Point { int color; void clear() { reset(); } // error – reset() is private } //error: ColoredPoint() {super();} – default constructor class Test { public static void main(String[] args) { ColoredPoint c = new ColoredPoint(0,0);//error – //ColoredPoint has no such constructor c.reset(); //error – reset() is private } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 33 Наследование и доступ по умолчанию package points; public class Point { int x, y; public void move(int dx, int dy) { x += dx; y += dy; } } import points.*; class Point4D extends Point3D { int w; public void move(int dx, int dy, int dz, int dw) { x+=dx; y+=dy; z+=dz; //error! w+=dw; } } Новосибирск, 2004 package points; public class Point3D extends Point { int z; public void move(int dx, int dy, int dz) { x += dx; y += dy; z += dz; } } import points.*; class Point4D extends Point3D { int w; public void move(int dx, int dy, int dz, int dw) { super.move(dx,dy,dz); //Good! w+=dw; } } (С) Всеволод Рылов, все права защищены 34 Поля-члены класса (грамматика) FieldDeclaration: FieldModifiersopt Type VariableDeclarators ; VariableDeclarators: VariableDeclarator VariableDeclarators , VariableDeclarator FieldModifiers: FieldModifier FieldModifiers FieldModifier FieldModifier: one of public protected private static final transient volatile Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 35 Статические поля class Point { int x, y, useCount; Point(int x, int y) { this.x = x; this.y = y; } final static Point origin = new Point(0, 0); } class Test { public static void main(String[] args) { Point p = new Point(1,1); Point q = new Point(2,2); p.x = 3; p.y = 3; p.useCount++; p.origin.useCount++; System.out.println("(" + q.x + "," + q.y + ")"); System.out.println(q.useCount); System.out.println(q.origin == Point.origin); System.out.println(q.origin.useCount); } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 36 Singleton (объект одиночка) Данный шаблон используется для обеспечение единственности объекта определенного класса public class Singleton { private static Singleton instance = null; private Singleton(){} //никто не может вызвать конструктор //все должны использовать данный метод для получения объекта public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 37 Поля-члены, объявленные final Переменные классов(static) и переменные экземпляров могут быть объявлены final Статическая переменная, объявленная final должна быть инициализирована непосредственно при объявлении либо в блоке статической инициализации Переменная экземпляра, объявленная final должна быть проинициализирована непосредственно при объявлении либо в блоке инициализации, либо ей должно быть присвоено значение к концу исполнения каждого конструктора Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 38 Модификаторы volatile и transient Переменные, объявленные transient не являются частью persistent состояния объекта и не сохраняются во время сериализации. Для переменных, объявленных volatile, осуществляется синхронизация локальной и главной копий при каждом обращении к значению переменной в многопоточной среде. class Test { static int i = 0, j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } // может напечатать j } // большее, чем i Новосибирск, 2004 class Test { static volatile int i = 0, j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } // i всегда >= j !!! } (С) Всеволод Рылов, все права защищены 39 Инициализация полей Инициализация полей экземпляра происходит каждый раз при создании нового объекта. Инициализация статических полей класса происходит один раз при первом использовании класса. При инициализации поля экземпляра могут использовать статические поля, т.к. они гарантированно инициализированы к моменту создания объекта При инициализации статические поля класса не могут использовать поля экземпляра, а также ключевые слова this и super Инициализация полей происходит в порядке объявления и в порядке исполнения блоков инициализации. Константы времени компиляции инициализируются первыми. Код конструкторов исполняется в последнюю очередь Стоит избегать зависимости от порядка инициализации полей Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 40 Разрешение перекрытия полей class Point { static int x = 2; } class Test extends Point { static double x = 4.7; public static void main(String[] args) { new Test().printX(); } void printX() { System.out.println(x + " " + super.x); } } Для доступа к полям, перекрытым при наследовании можно использовать super, а также полную квалификацию (super.x или Point.x) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 41 Множественное перекрытие interface Frob { float v = 2.0f; } class SuperTest { int v = 3; } class Test extends SuperTest implements Frob { public static void main(String[] args) { new Test().printV(); } void printV() { System.out.println((super.v + Frob.v)/2); } } При множественном перекрытии необходимо использовать полную квалификацию Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 42 Грамматика объявления метода Метод определяет участок исполняемого кода, который может быть вызван с передачей фиксированного количества параметров определенного типа MethodDeclaration: MethodHeader MethodBody MethodHeader: MethodModifiersopt ResultType MethodDeclarator Throwsopt ResultType: Type void MethodDeclarator: Identifer ( FormalParameterListopt ) В классе может быть объявлен метод, имя которого совпадает с именем члена-поля, вложенного класса, интерфейса или другого метода (стоит избегать!!!) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 43 Сигнатура метода Методы класса должны различаться по своей сигнатуре. Сигнатура метода определяется его именем, количеством параметров и типами этих параметров FormalParameterList: FormalParameter FormalParameterList , FormalParameter FormalParameter: finalopt Type VariableDeclaratorId VariableDeclaratorId: Identifier VariableDeclaratorId [ ] Имена параметров метода должны быть различны Список формальных параметров метода может быть пуст Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 44 Параметры метода Во время вызова метода вычисленные значения передаваемых аргументов используются для инициализации переменныхпараметров метода Таким образом всегда имеет место передача «по значению» Область видимости параметра ограничивается методом, в котором он объявлен. При этом доступ к нему осуществляется с помощью обычного имени. Параметры перекрывают собой поля-члены класса, в котором объявлен метод, содержащий эти параметры. Для доступа к перекрытым полям-членам нужно использовать this либо полное квалифицированное имя Параметры типов double и float всегда содержат значения из множества double и float соответственно. Они не могут принимать расширенных значений появляющихся во время вычисления выражений не являющихся strictfp Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 45 Модификаторы метода MethodModifiers: MethodModifier MethodModifiers MethodModifier MethodModifier: one of public protected private abstract static final synchronized native strictfp Запрещенные комбинации: два из public, protected, private abstract с любым из: private, static, final, native, strictfp, synchronized native strictfp Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 46 Абстрактные методы Абстрактный метод определяет сигнатуру и список выбрасываемых исключений для метода, который должен быть реализован ниже по иерархии наследования Абстрактный класс может перегружать метод, оставляя (или делая) его абстрактным и сохраняя его сигнатуру. При этом может измениться список выбрасываемых исключений. class BufferEmpty extends Exception {…} class BufferError extends Exception {…} public interface Buffer { char get() throws BufferEmpty, BufferError; } public abstract class InfiniteBuffer implements Buffer { abstract char get() throws BufferError; } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 47 Осторожность при перегрузке abstract class Point { int x, y; public abstract String toString(); } class ColoredPoint extends Point { int color; public String toString() { //ошибка – вызов абстрактного метода: return super.toString() + ": color " + color; } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 48 Модификаторы метода (продолжение) В статическом методе не может использоваться ссылка this Ссылки super и this могут использоваться только в методах объекта (т.е. методах, не объявленных static) Метод, объявленный final, не может быть перегружен в классахнаследниках. Никакой метод класса, объявленного final не может быть перегружен (так как такой класс не может иметь наследников) и, таким образом, все его методы являются final По своей сути метод, объявленный private является final Компилятор или оптимизатор могут использовать «inline» подстановку для final и private методов, тем самым увеличивая скорость исполнения программы Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 49 Модификаторы метода (продолжение) native методы используются для реализации их тела в платформенно-зависимой библиотеке, написанной на языке C, C++, Fortran и т.д. пример: файл производного доступа package java.io; public class RandomAccessFile implements DataOutput, DataInput { ... public native void open(String name, boolean writeable) throws IOException; public native int readBytes(byte[] b, int off, int len) throws IOException; public native void writeBytes(byte[] b, int off, int len) throws IOException; public native long getFilePointer() throws IOException; public native void seek(long pos) throws IOException; public native long length() throws IOException; public native void close() throws IOException; } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 50 Модификаторы метода (окончание) synchronized методы используются для реализации синхронных классов-серверов (Параллелизм: класс-сервер может быть последовательным, защищенным или синхронным) strictfp определяет метод, в котором все вычисляемые выражения float и double будут FP-strict. Это значит, что все промежуточные результаты вычисления выражения будут являться элементами множества float и double языка java и не могут принадлежать к расширенному набору float или double, которые может предоставлять конкретная платформа для обеспечения высокой точности вычисления выражений с плавающей точкой. При этом всегда будет происходит приведение промежуточного результата к элементу множества float или double, либо возникнет переполнение. Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 51 Выбрасываемые исключения Список throws определяет исключения, которые должны обрабатываться при вызове метода (checked exceptions) Throws: throws ClassTypeList ClassTypeList: ClassType ClassTypeList , ClassType Класс, объявленный в списке throws должен быть наследником класса Throwable или самим классом Throwable Классы-наследники RuntimeException можно не объявлять в списке throws Классы-наследники Error используются для сигнализации о сбое машины и не должны использоваться в прикладном коде Метод, перегружающий метод родительского класса или реализующий метод интерфейса не может «расширять» список throws (may not be declared to throw more checked exceptions) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 52 Тело метода MethodBody: Block ; Метод, не объявленный как abstract или native должен иметь тело, являющееся блоком Метод, объявленный void не может содержать оператор вида return Expression; Метод, объявленный с возвращаемым типом Type должен содержать выражение вида return Expression; на каждой возможной ветви завершения метода. При этом тип результата вычисления выражения Expression должен быть совместимым с типом Type В случае, если возможная ветвь метода завершается явным выбросом исключения, выражение return Expression; может быть опущено Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 53 Перегрузка методов (Overriding) Перегрузка методов экземпляра (не статических методов): Метод m1 класса C перегружает метод m2 класса A с той же сигнатурой, тогда и только тогда, когда: Класс C является наследником класса A либо m2 не является private и доступен из C m1 перегружает m3, который перегружает m2 и отличен от m1 и m2 Если m1 не является abstract, то говорят что он реализует абстрактные методы, которые перегружает. Для доступа к перегруженному методу используется super Приведение к типу суперкласса содержащего объявление перегруженного метода не обеспечивает вызов этого метода (виртуальный полиморфизм) в отличие от обеспечения доступа к сокрытым переменным static, private, final методы не могут быть перегружены Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 54 Сокрытие методов (Hiding) Если класс декларирует статический метод, то этот метод скрывает методы с той же сигнатурой объявленные в его суперклассах Для доступа к сокрытому методу можно использовать выражение со словом super, либо квалифицированное имя, либо приведение к типу класса в котором этот метод объявлен. В этом случае сокрытые методы ведут себя также как и сокрытые поля Статический метод не может скрывать метод экземпляра (не являющийся статическим) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 55 Требования к перегрузке и сокрытию Перегружаемые и скрываемые методы должны совпадать не только по сигнатуре но и по возвращаемому значению Перегружающий или перекрывающий метод должен иметь такой же, либо более открытый уровень доступа: public -> public protected -> protected, public package(default) -> package(default), protected, public private методы не наследуются и не перегружаются поэтому могут иметь совпадающую сигнатуру, но разные возвращаемые значения и не совместимые списки throws на разных уровнях абстракции Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 56 Наследование нескольких методов с одинаковой сигнатурой Наследование нескольких методов с одинаковой сигнатурой не всегда приводит к ошибке. При этом возможны следующие варианты: Если один из методов не является абстрактным, то: Если этот метод static то возникает ошибка времени компиляции Иначе этот метод реализует (implements) или перегружает все унаследованные методы. Если при этом выявляется несовместимость по возвращаемому значению или списку исключений, то возникает ошибка времени компиляции Если метод абстрактный, то и класс является абстрактным и при этом говорят что данный метод перегружает все унаследованные методы. При этом также проверяется совместимость по возвращаемому значению и списку выбрасываемых исключений В языке java не может возникнуть ситуация, когда два из наследуемых методов с одинаковой сигнатурой не являются абстрактными (т.к. одиночное наследование) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 57 Overloading, Overriding, and Hiding class Point { int x = 0, y = 0; int color; void move(int dx, int dy) { x += dx; y += dy; } } class RealPoint extends Point { float x = 0.0f, y = 0.0f; // hiding x and y // overriding move void move(int dx, int dy) { move((float)dx, (float)dy); } //overloading move void move(float dx, float dy) { x += dx; y += dy; } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 58 Некорректное перекрытие class Point { int x = 0, y = 0, color; void move(int dx, int dy) { x += dx; y += dy; } int getX() { return x; } int getY() { return y; } } class RealPoint extends Point { float x = 0.0f, y = 0.0f; void move(int dx, int dy) { move((float)dx, (float)dy); } void move(float dx, float dy) { x += dx; y += dy; } float getX() { return x; } float getY() { return y; } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 59 Вызов перегруженных методов class Super { static String greeting() { return "Goodnight"; } String name() { return "Richard"; } } class Sub extends Super { static String greeting() { return "Hello"; } String name() { return "Dick"; } } class Test { public static void main(String[] args) { Super s = new Sub(); System.out.println(s.greeting() + ", " +s.name() ); } } produces the output: Goodnight, Dick Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 60 Несоответствие списков исключений class BadPointException extends Exception { BadPointException() { super(); } BadPointException(String s) { super(s); } } class Point { int x, y; void move(int dx, int dy) { x += dx; y += dy; } } class CheckedPoint extends Point { void move(int dx, int dy) throws BadPointException { if ((x + dx) < 0 || (y + dy) < 0) throw new BadPointException(); x += dx; y += dy; } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 61 Интерфейсы InterfaceDeclaration: InterfaceModifiersopt interface Identifier ExtendsInterfacesopt InterfaceBody InterfaceModifiers: InterfaceModifier InterfaceModifiers InterfaceModifier InterfaceModifier: one of public protected private abstract static strictfp Допустимо множественное наследование интерфейсов: ExtendsInterfaces: extends InterfaceType ExtendsInterfaces , InterfaceType Все интерфейсы являются abstract protected, static, private относятся только к членаминтерфейсам Глобальные (не вложенные) интерфейсы являются public Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 62 Отношение наследования Интерфейс I напрямую зависит от типа T если T присутствует в списке extends интерфейса I как родительский интерфейс, либо как квалификатор в имени родительского интерфейса. Интерфейс I зависит от ссылочного типа T если выполняется одно из условий: I напрямую зависит от T. I напрямую зависит от класса C который зависит от T. I напрямую зависит от интерфейса J который зависит от T (применяя правило рекурсивно). Интерфейс K является родительским (суперинтерфейсом) интерфейса I если выполняется одно из условий: K является прямым суперинтерфейсом I. Существует интерфейс J такой что K является суперинтерфейсом J, и J является суперинтерфейсом I, применяя это правило рекурсивно Интерфейс I называется подинтерфейсом (subinterface) интерфейса K, если K является суперинтерфейсом I. Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 63 Тело и члены интерфейса InterfaceBody: { InterfaceMemberDeclarationsopt } InterfaceMemberDeclarations: InterfaceMemberDeclaration InterfaceMemberDeclarations InterfaceMemberDeclaration InterfaceMemberDeclaration: ConstantDeclaration AbstractMethodDeclaration ClassDeclaration InterfaceDeclaration ; Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 64 Члены интерфейса Членами интерфейса являются: Члены, объявленные в интерфейсе Члены унаследованные от прямых суперинтерфейсов Если у интерфейса нет прямых суперинтерфейсов, то интерфейс по умолчанию (неявно) декларирует public abstract метод m сигнатуры s, возвращаемого типа r, и списка исключенийt для каждого public instance метода m сигнатуры s, возвращаемого типа r, и списка исключений t, объявленного в классе Object, кроме таковых объявленных явно в этом интерфейсе. Если интерфейс декларирует метод с той же сигнатурой, но с отличным типом возвращаемого значения либо несовместимым списком исключений то будет ошибка компиляции. Интерфейс наследует от интерфейсов, которые расширяет (extends) всех членов этих интерфейсов за исключением полей, классов, интерфейсов которые он скрывает(hides) и методов, которые перегружает(overrides). Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 65 Константные поля интерфейсов ConstantDeclaration: ConstantModifiersopt Type VariableDeclarators ConstantModifiers: ConstantModifier ConstantModifiers ConstantModifer ConstantModifier: one of public static final Фактически все поля интерфейса являются public static final константами. Декларация данных спецификаторов является избыточной. В случае если интерфейс унаследует два и более поля с одинаковыми именами от своих суперинтерфейсов, ошибка времени компиляции будет иметь место только при попытке обращения к этим полям по простому имени (без полной квалификации). Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 66 Инициализация полей интерфейсов Каждое поле в теле интерфейса должно быть проинициализировано выражением, значение которого должно быть вычислено на стадии компиляции. При этом возможно использование в выражении уже проинициализированных полей самого интерфейса или его суперинтерфейсов. Поля инициализируются в порядке их декларации за исключением полей, явно инициализируемых константами. В выражениях инициализации нельзя использовать ключевые слова this и super кроме случая если эти слова используются внутри декларации тела анонимного класса реализующего интерфейс. interface float f int j = int k = } Test { = j; //error – j используется до объявления 1; k+1; //error – k инициализируется с использованием k Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 67 Неоднозначность при наследовании interface BaseColors { int RED = 1, GREEN = 2, BLUE = 4; } interface RainbowColors extends BaseColors { int YELLOW = 3, ORANGE = 5, INDIGO = 6, VIOLET = 7; } interface PrintColors extends BaseColors { int YELLOW = 8, CYAN = 16, MAGENTA = 32; } interface LotsOfColors extends RainbowColors, PrintColors { int FUCHSIA = 17, VERMILION = 43, CHARTREUSE = RED+90; } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 68 Декларация абстрактных методов AbstractMethodDeclaration: AbstractMethodModifiersopt ResultType MethodDeclarator Throwsopt ; AbstractMethodModifiers: AbstractMethodModifier AbstractMethodModifiers AbstractMethodModifier AbstractMethodModifier: one of public abstract Фактически все методы интерфейса являются public abstract, и использование данных спецификаторов является избыточным Будьте осторожны при наследовании интерфейсом от своих суперинтерфейсов методов с одинаковой сигнатурой но несовместимыми возвращаемыми значениями или throws clauses Все члены-классы и члены-интерфейсы, объявленные в интерфейсе, являются static public по умолчанию и не могут быть внутренними (inner) Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 69 Анонимные классы public interface MyInterface { void doIt(); } public abstract class MyAbstractClass { int i,j; public MyAbstractClass (int i, int j) { this.i = i; this.j = j;} public abstract void doAnother(); } //Использование: … MyInterface impl = new MyInterface() { void doIt() { System.out.println(“Hello!”); } }; impl.doIt(); Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 70 public class Main { public static void main(String[] args) { MyInterface myInterfaceImpl = new MyInterface () { public void doIt () { System.out.println("Hello!"); } }; myInterfaceImpl.doIt();//prints: Hello! MyAbstractClass myAbstractImpl = new MyAbstractClass() { public void doAnother() { System.out.println("Hello again! "+i+" "+j); } }; MyAbstractClass myAbstractImpl2 = new MyAbstractClass(5,6) { public void doAnother() { System.out.println("Hello again! "+i+" "+j); } }; myAbstractImpl.doAnother(); //prints: Hello again! 0 0 myAbstractImpl2.doAnother(); //prints: Hello again! 5 6 } } 71 Новосибирск, 2004 (С) Всеволод Рылов, все права защищены Перечисления (enum), начиная с java 1.5 В отличие от статических констант, предоставляют типизированный, безопасный способ задания фиксированных наборов значений Являются классами специального вида, не могут иметь наследников, сами в свою очередь наследуются от java.lang.Enum. Не могут быть абстрактными и содержать абстрактные методы, но могут реализовывать интерфейсы Экземпляры объектов перечисления нельзя создать с помощью new, каждый объект перечисления уникален, создается при загрузке перечисления в виртуальную машину, поэтому допустимо сравнение ссылок для объектов перечислений, можно использовать switch Как и обычные классы могут реализовывать поведение, содержать вложенные и внутренние классы-члены Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 72 Пример public enum Days { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; public boolean isWeekend() { switch(this) { case SUNDAY: case SATURDAY: return true; default: return false; } } } … System.out.println( Days.MODAY+” isWeekEnd(): “ + Days.MONDAY.isWeekend() ); Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 73 Перечисления (продолжение) Каждый класс перечисления неявно содержит следующие методы: values() - возвращает массив элементов перечисления (статический метод) ordinal() - возвращает порядковый номер элемента перечисления (в порядке декларации) valueOf(String name) – возвращает элемент перечисления по его строковому имени (статический метод, выбрасывает IllegalArgumentException если нет элемента с указанным именем) Класс перечисления может иметь конструктор (private либо package), который вызывается для каждого элемента при его декларации Отдельные элементы перечисления могут реализовывать свое собственное поведение Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 74 Пример более сложного перечисления public enum Direction { FORWARD(1.0) { public Direction opposite() {return BACKWARD;} }, BACKWARD(2.0) { public Direction opposite() {return FORWARD;} }; private double ratio; Direction(double r) { ratio = r; } public double getRatio() {return ratio;} public static Direction byRatio(double r) { if (r == 1.0) return FORWARD; else if (r == 2.0) return BACKWARD; else throw new IllegalArgumentException(); } } Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 75 Пакеты: организация java программ В типичном случае программа состоит из нескольких пакетов Каждый пакет имеет собственное пространство имен для типов объявленных в пакете Верхнеуровневый тип доступен извне пакета только если он объявлен со спецификатором public Пакеты образуют иерархическую структуру имен. Членами пакета являются: классы и интерфейсы, объявленные в единицах компиляции пакета подпакеты, которые имеют свои собственные подпакеты и единицы компиляции Пакеты могут располагаться на файловой системе или в базе данных Пакеты размещаемые на файловой системе имеют ряд ограничений на их организацию для обеспечения однозначности при поиске и загрузке (а также компиляции) типов (и единиц компиляции) и пакета Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 76 Пакеты: организация программ com.somecompany.project one subpackage First.java: public class First {...} class Cls {...} another Third.java Second.java Filesystem: /com /somecompany /project /one First.java First.class Cls.class Second.java Second.class /subpackage /another Third.java Third.class При отображении (хранении) на файловой системе единица компиляции может содержать тоьлко один тип объявленный public совпадающий по имени с именем файла единицы компиляции Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 77 Единицы компиляции Пакет содержит несколько единиц компиляции Типы внутри единицы компиляции имеют доступ ко всем верхнеуровневым типам, объявленным в других единицах компиляции данного пакета а также к типам пакета java.lang Для доступа к другим пакетам используется декларация import CompilationUnit: PackageDeclarationopt ImportDeclarationsopt TypeDeclarationsopt ImportDeclarations: ImportDeclaration ImportDeclarations ImportDeclaration TypeDeclarations: TypeDeclaration TypeDeclarations TypeDeclaration Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 78 Именованные и безымянные пакеты Объявление именованного пакета: PackageDeclaration: package PackageName; В качестве имени пакета выступает полное квалифицированное имя: например com.somecompany.project.one для First.java Единицы компиляции безымянного пакета не содержат объявление пакета Безымянные пакеты следует использовать только в небольших тестовых программах Переменная окружения CLASSPATH содержит точки привязки иерархий пакетов к точкам в файловой системе (коими могут являться директории и архивные jar или zip файлы) Классы находящиеся во всех «корневых» директориях точек привязки CLASSPATH принадлежат к единому безымянному пакету Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 79 Декларация import Декларация имени пакета распространяется на всю единицу компиляции Декларации import также распространяются на всю единицу компиляции Для того чтобы получить доступ к членам подпакета в единице компиляции, нужно явно импортировать эти члены. По умолчанию они не видны ImportDeclaration: SingleTypeImportDeclaration TypeImportOnDemandDeclaration import java.io.InputStream; // single type import declaration import java.net.*; // import on demand declaration Будучи импортированными типы становятся доступны в единице компиляции с использованием простого (не квалифицированного) имени. Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 80 Статический импорт (начиная с java 1.5) Для того чтобы иметь возможность обращаться к статическим методам, полям класса, а также к элементам перечислений без использования квалифицированного имени, можно воспользоваться статической декларацией импорта: import static Days.* ; import static java.lang.Math.*; … Day d = MONDAY; Day d2 = valueOf(“SATURDAY”); double v = sin(PI/2); Однако злоупотреблять статическим импортом не стоит Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 81 Сокрытие и конфликты import single-type-import декларация d в единице компиляции c пакета p импортирующая тип n, скрывает: любой верхнеуровневый тип n, объявленный в другой единице компиляции пакета p любой тип n импортированный type-imoprt-on-demand декларацией в c нельзя импортировать пакет, можно импортировать только типы: import java.util; - ведет к ошибке времени компиляции верхнеуровневые типы объявленные внутри единицы компиляции, а также вложенные типы скрывают типы, импортируемые typeimport-on-demand декларацией, при использовании простого имени. для разрешения неоднозначности или доступа к сокрытому типу можно воспользоваться квалифицированным именем Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 82 «Странный» пример package Vector; public class Mosquito { int capacity; } package strange.example; import java.util.Vector; import Vector.Mosquito; class Test { public static void main(String[] args){ System.out.println(new Vector().getClass()); System.out.println(new Mosquito().getClass()); } } Вывод: class java.util.Vector class Vector.Mosquito Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 83 Двойная декларация package test; import java.util.Vector; class Point { int x, y; } interface Point { // compile-time error #1 int getR(); int getTheta(); } class Vector { // compile-time error #2 Point[] pts; } --------------------------------------------------package test; import java.util.*; class Vector { Point[] pts; } // not a error Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 84 Опережающее использование package points; class Point { int x, y; // coordinates PointColor color; // color of this point Point next; // next point with this color static int nPoints; } class PointColor { Point first; // first point with this color PointColor(int color) { this.color = color; } private int color; // color components } //all is OK! Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 85 Правила именования пакетов Для обеспечения уникальности имени пакета в качестве основы следует использовать доменное имя организации, например: ru.nsu.fit.mylastname.task1 В случае если доменное имя не может быть использовано в силу наличия специальных символов, запрещенных к использованию в идентификаторах, нужно произвести следующую трансформацию: если имя содержит знак ‘-’, его заменяют на ‘_’: some-ware.com -> com.some_ware если имя является ключевым словом, то к нему добавляют ‘_’: do.something.com -> com.something.do_; если имя начинается с цифры, то спереди добавляется ‘_’: just.4you.com -> com._4you.just Примеры имен: com.sun.java.jag.scrabble com.apple.quicktime.v2 com.novosoft.siberon.someproject Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 86 Полное квалифицированное имя Полным квалифицированным именем является: для примитивных типов – ключевое слово типа для именованного пакета первого уровня – простое имя этого пакета для именованного пакета уровня N – полное квалифицированное имя объемлющего пакета плюс простое имя пакета: outer1.outer2.outerN-1.packagename для класса или интерфейса в безымянном пакете – простое имя этого класса или интерфейса полное квалифицированное имя класса или интерфейса в именованном пакете – это полное квалифицированное имя пакета плюс простое имя класса или интерфейса: outerpackage1...outerpackageN-1.packagename.ClassName Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 87 Полное квалифицированное имя класс (интерфейс) – член другого класса имеет полное квалифицированное имя только если таковое имеется у класса его содержащего: outerpackage1.….outerpackageN.OuterClass1.….OuterClassM.Member исключение – безымянные классы Полное квалифицированное имя массива – это полное квалифицированное имя компонентного типа с последующим [] Примеры полностью квалифицированных имен: java.lang.Object java.util.Map.Entry int java.lang.String[] Новосибирск, 2004 (С) Всеволод Рылов, все права защищены 88