Метод в java должен содержать как минимум
Перейти к содержимому

Метод в java должен содержать как минимум

  • автор:

Методы в Java

Java-университет

Методы в Java - 1В Java приложение состоит из классов. Классы, в свою очередь, состоят из переменных. Они отвечают за хранение данных и методов, которые отвечают за поведение класса: иначе говоря, логику, которую он может предоставлять (например, обработку некоторых данных, вызов других методов, и т. д.). Говорить о таких составляющих как переменные можно долго, но мы сегодня не для этого собрались. Давайте лучше поговорим о такой составляющей класса как метод. Методы в Java - 2Метод — это именованный блок кода, объявляемый внутри класса. Он содержит некоторую законченную последовательность действий (инструкций), направленных на решение отдельной задачи, который можно многократно использовать. Иными словами, метод — это некоторая функция: что-то, что умеет делать ваш класс. В других языках тоже присутствуют функции. Только в Java они являются членами классов и, согласно терминологии ООП, называются методами. Но прежде чем продолжить, давайте рассмотрим небольшой пример:

 public String constructHelloSentence(String name)

Тут ничего сложного: метод Java, задача которого сформировать строку приветствия, с именем, которое мы ему передаем. Как например — Hello world! My name is Bobby Давайте как следует разберемся с построением метода, рассмотрев каждое ключевое слово в объявлении метода (слева направо). Наше первое ключевое слово — public , и оно обозначает модификатор доступа:

Модификаторы доступа

Методы в Java - 3

Указывают допустимую область видимости для членов класса, то есть ограничение мест, в которых разрешается использовать какую-то переменную или метод. В языке Java применяют такие модификаторы доступа:

  • public : публичный. Методы или поля с этим модификатором общедоступны, видимы другим классам (а точнее, их методам и полям) из текущего пакета и из внешних пакетов. Это самый широкий уровень доступа из известных;
  • protected : к методам или переменным с этим модификатором есть доступ из любого места в текущем классе или пакете, или в классах, наследующих данный, а заодно — и методы или поля, даже если они находятся в других пакетах
 protected String constructHelloSentence(String name)
 String constructHelloSentence(String name)
 private String constructHelloSentence(String name)

Возвращаемое значение

Возвращаемое значение — это данные (некий результат выполнения метода), которые приходят на его место после вызова. Каждый метод имеет возвращаемое значение. Или нет?

Методы с возвращаемым значением

Это значение может быть данными любого вида: как переменной простого типа, так и ссылочного. В рассматриваемом примере мы указываем, что метод должен вернуть объект типа String , что как мы помним, является классом, описывающим строку. Второй момент здесь — слово return . Оно имеет прямое отношение к возвращаемому значению: значение, стоящее после него, будет отправлено назад, на место вызова метода, а сам же метод после return закроется. Это слово обычно идёт в последней строке метода (кроме методов с различными ветвлениями типа if, else.. .). Если написать код в следующей строке после return :

 private String constructHelloSentence(String name)

то мы получим ругательства компилятора, что не очень хорошо (компилятор ерунду не посоветует). Также нужно помнить, что тип данных после с должен совпадать с объявленным в сигнатуре метода. Подробнее о return читайте здесь.

void

Для каких служит void в Java? Не у всех методов есть возвращаемое значение. Некоторым или нечего, или не нужно ничего возвращать. Что же тогда делать? Тогда в сигнатуре метода на место возвращаемого значения мы пишем void . Как бы выглядел наш метод без возвращаемого значения?

 protected void constructHelloSentence(String name)

Вы наверняка заметили, что вместе с возвращаемым значением у нас исчезло слово return Так и есть, ведь наш метод и не должен ничего возвращать. Тем не менее, его можно тут поставить, но без какого-то значения, просто return ; в последней строке. Это в целом бесполезно, поэтому в методах с void он необязателен. Тем не менее, его можно применять с пользой в void методах, например, при ветвлениях или циклах, когда нужно немедленно выйти из метода. Далее в объявлении метода у нас шло constructHelloSentence .

Названия методов

Методы в Java - 4

constructHelloSentence — название метода, отличительная особенность, по которой мы сможем отличать тот или иной метод. И, соответственно, вызывать тот или иной метод. Названия методов должны начинаться с маленькой буквы, но и использовать верблюжий стиль (CamelCase, верблюжий регистр): т.е. каждое следующее слово в названии стоит впритык к предыдущему и пишется с большой буквы. Наименования методов должны описывать метод (лучший комментарий — правильное именование). Для этого используйте глаголы или сочетания с глаголами: getCat , delete , createCar , и так далее. В пределах одного класса имена методов должны быть уникальными (не считая перегрузки методов, о чем поговорим немного ниже). Смотрим дальше разбираемый нами метод и видим ( String name )

Параметры метода

Методы могут иметь (или не иметь) определенные данные, которые будут поступать снаружи, а именно — с места, где и был вызван метод. В нашем случае мы видим, что приходит объект типа String с именем name и в дальнейшем мы используем эту переменную в нашем методе. В методе можно использовать неограниченное количество параметров, но больше 7 — не рекомендуется. Когда мы не знаем точное количество элементов, но все эти элементы нужны для одной цели и будут одного типа (например, String ), используется многоточие:

 public void constructHelloSentence(String. name)

Обращение к каждому элементу будет такого вида: name[0] Ничего не напоминает? Верно, массив! Ничего не изменится, если мы напишем:

 protected void constructHelloSentence(String[] name)

Обращение к элементам также будет вида: name[1] И ещё кое что. Аргументы метода могут быть final:

 public String constructHelloSentence(final String name)

Это значит, что ссылка name привязана к конкретному объекту String , и переопределить её нельзя. Про работу с ссылочными переменными и их взаимодействие с зарезервированным словом final можно прочитать в материале “Ссылочные типы данных в Java”.

Вызов методов

Методы в Java - 5

Итак, с созданием методов разобрались, теперь давайте поговорим об их использовании. Как вызвать метод в Java? Каждый метод в Java находится в классе. Чтобы разобраться, как устроен вызов методов в Java, возьмем класс:

 public class StringConstructor < public String constructHelloSentence(String name) < String resultSentence = "Hello world! My name is " + name; System.out.println(resultSentence); return resultSentence; >> 

Так как у нас метод не является статическим (это отдельная тема для разговора, выходящая за рамки сегодняшней статьи), для его вызова нужно сперва создать объект, и уже у него вызвать метод:

 class Application < public static void main(String[] args) < StringConstructor stringConstructor = new StringConstructor(); stringConstructor.constructHelloSentence("Den"); >> 

В аргументы нашего метода мы передали строку (имя), которую хотим видеть в результирующей строке, выведенной на экран:

 Hello world! My name is Den 

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

this

Часто в коде можно увидеть ключевое слово this , как например в сеттерах:

 public void setValue(Long value)

И что же оно значит? this в Java — это ссылка на текущий объект данного класса. Например, если мы создали объект:

 StringConstructor stringConstructor = new StringConstructor(); 

то this внутри объекта stringConstructor будет ссылкой на этот же объект. this используется как для ссылки на переменную объекта (как в сеттере выше), так и для вызова некоторого метода. Мы можем немного переписать наш класс:

 public class StringConstructor < public String constructHelloSentence(String name) < String resultSentence = this.getSentence() + name; System.out.println(resultSentence); return resultSentence; >private String getSentence() < return "Hello world! My name is "; >> 

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

Перегрузка методов

Методы в Java - 7

Предположим нам понадобился метод, выполняющий по сути ту же самую логику, но в предложении Hello world ! вместо world мы хотим вставить своё слово (строку). Но ведь у нас уже есть метод constructHelloSentence . Значит, нам нужно придумать новое название для метода, который выполняет по сути тот же функционал? Как бы не так: в этот момент на помощь нам приходит перегрузка методов. Перегрузка методов — это использование одного и того же имени метода несколько раз при его объявлении в классе. С точки зрения синтаксиса языка, не может быть двух одинаковых имен в некотором локальном пространстве. Но при этом допускается объявление методов с одинаковыми именами но отличающимися аргументами. Иными словами, класс содержит в себе перегруженные, когда есть два и более методов с одинаковыми названиями, но различными входными данными:

 public class Constructor < public String constructHelloSentence(String name) < String resultSentence = "Hello world! My name is " + name; System.out.println(resultSentence); return resultSentence; >protected String constructHelloSentence(String firstName, String secondName) < String resultSentence = "Hello " + firstName + "! My name is " + secondName; System.out.println(resultSentence); return resultSentence; >> 

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

