Программирование на JAVA
Меню :
Стартовая
Основы программирования
Программирование на JAVA
Программирование на C++
Программирование на Pascal
Задачи по программированию
}
public void test() { int x=3; x=double(x);
}
Перейдем к ссылочным типам.
public void process(Point p) { p.x=3;
}
public void test() {
Point p = new Point(1,2);
process(p);
print(p.x);
}
Ссылочная переменная хранит ссылку на объект, находящийся в памяти виртуальной машины. Поэтому аргумент метода processo будет иметь в качестве значения ту же самую ссылку и, стало быть, ссылаться на тот же самый объект. Изменения состояния объекта, осуществленные с по-мошью одной ссылки, всегда видны при обращении к этому объекту с помощью другой. Поэтому результатом примера будет значение 3. Объектные значения передаются в Java по ссылке.
Однако если изменять не состояние объекта, а саму ссылку, то результат будет другим:
public void process(Point p) { p = new Point(4,5);
}
public void test() {
Point p = new Point(1,2);
process(p);
print(p.x);
}
В этом примере аргумент метода processo после присвоения начинает ссылаться на другой объект, нежели исходная переменная p, а значит, результатом примера станет значение 1. Можно сказать, что ссылочные величины передаются по значению, но значением является именно ссылка на объект.
Теперь можно уточнить, что означает возможность объявлять параметры методов и конструкторов как final. Поскольку изменения значений параметров (но не объектов, на которые они ссылаются) никак не сказываются на переменных вне метода, модификатор final говорит лишь о том, что значение этого параметра не будет меняться на протяжении работы метода. Разумеется, для аргумента final Point р выражение р.х=5 является допустимым (запрещается p=new Point(5, 5)).
Перегруженные методы
Перегруженными (overloading) методами называются методы одного класса с одинаковыми именами. Сигнатуры у них должны быть различными и различие может быть только в наборе аргументов.
Если в классе параметры перегруженных методов заметно различайся: например, у одного метода один параметр, у другого - два, то для ava это совершенно независимые методы и совпадение их имен может служить только для повышения наглядности работы класса. Каждый вы-3ов> в зависимости от количества параметров, однозначно адресуется то-МУ Или иному методу.
Однако если количество параметров одинаковое, а типы их различаются незначительно, при вызове может сложиться двойственная ситуация, когда несколько перегруженных методов одинаково хорошо подходят для использования. Например, если объявлены типы Parent и Child, где Child расширяет Parent, то для следующих двух методов:
void process(Parent р, Child с) {} void process(Child с, Parent p) {}
можно сказать, что они допустимы, их сигнатуры различаются. Однако при вызове
process(new Child(), new Child());
обнаруживается, что оба метода одинаково годятся для использования. Другой пример, методы:
process(Object о) {} process(String s) {}
и примеры вызовов:
process(new Objecto); process(new Point(4,5)); process("abc");
Очевидно, что для первых двух вызовов подходит только первый метод, и именно он будет вызван. Для последнего же вызова подходят оба перегруженных метода, однако класс String является более "специфичным", или узким, чем класс Object. Действительно, значения типа String можно передавать в качестве аргументов типа Object, обратное же неверно. Компилятор попытается отыскать наиболее специфичный метод, подходящий для указанных параметров, и вызовет именно его. Поэтому при третьем вызове будет использован второй метод.
Однако для предыдущего примера такой подход не дает однозначного ответа. Оба метода одинаково специфичны для указанного вызова, поэтому возникнет ошибка компиляции. Необходимо, используя явное приведение, указать компилятору, какой метод следует применить:
process((Parent)(new Child()), new Child()); // или
process(new Child(),(Parent)(new Child()));
Это верно и в случае использования значения null:
process((Parent)null, null); // или
process(null,(Parent)null);
Заключение
В этой лекции началось рассмотрение ключевой конструкции языка Java — объявление класса.
Первая тема посвящена средствам разграничения доступа. Главный вопрос — для чего этот механизм вводится в практически каждом современном языке высокого уровня. Необходимо понимать, что он предназначен не для обеспечения "безопасности" или "защиты" объекта от неких неправильных действий. Самая важная задача — разделить внешний интерфейс класса и детали его реализации с тем, чтобы в дальнейшем воспользоваться такими преимуществами ООП, как инкапсуляция и модульность.
Затем были рассмотрены все четыре модификатора доступа, а также возможность их применения для различных элементов языка. Проверка уровня доступа выполняется уже во время компиляции и запрещает лишь явное использование типов. Например, с ними все же можно работать через их более открытых наследников.
Объявление класса состоит из заголовка и тела класса. Формат заголовка был подробно описан. Для изучения тела класса необходимо вспомнить понятие элементов (members) класса. Ими могут быть поля, методы и внутренние типы. Для методов важным понятием является сигнатура.
Кроме того, в теле класса объявляются конструкторы и инициализаторы. Поскольку они не являются элементами, к ним нельзя обратиться явно, они вызываются самой виртуальной машиной. Также конструкторы и инициализаторы не передаются по наследству.
Дополнительно был рассмотрен метод main, который вызывается пРи старте виртуальной машины. Далее описываются тонкости, возникающие при передаче параметров, и связанный с этим вопрос о перегру-Женных методах.
Классы Java мы продолжим рассматривать в следующих лекциях.
Вариант 1
1. Какие модификаторы позволяют обращаться к элементу из классов того же пакета?
О public
О protected
|~1 по умолчанию
fjj private
2. Корректен ли следующий код? public class Test { private int id; public Test(int i) {
id=i;
}
public static boolean test(Test t, int id) { return t.id==id;
}
}
□ да, так как метод test является элементом класса Test
П нет, так как поле id объявлено как private, а значит недоступно извне объекта
3. Как записывается заголовок метода main?
G public int main()
П public int main(String[] args)
G public static void main(String[] args)
П public void main()
Вариант 2
1. Если в классе заводится новый элемент и пока нет никаких факторов, позволяющих выбрать тот или иной модификатор доступа, какой модификатор следует использовать?
О public
П protected
Г~! по умолчанию
□ private
2. Если метод использует переменную класса, должна ли она быть объявлена выше объявления метода?
□ да
□ нет
3. Может ли измениться содержимое переменной типа String, если передать ее в качестве аргумента при вызове метода?
□ да
□ нет
Вариант 3
1. Пусть класс User описывает пользователя системы. В качестве имени используется его e-mail адрес, который всем известен, а пароль, конечно, не должен быть доступен никому, кроме самого пользователя. Корректна ли следующая реализация?
public class User {
public String login; // e-mail private String password; // пароль
}
П код некорректен
f~| код корректен с точки зрения компилятора, но, скорее всего, неверен с позиций ООП; лучше ограничить доступ к переменной login с помощью метода getLogin(), чтобы значение переменной не могло измениться непредсказуемо
П код полностью верен
2. Может ли класс не иметь ни одного конструктора?
□ да О нет
3. Какие заголовки методов являются корректными с точки зрения компилятора?
П public void getX()
П static private int setY()
П public void static main (String s[])
П String toString(final int x)