admin / 02.03.2018

Java — Классы и объекты / ProgLang

Ключевое слово static

Иногда требуется определить член класса, который будет использоваться независимо от любого объекта этого класса. И его можно использовать самостоятельно без ссылки на конкретный экземпляр. Для создания подобного члена класса, нужно в начало его объявления перед объявлением типа поместить ключевое слово static. В этом случае он становится доступен до создания каких-либо объектов его класса и без ссылки на какой-либо объект. Статическими могут быть и переменные и методы.

По существу переменные экземпляров, объявленные как static, являются глобальными переменными. При объявлении объектов их класса программа не создаёт никаких копий статической переменной. Вместо этого все экземпляры класса совместно используют одну и ту же статическую переменную.

У статических методов есть ряд ограничений:

  • они могут вызывать только другие статические методы
  • они могут непосредственно осуществлять доступ только к статическим переменным
  • они не могут ссылаться на члены типа this или super

В большинстве случаев среда разработки или компилятор заметят ошибку программиста и выведут предупреждение о неправильном использовании переменных.

Например, нельзя писать такой код.

В статическом методе main() мы пытаемся задействовать нестатическую переменную number.

Также следите, чтобы не объявлять статическую переменную в статическом методе — так тоже нельзя.

Если для инициализации статических переменных требуется произвести вычисления, то для этой цели можно объявить статический блок, который будет выполняться только один раз при первой загрузки класса.

Создадим класс, который будет содержать статические переменные, статический метод и статический блок

За пределами класса, в котором они определены, статические методы и переменные могут использоваться независимо от какого-либо объекта. Для этого достаточно указать имя класса, затем точку, а потом имя метода или переменной:

имя_класса.метод() имя_класса.переменная

В Android имеются много статических методов и переменных. Например, метод Log.i(). Так как метод является статическим, мы не объявляем Log log = new Log(). Достаточно сразу вызвать метод.

Также часто используется статический метод ToastmakeText().

Статическая переменная

Чтобы лучше уяснить механизм работы статической переменной, напишем следующий пример. Создадим класс Cat.

Мы создали две статические переменные. Одну не трогаем, а вторую увеличиваем на единицу в конструкторе.

Переходим в класс активности и проверяем, чему равны эти переменные.

Программа вернёт значения, которые мы сами установили — 0 и 8. Обратите внимание, чтоб мы даже не создавали экземпляры класса, а обращались напрямую к классу.

А теперь создадим двух котов с именами и возрастом. А между котами явно увеличим одну статическую переменную. И снова проверим значения статических переменных.

Получим результат.

Первые два значения понятны из предыдущего примера. Затем при создании первого кота, переменная sId автоматически увеличивается на единицу. Вторая переменная остаётся без изменений.

Затем мы явно указываем новое значение для второй переменной, и создаём второго кота, у которого также сработает увеличение на единицу первой переменной. Проверка убедит нас в этом. Было 1 и 8, стало 2 и 15.

Вариант с автоматическим увеличением иногда используют для создания уникального идентификатора объекта, например, товара в магазине. Заводя новый товар, мы автоматически получаем его новый номер, используя статическую переменную.

Реклама

Статья проплачена кошками — всемирно известными производителями котят.

Если статья вам понравилась, то можете поддержать проект.

.

Ключевое слово static

Initialize a CollectionTag(s): Language

The regular way

import java.util.List; import java.util.ArrayList; public class InitCollections { public static void main(String args[]) { ArrayList<String> list = new ArrayList<String>(); list.add(«Bart»); list.add(«Lisa»); list.add(«Marge»); list.add(«Barney»); list.add(«Homer»); list.add(«Maggie»); dump(list); } public static void dump(List<String> list) { for (String s:list) { System.out.println(s); } } }

Using a static initializer