Java – Методы

Java-метод – это набор операторов, сгруппированных для выполнения операции. Когда вы звоните System.out. Например, метод println () , система фактически выполняет несколько операторов для отображения сообщения на консоли.

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

Создание метода

Рассмотрим следующий пример для объяснения синтаксиса метода –

public static int methodName(int a, int b) < // body >
  • public static – модификатор
  • int – тип возвращаемого значения
  • methodName – название метода
  • а, б – формальные параметры
  • int a, int b – список параметров

public static – модификатор

int – тип возвращаемого значения

methodName – название метода

а, б – формальные параметры

int a, int b – список параметров

Определение метода состоит из заголовка метода и тела метода. То же самое показано в следующем синтаксисе –

modifier returnType nameOfMethod (Parameter List) < // method body >

Синтаксис, показанный выше, включает:

  • Модификатор – определяет тип доступа к методу и является необязательным для использования.
  • returnType – Метод может вернуть значение.
  • nameOfMethod – это имя метода. Подпись метода состоит из имени метода и списка параметров.
  • Список параметров – список параметров, это тип, порядок и количество параметров метода. Это необязательно, метод может содержать ноль параметров.
  • тело методатело метода определяет, что метод делает с операторами.

Модификатор – определяет тип доступа к методу и является необязательным для использования.

returnType – Метод может вернуть значение.

nameOfMethod – это имя метода. Подпись метода состоит из имени метода и списка параметров.

Список параметров – список параметров, это тип, порядок и количество параметров метода. Это необязательно, метод может содержать ноль параметров.

тело методатело метода определяет, что метод делает с операторами.

Вот исходный код определенного выше метода с именем min () . Этот метод принимает два параметра num1 и num2 и возвращает максимум между двумя –

/** the snippet returns the minimum between two numbers */ public static int minFunction(int n1, int n2)  int min; if (n1 > n2) min = n2; else min = n1; return min; >

Вызов метода

Для использования метода он должен быть вызван. Существует два способа вызова метода, т. Е. Метод возвращает значение или ничего не возвращает (нет возвращаемого значения).

Процесс вызова метода прост. Когда программа вызывает метод, управление программой передается вызываемому методу. Затем этот вызываемый метод возвращает управление вызывающей стороне в двух условиях, когда –

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

Методы, возвращающие void, рассматриваются как вызов оператора. Давайте рассмотрим пример –

System.out.println("This is tutorialspoint.com!");

Метод, возвращающий значение, можно понять из следующего примера:

int result = sum(6, 9);

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

public class ExampleMinNumber  public static void main(String[] args)  int a = 11; int b = 6; int c = minFunction(a, b); System.out.println("Minimum Value pln"> + c); > /** returns the minimum of two numbers */ public static int minFunction(int n1, int n2)  int min; if (n1 > n2) min = n2; else min = n1; return min; > >

Это даст следующий результат –

Minimum value = 6

Пустое ключевое слово

Ключевое слово void позволяет нам создавать методы, которые не возвращают значение. Здесь, в следующем примере мы рассматриваем пустой метод methodRankPoints . Этот метод является пустым методом, который не возвращает никакого значения. Вызов метода void должен быть оператором, т.е. methodRankPoints (255.7); , Это оператор Java, который заканчивается точкой с запятой, как показано в следующем примере.

public class ExampleVoid  public static void main(String[] args)  methodRankPoints(255.7); > public static void methodRankPoints(double points)  if (points >= 202.5)  System.out.println("Rank:A1"); >else if (points >= 122.4)  System.out.println("Rank:A2"); >else  System.out.println("Rank:A3"); > > >

Это даст следующий результат –

Rank:A1

Передача параметров по значению

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

Передача параметров по значению означает вызов метода с параметром. Через это значение аргумента передается параметру.

Следующая программа показывает пример передачи параметра по значению. Значения аргументов остаются неизменными даже после вызова метода.

public class swappingExample  public static void main(String[] args)  int a = 30; int b = 45; System.out.println("Before swapping, a pln"> + a + " and b pln"> + b); // Invoke the swap method swapFunction(a, b); System.out.println("\n**Now, Before and After swapping values will be same here**:"); System.out.println("After swapping, a pln"> + a + " and b is " + b); > public static void swapFunction(int a, int b)  System.out.println("Before swapping(Inside), a pln"> + a + " b pln"> + b); // Swap n1 with n2 int c = a; a = b; b = c; System.out.println("After swapping(Inside), a pln"> + a + " b pln"> + b); > >

Это даст следующий результат –

Before swapping, a = 30 and b = 45 Before swapping(Inside), a = 30 b = 45 After swapping(Inside), a = 45 b = 30 **Now, Before and After swapping values will be same here**: After swapping, a = 30 and b is 45

Перегрузка метода

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

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

Следующий пример объясняет то же самое –

public class ExampleOverloading  public static void main(String[] args)  int a = 11; int b = 6; double c = 7.3; double d = 9.4; int result1 = minFunction(a, b); // same function name with different parameters double result2 = minFunction(c, d); System.out.println("Minimum Value pln"> + result1); System.out.println("Minimum Value pln"> + result2); > // for integer public static int minFunction(int n1, int n2)  int min; if (n1 > n2) min = n2; else min = n1; return min; > // for double public static double minFunction(double n1, double n2)  double min; if (n1 > n2) min = n2; else min = n1; return min; > >

Это даст следующий результат –

Minimum Value = 6 Minimum Value = 7.3

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

Использование аргументов командной строки

Иногда вы захотите передать некоторую информацию в программу при запуске. Это достигается передачей аргументов командной строки в main ().

Аргумент командной строки – это информация, которая непосредственно следует за именем программы в командной строке при ее выполнении. Получить доступ к аргументам командной строки внутри Java-программы довольно просто. Они хранятся в виде строк в массиве String, передаваемом в main ().

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

public class CommandLine  public static void main(String args[])  for(int i = 0; iargs.length; i++)  System.out.println("args[" + i + "]: " + args[i]); > > >

Попробуйте выполнить эту программу, как показано здесь –

$java CommandLine this is a command line 200 -100

Это даст следующий результат –

args[0]: this args[1]: is args[2]: a args[3]: command args[4]: line args[5]: 200 args[6]: -100

Это ключевое слово

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

Примечание . Ключевое слово this используется только внутри методов или конструкторов экземпляра.

это

В общем, ключевое слово это используется для –

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

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

class Student  int age; Student(int age)  this.age = age; > >
  • Вызовите один тип конструктора (параметризованный конструктор или по умолчанию) из другого класса. Это известно как явный вызов конструктора.

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

class Student  int age Student()  this(20); > Student(int age)  this.age = age; > >

Вот пример, который использует это ключевое слово для доступа к членам класса. Скопируйте и вставьте следующую программу в файл с именем This_Example.java .

public class This_Example  // Instance variable num int num = 10; This_Example()  System.out.println("This is an example program on keyword this"); > This_Example(int num)  // Invoking the default constructor this(); // Assigning the local variable num to the instance variable num this.num = num; > public void greet()  System.out.println("Hi Welcome to Tutorialspoint"); > public void print()  // Local variable num int num = 20; // Printing the local variable System.out.println("value of local variable num is : "+num); // Printing the instance variable System.out.println("value of instance variable num is : "+this.num); // Invoking the greet method of a class this.greet(); > public static void main(String[] args)  // Instantiating the class This_Example obj1 = new This_Example(); // Invoking the print method obj1.print(); // Passing a new value to the num variable through parametrized constructor This_Example obj2 = new This_Example(30); // Invoking the print method again obj2.print(); > >

Это даст следующий результат –

This is an example program on keyword this value of local variable num is : 20 value of instance variable num is : 10 Hi Welcome to Tutorialspoint This is an example program on keyword this value of local variable num is : 20 value of instance variable num is : 30 Hi Welcome to Tutorialspoint

Переменные Аргументы (var-args)

JDK 1.5 позволяет передавать методу переменное число аргументов одного и того же типа. Параметр в методе объявлен следующим образом:

typeName. parameterName

В объявлении метода вы указываете тип, за которым следует многоточие (…). В методе может быть указан только один параметр переменной длины, и этот параметр должен быть последним параметром. Любые обычные параметры должны предшествовать этому.

public class VarargsDemo  public static void main(String args[])  // Call method with variable args printMax(34, 3, 3, 2, 56.5); printMax(new double[]1, 2, 3>); > public static void printMax( double. numbers)  if (numbers.length == 0)  System.out.println("No argument passed"); return; > double result = numbers[0]; for (int i = 1; i  numbers.length; i++) if (numbers[i] > result) result = numbers[i]; System.out.println("The max value is " + result); > >

Это даст следующий результат –

The max value is 56.5 The max value is 3.0

Метод finalize ()

Можно определить метод, который будет вызываться непосредственно перед окончательным уничтожением объекта сборщиком мусора. Этот метод называется finalize () , и его можно использовать для обеспечения правильного завершения объекта.

Например, вы можете использовать finalize (), чтобы убедиться, что открытый файл, принадлежащий этому объекту, закрыт.

Чтобы добавить финализатор в класс, вы просто определяете метод finalize (). Среда выполнения Java вызывает этот метод всякий раз, когда собирается перезапустить объект этого класса.

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

Метод finalize () имеет такую ​​общую форму –

protected void finalize( ) < // finalization code here >

Здесь ключевое слово protected – это спецификатор, который запрещает доступ к finalize () по коду, определенному вне его класса.

Это означает, что вы не можете знать, когда или даже выполнится finalize (). Например, если ваша программа заканчивается до того, как происходит сборка мусора, finalize () не будет выполняться.

2: Все есть объекты

Хотя он основывается на C++, Java более “чистый” объектно-ориентированный язык.

И C++ и Java гибридные языки, но разработчики Java почувствовали, что гибридизация не так важна, как в случае C++. Гибридные языки позволяют различные стили программирования; причина гибридизации C++ в обратной совместимости с языком C. Поэтому C++ является расширением языка C, он включает много нежелательных особенностей этого языка, которые могут сделать некоторые аспекты C++ чрезмерно запутанными.

Язык Java предполагает, что вы хотите заниматься только объектно-ориентированным программированием. Это значит, что прежде чем вы сможете начать, вы должны продвинуть свой разум в объектно-ориентированный мир (если вы еще не там). Польза от этого начального достижения — это способность программировать на языке, который проще для изучения и использования, чем многие другие ООП языки. В этой главе вы увидите основные компоненты Java программы, и мы выучим, что все в Java — это объекты, даже Java программа.

Вы управляете объектами через ссылки

Каждый язык программирования вкладывает совой собственный смысл в управление данными. Иногда программисты должны постоянно осознавать, какого типа управление происходит. Управляете ли вы объектом напрямую, или вы имеете дело с определенного рода непрямым представлением (указатель в C и C++), которое должно трактоваться в специальном синтаксисе?

Все это упрощено в Java. Вы трактуете все как объекты, так что здесь однородный синтаксис, который вы используете везде. Хотя вы трактуете все, как объекты, идентификатор, которым вы манипулируете, на самом деле является “ссылкой” на объект [20] . Вы можете вообразить эту сцену, как телевизор (объект) с вашим пультом дистанционного управление (ссылка). Столько, сколько вы держите эту ссылку, вы имеете связь с телевизором, но когда что-то говорит: “измените канал” или “уменьшите звук”, то, чем вы манипулируете, это ссылка, которая производит модификацию объекта. Если вы хотите ходить по комнате и все равно хотите управлять телевизором, вы берете пульт/ссылку с собой, но не телевизор.

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

String s;

Но здесь вы создаете только ссылку, а не объект. Если вы решите послать сообщение для s в этом месте, то вы получите ошибку (времени выполнения), потому что s ни к чему не присоединено (здесь нет телевизора). Безопасная практика, поэтому, всегда инициализировать ссылку, когда вы создаете ее:

String s = "asdf";

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

Вы должны создавать все объекты

Когда вы создаете ссылку, вы хотите соединить ее с новым объектом. Вы делаете это, в общем случае, с помощью ключевого слова new . new говорит: “Создать один новый экземпляр этого объекта”. В приведенном выше примере вы можете сказать:

String s = new String("asdf");

Это значит не только “Создать мне новый String ”, но это также дает информацию о том, как создать String , указывая инициализирующую строку.

Конечно, String — это не только существующий тип. Java пришла с полноценными готовыми типами. Что более важно, так это то, что вы можете создать свои собственные типы. Фактически, это основной род деятельность при программировании на Java, и это то, что вы будите учиться делать в оставшейся части книги.

Где живет хранилище

Полезно показать некоторые аспекты тог, как размещаются вещи во время работы программы, особенно, как распределяется память. Есть шесть разных вещей для хранения данных:

  1. Регистры . Это самое быстрое хранилище, потому что оно существует в месте, отличном от других хранилищ: внутри процессора. Однако число регистров сильно ограничено, так что регистры резервируются компилятором в соответствии с его требованиями. Вы не имеете прямого контроля, и при этом вы не видите никакого свидетельства в вашей программе, что регистры вообще существуют.
  2. Стек . Он расположен в области обычной RAM (память произвольного доступа — random-access memory), но имеет прямую поддержку процессора через указатель стека. Указатель стека перемещается вниз при создании новой памяти, и перемещается вверх при освобождении памяти. Это чрезвычайно быстрый и эффективный способ для выделения хранилища, второй после регистров. Компилятор Java должен знать во время создания программы точный размер и продолжительность жизни всех данных, которые хранятся в стеке, потому что он должен генерировать код для перемещения указателя стека вверх и вниз. Это ограничение сказывается на гибкости ваших программ, так что пока хранилище Java существует в стеке — обычно, для ссылок на объекты — объекты Java не помещаются в стек.
  3. Куча . Это пул памяти общего назначения (также в области RAM), где живут объекты Java. Главная прелесть кучи, в отличие от стека, в том, что компилятору нет необходимости знать, как много места необходимо выделить из кучи для хранилища или как долго это хранилище будет оставаться в куче. Поэтому, большой плюс для гибкости при создании хранилища в куче. Когда бы вам ни понадобилось создавать объект, вы просто пишите код для его создания, используя new, а когда такой код выполняется, хранилище выделяется в куче. Конечно, вы платите за эту гибкость: это занимает больше времени при выделении хранилища в куче, чем при выделении хранилища в стеке (если бы вы могли создать объект в стеке в Java, как вы это можете в C++).
  4. Статическое хранилище . “Статическое” здесь используется в смысле “в фиксированном месте” (хотя это тоже в RAM). Статическое хранилище содержит данные, которые доступны в течение всего времени выполнения программы. Вы можете использовать ключевое слово static , чтобы указать, что определенный элемент объекта — статический, но Java объект никогда не помещается в статическое хранилище.
  5. Хранилище констант . Константные значения часто помещаются прямо в код программы, что является безопасным, так как они никогда не могут измениться. Иногда константы огораживают себя так, что они могут быть по выбору помещены в память только для чтения (ROM).
  6. Не RAM хранилище . Если данные живут полностью вне программы, они могут существовать, пока программа не работает, вне управления программы. Два основных примера — это потоковые объекты, в которых объекты переведены в поток байтов, обычно для посылки на другую машину, и объекты представления, в которых объекты помещаются на диск, так что они сохраняют свое состояние, даже когда программа завершена. Фокус этих типов хранилищ в переводи объектов во что-то, что может существовать на другом носителе, и даже могут быть воскрешены в обычный объект в RAM, когда необходимо. Java обеспечивает поддержку для легковесной живучести, и будущие версии Java могут предлагать более полное решение для живучести.

Особый случай: примитивные типы

Есть группа типов, имеющих особое обращение; вы можете думать о них, как о “примитивных” типах, которые вы достаточно часто используете в вашем программировании. Причина специального использования в том, что создание объектов с помощью new —особенно маленьких, простые переменных — не очень существенно, поскольку new помещает объекты в кучу. Для этих типов Java возвращается к подходу, принятому в C и C++. Так что, вместо создания переменной с использованием new, “автоматические” переменные создаются не по ссылке. Переменная хранит значение, и оно помещается в стек, так как это более эффективно.