import java.util.List; import java.util.ArrayList; public class InitCollections { static ArrayList<String> list = new ArrayList<String>(); static { list.add(«Bart»); list.add(«Lisa»); list.add(«Marge»); list.add(«Barney»); list.add(«Homer»); list.add(«Maggie»); } public static void main(String args[]) { dump(list); } public static void dump(List<String> list) { for (String s:list) { System.out.println(s); } } }

Using the Double Brace Initialization.
Careful with this one because it can cause memory leak.

import java.util.List; import java.util.ArrayList; public class InitCollections { static ArrayList<String> list = new ArrayList<String>() {{ add(«Bart»); add(«Lisa»); add(«Marge»); add(«Barney»); add(«Homer»); add(«Maggie»); }}; public static void main(String args[]) { dump(list); } public static void dump(List<String> list) { for (String s:list) { System.out.println(s); } } }

Use Arrays.asList()

import java.util.List; import java.util.Arrays; public class InitCollections { public static void main(String args[]) { List

Using Static import

First a small static class

package com.rgagnon.howto; import java.util.Arrays; import java.util.List; public class CollectionUtils { public static <T> List<T> List(T…elems){ return Arrays.asList( elems ); } }

then

package com.rgagnon.howto; import static com.rgagnon.howto.CollectionUtils.List; import java.util.List; public class InitCollections { public static void main(String args[]) { List<String> list = List(«Bart», «Lisa», «Marge», «Homer», «Maggie»); dump(list); } public static void dump(List<String> list) { for (String s:list) { System.out.println(s); } } }



Важно различать инициализацию класса и инициализацию объекта.

Инициализация класса

Класс или интерфейс инициализируется после первого доступа, назначая поля постоянной времени компиляции, а затем рекурсивно инициализируя суперкласс (если он еще не инициализирован), затем обработка статических инициализаторов (которые включают инициализаторы для статических полей, которые не являются константами времени компиляции).

Как вы заметили, инициализация класса сама по себе не инициирует инициализацию интерфейсов, которые она реализует. Поэтому интерфейсы инициализируются при первом обращении к ним, как правило, путем чтения поля, которое не является постоянной времени компиляции. Этот доступ может возникать при оценке инициализатора, вызывая рекурсивную инициализацию.

Также стоит отметить, что инициализация не запускается путем доступа к полям, которые являются константами времени компиляции, поскольку они оцениваются в время компиляции:

Ссылка на поле, которое является постоянной переменной (§4.12.4), должно быть разрешено во время компиляции до значения V, обозначенного инициализатором постоянной переменной.

Если такое поле является статическим, тогда никакая ссылка на поле не должна присутствовать в коде в двоичном файле, включая класс или интерфейс, которые объявили это поле. Такое поле всегда должно быть инициализировано (§12.4.2); начальное значение по умолчанию для поля (если оно отличается от V) никогда не должно наблюдаться.

Если такое поле не статично, то никакая ссылка на поле не должна присутствовать в коде двоичного файла, кроме класса, содержащего это поле. (Это будет класс, а не интерфейс, поскольку интерфейс имеет только статические поля.) Класс должен иметь код для установки значения поля V во время создания экземпляра (§12.5).

Инициализация объектов

Объект инициализируется всякий раз, когда создается новый объект, как правило, путем оценки выражения создания экземпляра класса.

Модификаторы в Java: static, final, abstract, synchronized, transient, volatile.

Это происходит следующим образом:

  • Назначьте аргументы конструктора новым созданным переменным параметра для этого вызова конструктора.

  • Если этот конструктор начинается с явного вызова конструктора (§8.8.7.1) другого конструктора в том же классе (с использованием этого), то затем оценивайте аргументы и обрабатывайте вызов конструктора рекурсивно, используя эти пять шагов. Если вызов конструктора завершается внезапно, то эта процедура завершается внезапно по той же причине; в противном случае перейдите к шагу 5.

  • Этот конструктор не начинается с явного вызова конструктора другого конструктора в том же классе (используя это). Если этот конструктор относится к классу, отличному от Object, то этот конструктор начнет с явного или неявного вызова конструктора суперкласса (используя super). Оцените аргументы и обработайте вызов конструктора суперкласса рекурсивно, используя эти пять шагов. Если вызов конструктора завершается внезапно, то эта процедура завершается внезапно по той же причине. В противном случае перейдите к шагу 4.

  • Выполните инициализаторы экземпляра и инициализаторы переменных экземпляра для этого класса, присваивая значения инициализаторов переменной экземпляра соответствующим переменным экземпляра в порядке слева направо, в котором они отображаются в текстовом виде в исходном коде для класс. Если выполнение любого из этих инициализаторов приводит к исключению, то никакие новые инициализаторы не обрабатываются, и эта процедура завершается внезапно с тем же исключением. В противном случае перейдите к шагу 5.

  • Выполните оставшуюся часть тела этого конструктора. Если это выполнение завершается внезапно, то эта процедура завершается внезапно по той же причине. В противном случае эта процедура выполняется нормально.

Как мы видим на шаге 3, наличие явного вызова супер-конструктора просто изменяет конструкцию суперкласса.

ответ дан meriton 16 апр. '14 в 0:27

источникподелиться

Описатели ограничения доступа

Такие элементы языка Java как класс , поле и метод имеют ограничения доступа . Т.е. для них можно указать, где они будут доступны, а где нет.

Для описания ограничений доступа используются ключевые слова public , private , protected . Они являются опциональными описателями и дают нам три варианта ограничений доступа плюс четвертый вариант, если не указан не один из этих описателей.

  • public — означает, что данный элемент доступен без каких-либо ограничений;
  • private — доступ разрешен только из данного класса;
  • protected — доступ разрешен из данного класса и из всех классов-потомков(это связано с наследованием классов, которое мы будем рассматривать позже), а также из всех классов данного пакета(что такое пакеты мы также будем рассматривать позже).
  • без описателя — доступ разрешен из всех классов данного пакета.

Для классов применим только один описатель — public. Кроме того, классы могут не иметь никакого описателя ограничения доступа.

Как мы уже рассматривали на 1-м занятии, каждый java-файл должен содержать класс с именем этого файла, а каждый public-класс должен быть в java-файле с именем этого класса. Классы без описателя public могут быть в любом java-файле.

Для полей и методов применимы все 4 варианта ограничения доступа.

Мы, наконец, дошли до некоторой «критической массы» и можем написать несколько примеров программ так, что не все в этих программах будет непонятно. Отдельные элементы этих примеров, которые выходят за рамки изученного материала, мы рассмотрим с содержательной стороны, т.е. разберемся, что они делают, не вдаваясь в подробности, что за понятия в них использованы.

Один из таких элементов — это вывод результатов. Он выглядит так

System.out.println( < то, что нужно напечатать> );

В скобках можно задать текст или переменную или выражение. Подробнее мы рассмотрим это на конкретных примерах.

Пример (файл XUser.java)

// Это простой демонстрационный пример // Два класса X и XUser взаимодействуют друг с другом class X { public int x = 0; // В классе X одно поле void f(int y) { x = y; } } public class XUser { void f() { int n = 6; // Переменная n X x1 = new X(); X x2 = new X(); x1.x = 5; x1.f(n); x2.f(2); System.out.println(«Поле x из x1: «+ x1.x); System.out.println(«Поле x из x2: «+ x2.x); } public static void main(String args[]) { XUser ref = new XUser(); ref.f(); } }

  • Трансляция j.bat XUser.java
  • Запуск jr.bat XUser
  • Результат работы Поле x из x1: 6 Поле x из x2: 2

Для того, чтобы разобраться, в примере достаточно проследить всю цепочку его выполнения шаг за шагом, начиная от метода main. В заключение обратим внимание на строки

System.out.println(«Поле x из x1: «+ x1.x); System.out.println(«Поле x из x2: «+ x2.x);

Параметром в данной конструкции является строка. Но для строк, как мы рассмотрим позднее, определена операция сложения строк друг с другом, с целыми и вещественными числами и даже с объектами.

Возврат значения в методе класса

Для возврата значения из метода класса используется оператор return вида

return < выражение>;

Например,

int f(int a, int b) { return a+b; // возвращает сумму двух аргументов данного метода }

Как мы уже рассматривали, тип возвращаемого значения указывается в заголовке метода перед его именем. Тип выражения в операторе return должен соответствовать типу возвращаемого значения.

Ключевое слово this

Разберемся подробнее с вызовом метода. Мы рассматривали, что вызов метода всегда производится для некоторого объекта. При этом внутри метода можно обращаться к полям класса, не указывая объект.

Это реализуется путем передачи скрытого параметра — ссылки на тот объект, для которого вызван данный метод. Всегда, когда мы пишем обращение к полю или методу того же класса, что и сам данный метод, неявно подставляется этот скрытый параметр. В некоторых случаях требуется обратиться к этому параметру явно. Такая возможность предусмотрена. Для этого в языке определено ключевое слово this .

Например,

class A { private int size = 0; public void setSize(int size) { this.size = size; } . . . }

Этот пример демонстрирует, как можно реализовать установку значения private-поля класса, т.е. поля, которое недоступно напрямую извне класса. Для этого в классе реализован открытый (public) метод setSize(…). В этом методе имя параметра совпадает с именем поля класса (size). Такое в Java разрешено, более того, это является общепринятым стилем. Но совпадение имен заставляет нас писать слово this с точкой перед именем поля (внутри метода имя size обозначает параметр, а не поле).

Мы рассмотрели базовые возможности языка, реализующие концепцию объектно-ориентированного программирования. Естественно, что это только «вершина айсберга».

Практическое задание

Рассмотрим программу Proba1.java.

public class Proba1 { public static void main(String args[]) { Oper op = new Oper(); op.a = 6; op.b = 7; System.out.println(«Сумма=» + op.sum()); System.out.println(«Разность=» + op.dif()); } }

Это незаконченная программа. Разберем ее построчно, определим, что означает каждый оператор.

В программе используется класс Oper, который не реализован. Задача состоит в реализации этого класса. В частности, нужно определить

1. В каком файле разместить этот класс. 2. Какие поля должен содержать этот класс. 3. Какие методы должны быть в нем реализованы.

В заключение оттранслируем и запустим эту программу.

Статические поля и методы класса

Мы уже встречались в программах с описателем static в конструкции «public static void main(String args[])». Пора разобраться с тем, что он означает.

В Java есть статические поля и статические методы. Для указания того, что поле или метод являются статическими, используется описатель static перед именем типа поля или метода. Например,

class SomeClass { static int t = 0; // статическое поле . . . public static void f() { // статический метод . . . } }

Для поля описатель static означает, что такое поле создается в единственном экземпляре вне зависимости от количества объектов данного класса. Статическое поле существует даже в том случае, если не создано ни одного экземпляра класса. Статические поля класса размещаются VM Java отдельно от объектов класса в некоторой области памяти в момент первого обращения к данному классу.

Рассмотрим это на примере (файл Proba2.java)

// Демонстрация статических полей класса public class Proba2 { int a = 10; // обычное поле static int cnt = 0; // статическое поле public void print() { System.out.println(«cnt=» + cnt); System.out.println(«a=» + a); } public static void main(String args[]) { Proba2 obj1 = new Proba2(); cnt++; // увеличим cnt на 1 obj1.print(); Proba2 obj2 = new Proba2(); cnt++; // увеличим cnt на 1 obj2.a = 0; obj1.print(); obj2.print(); } }

В данном примере поле cnt является статическим. При печати обоих объектов в конце метода main (…) будет отпечатано одно и то же значение поля cnt . Это объясняется тем, что оно присутствует в одном экземпляре.

По аналогии со статическими полями, статические методы не привязаны к конкретному объекту класса. При вызове статического метода перед ним можно указать не ссылку, а имя класса. Например,

class SomeClass { static int t = 0; // статическое поле . . . public static void f() { // статический метод . . . } } . .

Ключевое слово static в Java

. SomeClass.f(); . . .

Поскольку статический метод не связан с каким либо объектом, внутри такого метода нельзя обращаться к нестатическим полям класса без указания объекта перед именем поля. К статическим полям класса такой метод может обращаться свободно.

Это легко продемонстрировать на примере Proba2.java. Попробуем описать метод print(…) как статический. При трансляции измененной программы мы получим сообщение об ошибке в строке

System.out.println(«a=» + a);

Действительно, здесь идет обращение к нестатическому полю a и, поскольку метод print(…) является статическим, то неизвестно к какому объекту относится это поле.

Если мы хотим сделать метод print(…) статическим (что, в общем-то, не соответствует общим принципам построения объектно-ориентированных программ), то мы должны определить в нем параметр типа Proba2 и использовать его для доступа к полю a .

Перепишем этот пример (файл Proba3.java)

// Демонстрация статических полей и методов класса public class Proba3 { int a = 10; // обычное поле static int cnt = 0; // статическое поле public static void print(Proba3 obj) { System.out.println(«cnt=» + cnt); System.out.println(«a=» + obj.a); } public static void main(String args[]) { Proba3 obj1 = new Proba3(); cnt++; // увеличим cnt на 1 Proba3.print(obj1); Proba3 obj2 = new Proba3(); cnt++; // увеличим cnt на 1 obj2.a = 0; print(obj1); print(obj2); } }

Обратим внимание на то, что при первом вызове print(…) перед ним указано имя класса, а в двух других случаях print(…) вызывается без каких-либо уточнителей. В действительности и при первом вызове мы могли не ставить префикс «Proba3.», поскольку мы вызываем статический метод класса из другого метода класса, а при этом указывать имя объекта или класса не обязательно.

Статические методы используются достаточно часто. В составе стандартной библиотеки Java есть целые классы, в которых все методы статические (Math, Arrays, Collections).

При работе с Java невозможно обойтись без документации. Документация поставляется в виде html-файлов. В каталоге c:\jdk1.3\docs находится головной индекс документации по Java. Откроем его. Там указано, какие разделы документации доступны локально (в колонке Location проставлено docs), а какие могут быть загружены (website).

Основная документация, необходимая в работе над программами — » Java 2 Platform API Specification » (c:\jdk1.3\docs\api\index.html). Это документация по стандартной библиотеке Java. Откроем ее. Выберем вариант FRAMES.

В левой колонке вверху список пакетов. Библиотеки в Java строятся из пакетов. Пакет — это просто способ группировки связанных друг с другом классов. Мы будем подробнее знакомиться с ними позже.

В левой колонке снизу — список классов. Изначально в списке пакетов выбран элемент «All packages» (Все пакеты). Это означает, что в списке классов виден перечень всех классов библиотеки. Если кликнуть на некотором конкретном пакете, то в списке классов останутся только классы данного пакета.

Основную часть экрана занимает собственно документация по конкретному классу. Если выбрать некоторый класс в списке классов, то в основной части появится документация по этому классу.

Выберем в списке пакетов пакет java.lang и в нем класс Boolean. Просмотрим документацию по этому классу. Сначала идет небольшое описание класса, потом краткий список полей (Field Summary), потом перечень конструкторов (Constructor Summary), потом список методов (Method Summary), а потом уже детальное описание всех этих элементов.

Выберем в том же пакете класс Math и постараемся по документации выяснить его назначение и возможности.

  • Поскольку эта документация нужна постоянно, лучше сделать для нее иконку на рабочем столе. Для этого лучше всего кликнуть правой клавишей мыши на ссылке FRAMES в верхней строке экрана, скопировать ссылку (Copy Shortcut), а потом перейти на рабочий стол и выполнить Paste Shortcut.

Практическая работа

  • 1. На основе документации по классу Math написать программу, которая вычисляет и печатает синус и косинус 30. Нужно учесть, что стандартные методы класса Math ожидают параметр в радианах. Поэтому нам нужно преобразовать 30 в нужное число радиан.
  • 2. Рассмотрим, как реализовать преобразование строки в число. Это нам понадобится для написания более универсальных программ, в которых мы сможем, скажем, вычислять синус и косинус от произвольного аргумента.
    Для этого рассмотрим класс Double и найдем в нем метод parseDouble(…).
    Теперь преобразуем нашу программу так, чтобы она могла вычислять синус и косинус произвольного аргумента в градусах. <<br /> Программа должна принимать один параметр вызова (args[0]), преобразовывать его в нужное число радиан, вычислять синус и косинус и печатать аргумент и значение синуса и косинуса.

[an error occurred while processing this directive]
[an error occurred while processing this directive](none)


Нестатический блок:

Получает вызов каждый раз, когда экземпляр класса строится. Статический блок только вызывается один раз , когда сам класс инициализируется, независимо от того, сколько объектов этого типа вы создаете.

Пример:

Это печатает:


Вот пример:

Код в разделе «статические» будет выполняться во время загрузки класса, прежде чем будут созданы какие-либо экземпляры класса (и до того, как какие-либо статические методы будут вызваны из других источников). Таким образом, вы можете убедиться, что все ресурсы класса готовы к использованию.

Также возможно иметь нестатические блоки инициализатора. Они действуют как расширения для набора методов конструктора, определенных для класса. Они выглядят так же, как и статические блоки инициализатора, за исключением того, что ключевое слово «статический» не используется.


Я бы сказал, что — это просто синтаксический сахар. Вы ничего не можете сделать со блоком, а не с чем-либо еще.

Повторное использование некоторых примеров, размещенных здесь.

Эта часть кода может быть переписана без использования инициализатора.

Способ №1: со

Метод № 2: без


Вы можете выполнить бит кода один раз для класса, прежде чем объект будет создан в статических блоках.

Например


Если ваши статические переменные необходимо установить во время выполнения, блок очень полезен.

Собеседование по Java — ООП (вопросы и ответы). Часть 2

Например, если вам нужно установить статический член в значение, которое хранится в файле конфигурации или базе данных.

Также полезно, когда вы хотите добавить значения к статическому члену поскольку вы не можете добавить эти значения в первоначальную декларацию участника.


Как дополнительный, как @Pointy сказал

Код в разделе «статические» будет выполняться во время загрузки класса, прежде чем будут созданы какие-либо экземпляры класса (и до того, как какие-либо статические методы будут вызваны из других источников).

Предполагается добавить в статический блок.

Он не гарантирует, что нативный метод не будет вызван до того, как соответствующая библиотека будет загружена в память.

Согласно loadLibrary из oracle :

Если этот метод вызывается более одного раза с тем же именем библиотеки, второй и последующие вызовы игнорируются.

Так что совершенно неожиданно, если System.loadLibrary не используется, чтобы избежать загрузки библиотеки многократно.


Статические блоки выполняются только один раз во время загрузки и инициализации класса с помощью JVM, т. Е. При первом обращении к классу в коде.

Типичным примером использования статического блока является поддержка восстановления экземпляра Enum по его значению, для этого вы определяете хэш-карту как статическую переменную, которая отображает каждое значение в соответствующий экземпляр Enum , карта инициализируется и заполняется внутри статического перед тем как Enum будет использоваться в приложении.

Ссылка: статическое ключевое слово в java


FILED UNDER : IT

Submit a Comment

Must be required * marked fields.

:*
:*