Java определяет размер каждого примитивного типа. Размеры не меняются при переходе от одной архитектуры машины к другой, как это сделано во многих языках. Этот размер инвариантен — это причина того, что программирование на Java так переносимо.

Примитивный тип
Тип оболочки
boolean — — — Boolean char 16-бит Unicode 0 Unicode 2 16 — 1 Character byte 8-bit -128 +127 Byte short 16-bit -2 15 +2 15 — 1 Short int 32-bit -2 31 +2 31 — 1 Integer long 64-bit -2 63 +2 63 —1 Long float 32-bit IEEE754 IEEE754 Float double 64-bit IEEE754 IEEE754 Double void — — — Void

Все числовые типы знаковые, так что не ищите беззнаковые типы.

Размер boolean типов точно не определено; только указано, что они способны принимать литерные значения true или false .

Примитивные типы данных также имеют классы “оболочки” для них. Это означает, что если вы хотите создать не примитивный объект в куче для представления примитивного типа, вы используете ассоциированную оболочку. Например:

char c = 'x'; Character C = new Character(c);

Или вы также моги использовать:

Character C = new Character('x');

Обоснования для этого действия будет дано в последующих главах.

Числа высокой точности

Java включает два класса для работы с высокоточной арифметикой: BigInteger и BigDecimal . Хотя они приблизительно попадают в ту же категорию, что и классы “оболочки”, ни один из них не имеет примитивного аналога.

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

BigInteger поддерживают целые числа произвольной точности. Это означает, что вы можете точно представить значение целого числа любого размера без потерь любой информации во время операций.

BigDecimal для чисел с фиксированной точкой произвольной точности; вы можете использовать это, например, для точных денежных расчетов.

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

Массивы в Java

Фактически, все языки программирования поддерживают массивы. Использование массивов в C и C++ рискованно, поскольку эти массивы всего лишь блоки памяти. Если программа обращается к массиву вне пределов этого блока, или использует память до инициализации (общая ошибка программирования), получится непредсказуемый результат.

Одна из главных целей Java — это безопасность, так что многие проблемы, надоедающие программистам в C и C++, не повторяются в Java. Java массив гарантированно инициализируется и нельзя получить доступ вне его пределов. Цена такой проверки диапазона — выделение дополнительной памяти к каждому массиву, так же как и за проверку индексов во время выполнения, но предположение, что это безопасно и повышает продуктивность, стоит расходов.

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

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

Массивы более подробно будут рассмотрены в следующих главах.

Вам никогда не нужно уничтожать объекты

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

Ограничивание

Большинство процедурных языков имеют концепцию границ. Они определяют и видимость, и время жизни имен, определенных в таких границах. В C, C++ и Java границы определяются расстановкой фигурных скобок <> . Так, например:

< int x = 12; /* доступно только x */ < int q = 96; /* доступны и x, и q */ > /* Доступно только x */ /* q “за границами” */ >

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

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

Обратите внимание, что в не можете сделать следующее, хотя это разрешено в С и C ++:

< int x = 12; < int x = 96; /* недопустимо */ > >

Компилятор объявит, что переменная x уже определена. Таким образом, C и C++ способны “прятать” переменные в больших границах, что не позволяется в Java, поскольку разработчики подумали, что это будет запутывать программы.

Границы объектов

Java объекты не имеют то же самое время жизни, что и примитивы. Когда вы создаете Java объект, используя new, он продолжает существовать после конца границы. Таки образом, если вы используете:

< String s = new String("a string"); > /* конец блока */

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

Оказывается, потому что объекты создаются с помощью new , они остаются столько, сколько вы этого хотите, что создавало в C++ проблемы при программировании, и что просто исчезло в Java. Сложнейшие проблемы случаются в C++ потому, что вы не получаете никакой помощи от языка, чтобы убедится, что объект доступен, когда он нужен. И, что более важно, в C++ вы должны убеждаться, что вы уничтожили объект, когда вы закончили работать с ним.

Это выявляет интересный вопрос. Если Java оставляет объекты лежать вокруг, что предохраняет от переполнения памяти и остановки вашей программы? Этот вид проблемы точно случается в C++. Здесь происходит немного магии. Java имеет сборщик мусора, который смотрит на все объекты, которые были созданы с помощью new, и решает, на какие из них больше нигде нет ссылок. Затем он освобождает память этого объекта, так что память может использоваться для новых объектов. Это означает, что вам нет необходимости самостоятельно заботится об утилизации памяти. Вы просто создаете объекты и, когда он вам больше не нужен, он сам исчезнет. Это подавляет определенных класс проблем программирования: так называемую “утечку памяти”, при которой программисты забывают освободить память.

Создание новых типов данных: классов

Если все — это объекты, что определяет, как выглядит и ведет себя объект определенного класса? Или, другими словами, что основывает тип объекта? Вы можете ожидать здесь ключевого слова “type”, и, конечно, это бы имело смысл. Однако исторически сложилось, что большинство объектно-ориентированных языков используют ключевое слово class , которое означает: “Я говорю тебе, как выглядит новый тип объекта”. За ключевым словом class (которое является настолько общим, что оно не будет поощряться в этой книге) следует имя нового типа. Например:

class ATypeName < /* Здесь помещается тело класса */ >

Это вводит новый тип, так что вы можете теперь создавать объекты этого типа, используя new :

ATypeName a = new ATypeName();

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

Поля и методы

Когда вы определяете класс (а все, что вы делаете в Java — это определение классов, создание объектов этих классов и посылка сообщений этим объектам), вы можете поместить два типа элементов в ваш класс? Члены-данные (иногда называемые полями) и члены-функции (обычно называемые методами). Члены-данные — это объекты любого типа, с которыми вы можете взаимодействовать через ссылку. Они также могут быть примитивными типами (которые не являются ссылками). Если это ссылка на объект, вы должны инициализировать эту ссылку, присоединив ее к реальному объекту (используя new, как показано ранее), в специальной функции, называемой конструктором (полностью описано в Главе 4). Если это примитивный тип, вы можете инициализировать его напрямую в точке определения в классе. (Как вы увидите позже, ссылки также могут быть инициализированы в месте определения.)

Каждый объект держит свое собственное место для своих членов-данных; члены-данные не делятся между объектами. Здесь приведен пример класса с какими-то членами-данными:

class DataOnly < int i; float f; boolean b; >

Это класс не делает ничего, но вы можете создать объект:

DataOnly d = new DataOnly();

Вы можете присвоить значение члену-данному, но вы сначала должны узнать, как обратиться к члену объекта. Это совершается, начиная с имени ссылки объекта, далее следует разделитель (точка), далее следует имя члена внутри объекта:

objectReference.member
d.i = 47; d.f = 1.1f; d.b = false;

Также возможно, чтобы ваш объект содержал другой объект, который содержит данные, которые вы хотите модифицировать. Для этого вы используете “соединяющие точки”. Например:

myPlane.leftTank.capacity = 100;

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

Значения по умолчанию примитивных членов

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

Тип примитива Умолчание
boolean false
char ‘\u0000’ (null)
byte (byte)0
short (short)0
int 0
long 0L
float 0.0f
double 0.0d

Обратите внимание, что значение по умолчанию Java гарантирует тогда, когда переменная используется как член класса. Это означает, что переменные-члены примитивных типов всегда будут инициализированы (кое-что C++ не делает), что подавляет источник ошибок. Однако это начальное значение может быть не корректным или разрешенным для написанных вами программ. Так что лучше всегда явно инициализировать ваши переменные.

Эта гарантия не применяется к “локальным” переменным, которые не являются полями класса. Так что, если в пределах определения функции вы имеете:

int x;

Затем x получит произвольное значение (как и в C, и в C++); она не будет автоматически инициализирована нулем. Вы несете ответственность за присвоение и соответствие значения прежде, чем вы будете использовать x . Если вы забудете, Java определенно лучше C++: вы получите ошибку времени компиляции, которая скажет вам, что переменная возможно не инициализирована. (Многие C++ компиляторы предупредят вас об отсутствии инициализации переменной, но в Java — это ошибка.)

Методы, аргументы и
возвращаемое значение

До этих пор термин функция использовался для описания поименованной процедуры. Термин, наиболее часто используемый в Java, это метод, как “способ что-то сделать”. Если вы хотите, вы можете продолжать думать в терминах функций. На самом деле, это только семантическое различие, но далее в этой книге будет использоваться “метод”, а не “функция”.

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

Фундаментальные части метода — это его имя, аргументы, возвращаемое значение и тело. Посмотрите на основную форму:

returnType methodName( /* список аргументов */ ) < /* Тело метода */ >

Возвращаемый тип — это тип значения, которое помещается в память из метода после его вызова. Список аргументов дает типы и имена, чтобы проинформировать вас, что вы должны передать в этот метод. Имя метода и список аргументов вместе уникально идентифицируют метод.

Методы в Java могут создаваться только как часть класса. Метод может быть вызван только для объекта, [21] а этот объект должен быть способен выполнить этот вызов метода. Если вы попытаетесь вызвать неправильный метод для объекта, вы получите сообщение об ошибке во время компиляции. Вы вызываете метод для объекта по имени объекта, за которым следует разделитель (точка), а далее идет имя метода и список его аргументов, как здесь: objectName.methodName(arg1, arg2, arg3) . Например, предположим, что вы имеете метод f( ) , который не принимает аргументов и возвращает значение типа int . Тогда, если вы имеете объект с именем a для которого может быть вызван f( ) , вы можете сказать:

int x = a.f();

Тип возвращаемого значения должен быть совместим с типом x .

Этот вызов метода часто называется посылкой сообщения объекту. В приведенном выше примере сообщение — f( ) , а объект — a . Объектно-ориентированное программирование часто резюмирует, как просто “посылку сообщения объекту”.

Список аргументов

Список аргументов метода определяет, какую информацию вы передаете в метод. Как вы можете догадаться, это информация — как и все в Java — принимает форму объекта. Таким образом, то, что вы должны указать в списке аргументов — это типы объектов для передачи и имена для использования каждого из них. Как и в любой ситуации в Java, где вы кругом видите объекты, на самом деле вы передаете ссылки [22] . Однако, тип ссылки должен быть правильным. Если аргумент, предположим, String , то, что вы передаете должно быть строкой.

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

int storage(String s) < return s.length() * 2; >

Этот метод говорит вам как много байт требуется для хранения информации в обычном String. (Каждый char в String — это 16 бит длины, или два байта, для поддержки символов Unicode.) Аргумент типа String и он называется s . Как только s передается в метод, вы можете трактовать его, как и любой другой объект. (Вы можете посылать ему сообщения.) Здесь вызывается метод length( ) , который является одним из методов для String ; он возвращает число символов в строке.

Вы также можете увидеть использование ключевого слова return , которая делает две вещи. Во-первых, оно означает “покинуть метод, Я закончил”. Во-вторых, если метод произвел значение, это значение помещается справа сразу за выражением return . В этом случае, возвращаемое значение производится путем вычисления выражения s.length( ) * 2 .

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

boolean flag() < return true; > float naturalLogBase() < return 2.718f; > void nothing() < return; > void nothing2() <>

Когда возвращаемый тип — void , то ключевое return используется только для выхода из метода, и поэтому необязательно, когда вы достигаете конца метода. Вы можете вернуться из метода в любом месте, но если вы имеете возвращаемый тип не void , компилятор заставит вас (с помощью сообщения об ошибке) вернуть значение подходящего типа, не зависимо от того, откуда вы возвращаетесь.

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

Построение Java программы

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

Видимость имен

Проблема каждого языка программирования состоит в управлении именами. Если вы используете имена в одном модуле программы, а другой программист использует эти же имена в другом модуле, как вы отличите одно имя от другого и предохраните два имени от “конфликта”? В C это обычная проблема, поэтому программы часто содержат неуправляемое море имен. Классы C++ (на которых основываются классы Java) содержат функции внутри классов, так что они не могут конфликтовать с именами функций, расположенных в других классах. Однако C++ все еще позволяет глобальные данные и глобальные функции, так что конфликт из-за этого все еще возможен. Для решения этой проблемы C++ вводит пространство имен, используя дополнительные ключевые слова.

Java способен предотвратить все это, выбрав свежий подход. Для производства недвусмысленных имен для библиотеки, используется спецификатор, мало чем отличающийся от доменных имен Internet. Фактически, создатели Java хотят использовать ваши доменные имена Internet в обратном порядке, так как это гарантирует их уникальность. Так как мое доменное имя BruceEckel.com , мои библиотеки утилит foibles будет называться com.bruceeckel.utility.foibles . После того, как вы развернете доменное имя, точки предназначены для представления директорий.

В Java 1.0 и Java 1.1 доменное расширение com , edu , org , net , и т.д. по соглашению печатаются большими буквами, так что библиотека будет выглядеть: COM.bruceeckel.utility.foibles . Однако, отчасти из-за разработки Java 2, это стало причиной проблемы и теперь все имя пакета пишется маленькими буквами.

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

Использование других компонентов

Когда бы вы ни пожелали использовать предопределенные классы в вашей программе, компилятор должен знать, где они расположены. Конечно, класс может существовать в том же самом файле исходного кода, из которого он вызывается. В этом случае вы просто используете класс — даже если класс определен дальше по файлу. Java устранит проблему “ранней ссылки”, так что вам нет необходимости думать об этом.

Что можно сказать о классе, который существует в другом файле? Вы можете подумать, что компилятор должен быть достаточно умным, чтобы найти его, но это проблема. Вообразите, что вы хотите использовать класс с определенным именем, но существует более одного определения этого класса (по-видимому, это разные определения). Или хуже, вообразите, что вы написали программу и, когда вы строили ее, вы добавили новый класс в вашу библиотеку, который конфликтует с именем существующего класса.

Для решения этой проблемы вы должны устранить любую потенциальную двусмысленность. Это выполняется путем точного сообщения компилятору Java классов, которые вы хотите использовать с помощью ключевого слова import . import говорит компилятору о введении пакета, который является библиотекой классов. (В других языках библиотеки могут состоять из функций и данных так же, как и из классов, но помните, что весь код в Java должен быть написан внутри класса.)

Большую часть времени вы будите использовать компоненты из стандартных библиотек Java, которые идут вместе с компилятором. Поэтому, вам нет необходимости заботиться о длинных, реверсированных доменных именах; вы просто скажите, например:

import java.util.ArrayList;

чтобы сказать компилятору, что вы хотите использовать Java класс ArrayList . Однако util содержит несколько классов, и вы можете использовать некоторые из них, не объявляя их точно. Это легче всего выполнить, используя ‘ * ’, чтобы указать чистую карту:

import java.util.*;

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

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

Обычно, когда вы создаете класс, вы описываете, как выглядит объект класса и как он будет себя вести. На самом деле вы ничего не получаете, пока не создадите объект класса с помощью new , и в этом месте создается хранилище данных, и становятся доступны методы.

Но есть две ситуации, в которых этот подход не достаточен. Один из них, если вы хотите иметь только одну часть хранилища для определенных данных, не зависимо от того, сколько объектов создано, или даже если не было создано объектов этого класса. Второй, если вам нужен метод, который не ассоциируется с объектом определенного класса. То есть, вам нужен метод, который вы можете вызвать, даже если объект не создан. Вы можете достигнуть этих эффектов с помощью ключевого слова static . Когда вы говорите о чем-то static , это означает, что данные или метод не привязаны к определенному экземпляру объекта класса. Даже если вы никогда не создадите объект этого класса, вы сможете вызвать статический метод или получить доступ к части статических данных. Как обычно, не статические данные и методы вы создаете объект и используете его для доступа к данным или методам, так как не статические данные и методы должны знать определенный объект, с которым они работают. Конечно, так как статическим методам не нужно создавать объект до их использования, они не могут получить прямой доступ к не статическим членам или методам простым вызовом этих методов без указания имени объекта (так как не статические члены и методы должны быть привязаны к определенному объекту).

Некоторые объектно-ориентированные языки используют термины данные класса и методы класса в том смысле, что данные и методы существуют только для класса, как целое, а не для любого определенного объекта класса. Иногда литература по Java тоже использует эти термины.

Чтобы сделать член-данное или член-метод статическим, вы просто помещаете ключевое слово перед определением. Например, следующий код производит статический член-данное и инициализирует его:

class StaticTest < static int i = 47; >

Теперь, даже если вы сделаете два объекта StaticTest , будет только одна часть хранилища для StaticTest.i. Оба объекта будут разделять одну и ту же i . Рассмотрим:

StaticTest st1 = new StaticTest(); StaticTest st2 = new StaticTest();

В этом месте и st1.i, и st2.i имеют одно и то же значение 47, так как они ссылаются на одну и ту же область памяти.

Есть два способа сослаться на статическую переменную. Как показано выше, вы можете назвать ее через объект, например, сказав st2.i . Вы также можете прямо сослаться через имя класса, что вы не можете сделать с не статическими членами. (Это предпочтительный способ сослаться на статическую переменную, та как это подчеркивает, что переменная имеет статическую природу.)

StaticTest.i++;

Оператор ++ инкрементирует переменную. В этом месте и st1.i , и st2.i будут иметь значение 48.

Сходная логика применима и к статическим методам. Вы можете сослаться на статический метод либо через объект, как вы можете сделать с любым методом, или с помощью специального дополнительного синтаксиса ClassName.method( ) . Вы определяете статический метод сходным образом:

class StaticFun < static void incr() < StaticTest.i++; >>

Вы можете увидеть, что метод incr( ) класса StaticFun инкрементирует статическую переменную i . Вы можете вызвать incr( ) обычным способом, через объект:

StaticFun sf = new StaticFun(); sf.incr();

Или, потому что incr( ) — статический метод, вы можете вызвать его прямо через класс:

StaticFun.incr();

Когда static применяется к членам-данным, это изменяет путь создания данных (одни для всего класса против не статического: один для каждого объекта), когда static применяется к методу — это не так драматично. Важность использования static для методов в том, чтобы позволить вам вызывать этот метод без создания объекта. Это неотъемлемая часть, как вы увидите это в определении метода main( ) , который является точкой входа для запуска приложения.

Как и любой метод, статический метод может создавать или использовать именованные объекты того же типа, так что статический метод часто используется как “пастух” для стада объектов одинакового типа.

Ваша первая Java программа

Наконец, здесь приведена программа. [23] Она начинается с печати строки, а затем даты, используя класс Date из стандартной библиотеки Java. Обратите внимание, что здесь приведен дополнительный стиль комментариев: ‘ // ’, который объявляет комментарий до конца строки:

// HelloDate.java import java.util.*; public class HelloDate < public static void main(String[] args) < System.out.println("Hello, it's: "); System.out.println(new Date()); > >

В начале каждого файла программы вы должны поместить объявление import об использовании любых дополнительных классов, которые вам нужны в этом файле. Обратите внимание на слово “дополнительные”; это потому, что есть определенные библиотеки классов, которые подключаются автоматически к любому Java файлу: java.lang . Запустите ваш Web броузер посмотрите документацию от Sun. (Если вы не загрузили ее с java.sun.com или не установили документацию Java, сделайте это сейчас.) Если вы посмотрите на первую страницу, вы увидите все различные библиотеки классов, которые поставляются с Java. Выберите java.lang . Появится список всех классов, являющихся частью этой библиотеки. Так как java.lang косвенно включается в каждый файл с Java кодом, эти классы поддерживаются автоматически. В списке классов java.lang нет класса Date , это означает, что вы должны импортировать другую библиотеку, чтобы использовать его. Если вы не знаете библиотеку, где есть определенный класс, или если вы хотите просмотреть все классы, вы можете выбрать “Дерево” в документации Java. Теперь вы можете найти каждый единичный класс, который поставляется с Java. Теперь вы можете использовать функцию поиска броузера для нахождения Date . Когда вы сделаете это, вы увидите в списке java.util.Date , что позволяет вам узнать, что она в библиотеке util и что вы должны написать import java.util.* для использования Date .

Если вы вернетесь к началу, выберите java.lang , а затем System , вы увидите, что класс System имеет несколько полей, и если вы выберите out , вы обнаружите, что это объект static PrintStream . Так как это static , вам нет необходимости создавать что-либо. Объект out всегда здесь и вы можете просто использовать его. Что вы можете сделать с этим объектом out , определяется типом: PrintStream . Удобство в том, что PrintStream в описании показан как гиперссылка, так что если вы кликните на ней, вы увидите все методы, которые вы можете вызвать для PrintStream . Это не все и подробнее будет описано позже в этой книге. Мы же сейчас интересуемся println( ) , которая подразумевает “печатать то, что я передаю, на консоль и выполнять переход на новую строку”. Таким образом, в Java программе вы пишите то, что хотите сказать в виде System.out.println(“things”) в любом месте, где бы вы ни захотели напечатать что-нибудь на консоль.

Имя класса такое же, что и имя файла. Когда вы создаете самостоятельную программу, такую как эта, один из классов в этом файле должен иметь такое же имя, что и файл. (Компилятор пожалуется, если вы не сделаете это.) Этот класс должен содержать метод, называемый main( ) с показанной здесь сигнатурой:

public static void main(String[] args) 

Ключевое слово public означает, что метод доступен извне (детально описано в Главе 5). Аргументом main( ) является массив объектов String . args не используется в этой программе, но компилятор Java настаивает, чтобы он был, потому что он сохраняет аргументы вызова командной строки.

Строка, печатающая дату, мало интересна:

System.out.println(new Date());

Относительно аргумента: объект Date создается только для передачи его значения в println( ) . Как только это выражение закончится, Date становится ненужным и сборщик мусора может пройтись и собрать его в любое время. Нам нет необходимости заботиться о его очистке.

Компиляция и запуск

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

Сходите в Internet на java.sun.com . Здесь вы найдете информацию и ссылки, которые проведут вас через процесс скачивания и установки JDK для вашей платформы.

Когда JDK установлен, и вы проставили информацию о путях на своем компьютере, чтобы он нашел javac и java , скачайте и распакуйте исходник для этой книге (вы можете найти его на CD ROM, прилагающийся к этой книге, или на www.BruceEckel.com ). Вы получите каталог для каждой главы этой книги. У вас создадутся каталоги для каждой главы этой книги. Перейдите в каталог c02 и наберите:

javac HelloDate.java

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

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

java HelloDate

и вы получите сообщение и дату в качестве вывода.

Этот процесс вы можете использовать для компиляции и запуска каждой программы в этой книге. Однако вы увидите, что исходный код для этой книги также имеет файл, называемый makefile в каждой главе и есть команда “make” для автоматического построения файлов этой главы. Посмотрите Web страницу этой книги на www.BruceEckel.com для получения более подробной информации об использовании makefiles.

Комментарии и встроенная документация

Есть два типа комментариев в Java. Первый - традиционный комментарий в стиле C, который был унаследован из C++. Этот комментарий начинается с /* и распространяется на много линий, пока не встретится */ . Обратите внимание, что многие программисты начинают каждую линию продолжающихся комментариев с * , так что вы часто можете видеть:

/* Это комментарий, * который распространяется * на несколько строк */

Однако помните, что все внутри /* и */ игнорируется, так что это ничем не отличается от:

/* Это комментарий, который распространяется на несколько строк */

Вторая форма комментариев пришла из C++. Это однострочный комментарий, который начинается с // и продолжается до конца линии. Этот тип комментариев удобен и часто используется из-за своей простоты. Вам нет необходимости охотиться за ключевыми словами, чтобы найти / , а затем * (вместо этого вы нажимаете эту кнопку дважды), и вам нет необходимости закрывать комментарий. Так что вы часто будете видеть:

// Это однострочный комментарий 

Комментарий-Документация

Одна из вдумчивых частей языка Java в том, что его разработчики не предполагали, что написание кода будет единственно важным действием — они также подумали о его документации. Возможно, что наибольшая проблема с документированием кода - это поддержка этой документации. Если документация и код разделены, вы получаете трудности при изменении документации всякий раз, когда вы будете менять код. Решение выглядит легким: свяжите код с документацией. Наилегчайший путь для этого - поместить все в один файл. Однако для завершения картины вам нужен специальный синтаксис для пометки специальной документации и инструмент для выделения этих комментариев и помещения их в удобную форму. Это то, что делает Java.

Инструмент, для выделения этих комментариев, называется javadoc. Он использует ту же технологию, что и Java компилятор для поиска специальных ярлыков комментариев, помещенных в вашу программу. Он не только выделяет информацию, помеченную этими ярлыками, а так же помещает имя класса или имя метода, присоединяя его к комментарию. Этим способом вы можете получить при минимальной работе для генерации хорошей документации программы.

На выходе javadoc получается HTML файл, который вы можете просмотреть вашим Web броузером. Этот инструмент позволяет вам создавать и поддерживать единственный исходный файл и автоматически генерирует полезную документацию. Поскольку с javadoc мы имеем стандарт для создания документации и это достаточно легко, поэтому мы можем ожидать или даже требовать документации от Java библиотек.

Синтаксис

Все команды javadoc встречаются только внутри комментариев /**. Комментарий заканчивается */, как обычно. Есть два основных способа использовать javadoc: вставление HTML или использование “ярлыков документации”. Ярлыки документации являются командами, которые начинаются с ‘@’, которая помещается с начала строки комментария. (Однако лидирующая ‘*’ игнорируется.)

Есть три “типа” комментариев документации, которые соответствуют элементам, предшествующий комментарию: класс, переменная или метод. Таким образом, компоненты класса появляются прямо перед определением класса; компонент переменная появляется прямо перед определением переменной, а компонент метода появляется прямо перед определением метода. Как простой пример:

/** Компонент - класс */ public class docTest < /** Компонент - переменная */ public int i; /** Компонент - метод */ public void f() <> >

Обратите внимание, что javadoc будет обрабатывать компоненты документации только для public и protected членов. Компоненты для private и “дружественных” членов (смотрите Главу 5) игнорируются, и вы не увидите их в выводе. (Однако вы можете использовать флаг -private для включения private членов наряду с остальными.) Это имеет смысл, так как только public и protected члены доступны извне файла, которые просматривают программисты-клиенты. Однако все комментарии для class включаются в выходной файл.

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

Вставка HTML

Javadoc пропускает HTML команды для генерации HTML документа. Это позволяет вам использовать HTML; однако главный мотив состоит в позволении вам форматировать код, например так:

/** * 
* System.out.println(new Date()); *

*/

Вы также можете использовать HTML, как вы это делаете в других Web документах для форматирования обычного текста вашего документа:

    *
  1. Первый элемент *
  2. Второй элемент *
  3. Третий элемент *

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

Все компоненты документации — класс, переменная и метод — могут поддерживать вставку HTML.

@see: ссылка на другой класс

Все три типа компонентов документации (класс, переменная и метод) могут содержать ярлык @see, который позволяет ссылаться на документацию другого класса. Javadoc генерирует HTML с ярлыком @see, как гиперссылку на другой документ. Форма:

@see classname @see fully-qualified-classname @see fully-qualified-classname#method-name

Каждая вставка добавляет гиперссылку, входящую в раздел “See Also”, при генерации документации. Javadoc не проверяет гиперссылки, которые вы даете, чтобы убедится в их правильности.

Ярлыки документации класса

Наряду со встроенным HTML и ссылками @see, документация класса может включать ярлыки для информации о версии и имени автора. Документация класса также может быть использована для интерфейса (смотрите Главу 8).

@version
@version version-information

в которой version-information - это любая важная для вас информация., которую вы хотите включить. Когда вносится флаг -version в командную строку javadoc, информация о номере версии специально будет включена в генерируемый HTML документ.

@author
@author author-information

в которой author-information это, предположительно, ваше имя, но она так же может включать ваш электронный адрес или любую другую подходящую информацию. Когда флаг -author вносится в командную строку javadoc, информация об авторе специально включается в генерируемый HTML документ.

Вы можете иметь несколько ярлыков авторства для всего списка авторов, но они будут помещены последовательно. Вся информация об авторах будет собрана вместе в один параграф генерируемого HTML.

@since

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

Ярлыки документации переменных

Документация переменных может включать только встроенный HTML код и ссылки @see.

Ярлыки документации методов

Так же как и встроенная документация и ссылки @see, методы допускают ярлыки документации для параметров, возвращаемых значений и исключений.

@param
@param parameter-name description

в которой parameter-name - это идентификатор в списке параметров, а description - текст, который может продолжаться на последующих строках. Описание считается законченным, когда обнаруживается новый ярлык документации. Вы можете иметь любое число таких ярлыков, предположительно, по одному для каждого параметра.

@return
@return description

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

@throws

Исключения будут продемонстрированы в Главе 10, но если коротко: это объекты, которые могут быть “выброшены” из метода, если метод окончится неудачей. Хотя только один объект исключение может появиться при вызове метода, обычно метод может производить любое число исключений различных типов, все они требуют описания. Форма ярлыка исключения следующая:

@throws fully-qualified-class-name description

в которой fully-qualified-class-name дает вам уникальное имя класса исключения, который где-нибудь определен, а description (которое может продолжаться на последующих линиях) говорит вам, почему этот тип исключения может возникнуть при вызове метода.

@deprecated

Это используется для ярлыка особенностей, которые были заменены улучшенными особенностями. Ярлык deprecated советует вам больше не использовать эту определенную особенность, так как когда нибудь в будущем она будет удалена. Метод, помеченный как @deprecated заставляет компилятор выдавать предупреждение, если он используется.

Пример документации

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

//: c02:HelloDate.java import java.util.*; /** Первая программа - пример Thinking in Java. * Отображает строку и сегодняшнюю дату. * @author Bruce Eckel * @author www.BruceEckel.com * @version 2.0 */ public class HelloDate < /** Единственная точка входа для класса и приложения * @param args массив строк аргументов * @return Возвращаемого значения нет * @exception Исключения не выбрасываются */ public static void main(String[] args) < System.out.println("Hello, it's: "); System.out.println(new Date()); > > ///:~

Первая строка файла использует мою собственную технику помещения ‘:’ как специальный маркер для строки комментария исходного имени файла. Эта строка содержит информацию о пути к файлу (в этом случае c02 указывает Главу 2), за которой следует имя файла [24] . Последняя строка также завершается комментарием, который означает конец исходного кода, который позволяет автоматически выбирать его из текста этой книги и проверять компилятором.

Стиль кодирования

неофициальный стандарт в Java - написание имени класса с большой буквы. Если имя класса содержит несколько слов, они идут вместе (так как вы не можете использовать подчеркивания для разделения имен), и первая буква каждого включенного слова пишется с большой буквы, как здесь:

class AllTheColorsOfTheRainbow < // . 

Относительно всего остального: методы, поля (переменные-члены) и имена ссылок на объекты принимает тот же стиль, что и для классов за исключением того, что первая буква идентификатора в нижнем регистре. Например:

class AllTheColorsOfTheRainbow < int anIntegerRepresentingColors; void changeTheHueOfTheColor(int newHue) < // . > // . >

Конечно, вы должны помнить, что пользователь тоже должен печатать все эти длинные имена, и будьте милосердны.

Java код, который вы увидите в библиотеках от Sun, следует размещению открывающих-закрывающих фигурных скобок, как вы видите в этой книге.

Резюме

В этой главе вы увидели достаточно о программировании на Java для понимания как писать простые программы, вы получили обзор языка и некоторых его основных идей. Однако все примеры имели форму “сделай это, затем сделай то, затем что-нибудь еще”. Что, если вы хотите программу для выбора, такого как “если результат выполнения красный, выполнить это; если нет, то что-нибудь другое”? Поддержка в Java для такого фундаментального программирования будет освещен в следующей главе.

Упражнения

Решения для выбранных упражнений могут быть найдены в электронной документации The Thinking in Java Annotated Solution Guide, доступной за малую плату на www.BruceEckel.com.

  1. Следуя примеру HelloDate.java из этой главы, создайте программу “hello, world”, которая просто печатает выражение. Вам необходим один метод в вашем классе (метод “main” принимает выполнение, когда программа начинается). Не забудьте сделать его статическим и включить список аргументов, даже если вы не используете его, скомпилируйте программу с помощью javac и запустите ее, используя java. Если вы используете другую среду разработки, отличную от JDK, выучите, как скомпилировать и запустит программу в этой среде.
  2. Найдите фрагмент кода, вводящий ATypeName, и включите его в программу, затем скомпилируйте и запустите.
  3. Включите фрагмент кода DataOnly в программу, затем скомпилируйте и запустите.
  4. Измените упражнение 3 так, чтобы значение данных в DataOnly назначалось и печаталось в main( ).
  5. Напишите программу, которая включает и вызывает метод storage( ), определенный как фрагмент кода в этой главе.
  6. Включите фрагмент кода StaticFun в работающую программу.
  7. Напишите программу, которая печатает три аргумента, принимаемые из командной строки. Чтобы сделать это, вам нужно ввести индекс в массив командной строки Strings.
  8. Включите AllTheColorsOfTheRainbow пример в программу, затем скомпилируйте и запустите.
  9. Найдите код для второй версии HelloDate.java, который является просто примером документации. Запустите javadoc для файла и просмотрите результат в вашем Web броузере.
  10. Включите docTest в файл, затем скомпилируйте и пропустите его через javadoc. проверьте результат в вашем Web броузере.
  11. Добавьте HTML список элементов в документацию упражнения 10.
  12. Возьмите программу в упражнении 1 и добавьте в нее комментарии-документацию. Выберите эту документацию в HTML файл, используя javadoc и просмотрите его в вашем Web броузере.

[20] Это может быть озарением. Есть те, кто может сказать: “понятно, это указатель”, но это, предположительно, лежащая в основе реализация. Также, ссылки Java во многом похожи на ссылки C++, чем на указатели с их синтаксисом. В первой редакции книги я изобрел новый термин “handle”, потому что ссылки C++ и ссылки Java имеют некоторое важное различие. Я пришел из C++ и не хочу смущать программистов C++, которые будут составлять самую большую аудиторию для Java. Во второй редакции я решил, что “ссылка” будет наиболее часто используемым термином, и тот, кто переходит с C++ будет иметь много больше для копирования с этой терминологией ссылок, так что они могут прыгнуть сразу на обе ноги. Однако есть люди, которые не согласны даже с термином “ссылка”. Я читал в одной книге, где было “абсолютно неправильно сказано, что Java поддерживает передачу по ссылке”, потому что идентификаторы объектов Java (в соответствии с авторами) реально являются ссылками на объект”. И все реально передается по значению. Так что вы не передаете по ссылке. Вы “передаете ссылку объекта по значению”. Можно было приводить доводы в пользу точности таких замысловатых объяснений, но я думаю, что мой подход упрощает понимание концепции без того, чтобы повредить чему-нибудь (адвокаты языка могут утверждать, что я лгу вам, но я скажу, что я обеспечиваю подходящую абстракцию).

[21] статические методы, которые вы скоро выучите, могут вызываться для класса без объекта.

[22] С обычным исключениями вышеупомянутых “специальных” типов данных boolean, char, byte, short, int, long, float и double. В общем, однако, вы передаете объекты, которые реально означают, что вы передаете ссылку на объект.

[23] Некоторые среды разработки высвечивают программу на экране и закрывают ее прежде, чем вы получите шанс увидеть результаты. Вы можете поместить следующий кусок кода в конец main( ) для приостановки вывода:

try  < System.in.read(); >catch(Exception e) <>

Это приостановит вывод, пока вы не нажмете “Enter” (или любую другую кнопку). Этот код включает концепцию, которая будет введена много позже в книге, так что вы не сможете понять его до этого места, но это будет работать.

#6. Вводный курс по JAVA. Методы

Методы в Java — это законченная последовательность действий (инструкций), направленных на решение отдельной задачи. По сути, это функции (они же процедуры, подпрограммы) более ранних, не ООП языков. Только эти функции являются членами классов и для различия с обычными функциями, согласно терминологии объектно-ориентированного программирования, называются методами.

Методы определяются всегда внутри классов:

public class Main < public static void foo() < // Тело метода >>

foo - это метод, который мы определили в классе Main, давайте его рассмотрим.

  • public – тип доступа (метод может вызываться из другого класса). Существуют и другие типы доступа, к примеру private (метод доступен только внутри класса) и protected (о нем мы будем говорить позже).
  • static означает что метод статический, он принадлежит классу Main, а не конкретному экземпляру класса Main. Мы можем вызвать этот метод из другого класса так: Main.foo() .
  • void значит, что этот метод не возвращает значение. Методы могут возвращать значение в Java и оно должно быть определено при объявлении метода. Однако, вы можете использовать return просто для выхода из метода.
  • Этот метод не получает никаких аргументов, но методы java могут получать аргументы, как мы увидим далее на примерах.

Если тип возвращаемого значения не void, в теле метода должен быть хотя бы один оператор

return выражение;
где тип выражения должен совпадать с типом возвращаемого значения. Этот оператор возвращает результат вычисления выражения в точку вызова метода.
Если тип возвращаемого значения – void, возврат из метода выполняется либо после выполнения последнего оператора тела метода, либо в результате выполнения оператора
return;
(таких операторов в теле метода может быть несколько).
Пример объявления метода, возвращающего значение типа int – сумму двух своих параметров типа int:

int sum(int a, int b)

При вызове метода, например, sum (5, 3) , параметры 5 и 3 передаются в метод, как значения соответственно a и b , и оператор вызова метода sum (5, 3) – заменяется значением, возвращаемым методом ( 8 ).

В отличие от языка C, в котором тип параметра, задаваемого при вызове, приводится к типу параметра в объявлении функции, тип задаваемого параметра в Java должен строго соответствовать типу параметра в объявлении метода, поэтому вызов метода sum(1.5, 8) приведет к ошибке при компиляции программы.

Не статические методы

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

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

public class Student < private String name; public String getName() < return name; >public void setName(String name) < this.name = name; >>

Вызов методов требует экземпляра класса Student .

Student s = new Student(); s.setName("Danielle"); String name = s.getName(); Student.setName("Bob"); // Не будет работать! Student.getName(); // Не будет работать!

Перегруженные методы

В языке Java в пределах одного класса можно определить два или более ме­тодов, которые совместно используют одно и то же имя, но имеют разное количество параметров. Когда это имеет место, методы называют перегру­женными, а о процессе говорят как о перегрузке метода (method overloading).

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

double sum(double a, double b)

вместе с объявленным ранее методом int sum(int a, int b)составляют пару перегруженных методов и при вызове sum(5, 8) будет вызван первый метод, а при вызове sum(5.0, 8.0) будет вызван второй метод.

По умолчанию метод, как и переменная, доступен только классам в том же пакете (наборе классов), что и исходный класс. Если перед возвращаемым типом задан модификатор доступа public, то метод является глобальным и доступен любым объектам, а модификатор private означает, что метод доступен в том классе, в котором он был объявлен, т.е. метод инкапсулирован в данном классе.

Переопределение методов

Кроме перегрузки существует также замещение, или переопределение методов (англ. overriding). Замещение происходит, когда класс потомок (подкласс) определяет некоторый метод, который уже есть в родительском классе(суперклассе), таким образом новый метод заменяет метод суперкласса. У нового метода подкласса должны быть те же параметры или сигнатура, тип возвращаемого результата, что и у метода родительского класса.

public class Thought < public void message() < System.out.println("Я себя чувствую как стрекоза, попавшая в параллельную вселенную."); >> public class Advice extends Thought < @Override // Аннотация @Override с Java 5 является необязательной, но весьма полезной public void message() < System.out.println("Внимание: Даты в календаре ближе, чем кажутся."); >>

Класс Thought представляет собой суперкласс и обеспечивает вызов метода message() . Подкласс, называемый Advice , наследует каждый метод класса Thought . Однако, класс Advice переопределяет метод message() , замещая функционал, описанный в классе Thought .

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

public class Advice extends Thought < @Override public void message() < System.out.println("Внимание: Даты в календаре ближе, чем кажутся."); super.message(); // Вызов версии метода родительского класса >>

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

Резюме

  • Каждый java-метод должен быть внутри класса
  • Статические методы принадлежат классу, а не статические методы принадлежат объектам, экземплярам класса
  • В пределах одного класса может быть два и более методов с одинаковыми именами, но разным набором параметров (перегрузка метода)
  • Класс-потомок может обеспечивать свою реализацию метода, уже реализованного в одном из родительских классов (переопределение метода)

Упражнение

Написать метод printFullName класса Student, который выводит полное ФИО студента.

Выполните упражнение, прежде чем перейти к следующему уроку.

Добавить комментарий

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