Ошибки начинающих java-программистов. часть 2

Введение

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


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

Класс, который наследуется от другого класса, называется подклассом (subclass), дочерним классом (child class), потомком или расширенным классом (extended class).

Класс, от которого наследуется дочерний класс, называется родительским классом (parent class), предком, суперклассом (superclass) или базовым классом (base class).

В самой вершине иерархии наследования находится класс Object , от которого наследуются все классы, для которых не указан явно суперкласс. Таким образом все классы (кроме самого Object ) напрямую или через какое-либо количество уровней наследования наследуются от класса Object.

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

Дочерний класс наследует все public  и protected  члены своего родителя независимо от пакета, в котором расположен родительский класс. Если дочерний и родительский класс находятся в одном пакете, то дочерний класс наследует также package-private члены своего родителя.

  • Унаследованные поля можно использовать напрямую, как все другие поля.
  • Можно объявить в дочернем классе поле с таким же именем, как и поле в родительском классе, тогда это поле скроет (hide) поле родительского класса (НЕ рекомендуется так делать).
  • В дочернем классе можно объявлять поля, которых нет в родительском классе.
  • Унаследованные методы можно использовать напрямую.
  • Можно объявить метод экземпляров в дочернем классе с точно такой же сигнатурой, что и метод экземпляров в родительском классе, тогда этот метод переопределит (override) метод суперкласса.
  • Можно объявить в дочернем классе статический метод с точно такой же сигнатурой, что и статический метод в родительском классе, тогда этот метод скроет (hide) метод родительского класса.
  • В дочернем классе можно объявлять новые методы, которых нет в родительском классе.
  • В дочернем классе можно объявить конструктор, который будет явно (с помощью ключевого слова super ) или неявно вызывать конструктор базового класса.

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

Public Access Modifier — Public

A class, method, constructor, interface, etc. declared public can be accessed from any other class. Therefore, fields, methods, blocks declared inside a public class can be accessed from any class belonging to the Java Universe.

However, if the public class we are trying to access is in a different package, then the public class still needs to be imported. Because of class inheritance, all public methods and variables of a class are inherited by its subclasses.

Example

The following function uses public access control −

public static void main(String[] arguments) {
   // ...
}

The main() method of an application has to be public. Otherwise, it could not be called by a Java interpreter (such as java) to run the class.

Как создать класс в Java

Теперь можно приступить к созданию классов. Начнём с пользователя:

Слово public выступает модификатором доступа — он определяет, откуда будет доступен компонент. Для класса можно указать следующие модификаторы:

  • public — доступно в любых частях программы (применимо и к другим компонентам);
  • default — доступно только классам из того же пакета.

Теперь в основном файле можно создать объект класса User:

Мы указали для объекта user1 класс User, а после оператора присваивания указали ключевое слово new и запустили конструктор (об этом позже). Вот как будет выполнена программа:

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

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

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

Теперь, чтобы создать объект, нужно немного поменять код:

Дальше можно создать класс для работы с сообщениями:

Обратите внимание, что в этот раз для атрибутов from и to мы задали модификатор private, а в качестве типа стоит User. Private позволяет закрыть доступ к элементам извне — то есть их можно менять только внутри методов самого класса

Это позволяет защитить атрибуты от незапланированного доступа. Если же вы хотите получать или менять атрибуты, можно воспользоваться getter и setter. Это специальные методы, которые позволяют обратиться к защищённой переменной:

Теперь можно написать код, который будет создавать сообщение:

Вот как это работает:

Inner classes

You also have to consider nested scopes, such as inner classes. An example of the complexity is that inner classes have members, which themselves can take access modifiers. So you can have a private inner class with a public member; can the member be accessed? (See below.) The general rule is to look at scope and think recursively to see whether you can access each level.

However, this is quite complicated, and for full details, . (Yes, there have been compiler bugs in the past.)

For a taste of how these interact, consider this example. It is possible to «leak» private inner classes; this is usually a warning:

Compiler output:

Some related questions:

Notes

  • A class’s methods are allowed to access private members of other objects of the same class. More precisely, a method of class C can access private members of C on objects of any subclass of C. Java doesn’t support restricting access by instance, only by class. (Compare with Scala, which does support it using .)
  • You need access to a constructor to construct an object. Thus if all constructors are private, the class can only be constructed by code living within the class (typically static factory methods or static variable initializers). Similarly for package-private or protected constructors.

4.1 Объекты

Все в Java является объектом.

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

Что же такое объект?

Объект — это сгруппированные вместе данные и методы для того, чтобы эти данные обрабатывать. Когда мы говорим о данных, имеем в виду переменные, конечно.

Про переменные объекта говорят, что это «данные объекта» или «состояние объекта».

Про методы объекта говорят: это «поведение объекта». Состояние объекта (переменные объекта) принято менять только с помощью методов того же объекта. Менять переменные объекта напрямую (не через методы объекта) считается дурным тоном.

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

У каждого объекта есть собственная копия переменных класса (полей класса). Если в классе была объявлена нестатическая переменная int a, и ваша программа во время работы создала 10 объектов этого класса, теперь в каждом объекте есть собственная переменная int a.

Взаимодействие с объектом

Самый удобный способ работы с объектом — сохранить ссылку на объект в переменную, и потом вызывать методы у этой переменной. Выглядит это для вас знакомо:

Где — это переменная, которая хранит в себе ссылку на объект, а метод — это метод класса объекта.

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

Где — это переменная, которая хранит в себе ссылку на объект, а поле — это переменная класса (поле объекта).

Класс Object и его методы

Последнее обновление: 21.04.2018

Хотя мы можем создать обычный класс, который не является наследником, но фактически все классы наследуются от класса Object. Все остальные классы, даже те, которые мы добавляем в свой проект, являются неявно производными от класса Object. Поэтому все типы и классы могут реализовать те методы, которые определены в классе Object. Рассмотрим эти методы.

toString

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

public class Program{
     
	public static void main(String[] args) {
			
		Person tom = new Person("Tom");
		System.out.println(tom.toString()); // Будет выводить что-то наподобие Person@7960847b
	}
}
class Person {
    
    private String name;
	
    public Person(String name){
    
        this.name=name;
    }
}

Полученное мной значение (в данном случае ) вряд ли может служить хорошим строковым описанием объекта. Поэтому метод нередко переопределяют. Например:

public class Program{
     
	public static void main(String[] args) {
			
		Person tom = new Person("Tom");
		System.out.println(tom.toString()); // Person Tom
	}
}
class Person {
    
    private String name;
   
    public Person(String name){
    
        this.name=name;
    }
	
	@Override
	public String toString(){
         
        return "Person " + name;
    }
}

Метод hashCode

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

Например, выведем представление вышеопределенного объекта:

Person tom = new Person("Tom");
System.out.println(tom.hashCode()); // 2036368507

Но мы можем задать свой алгоритм определения хэш-кода объекта:

class Person {
    
    private String name;
   
    public Person(String name){
    
        this.name=name;
    }
	
	@Override
	public int hashCode(){

        return 10 * name.hashCode() + 20456;
    }
}

Получение типа объекта и метод getClass

Метод позволяет получить тип данного объекта:

Person tom = new Person("Tom");
System.out.println(tom.getClass()); // class Person

Метод equals

Метод equals сравнивает два объекта на равенство:

public class Program{
     
	public static void main(String[] args) {
			
		Person tom = new Person("Tom");
		Person bob = new Person("Bob");
		System.out.println(tom.equals(bob)); // false
		
		Person tom2 = new Person("Tom");
		System.out.println(tom.equals(tom2)); // true
	}
}
class Person {
    
    private String name;
	
    public Person(String name){
    
        this.name=name;
    }
	
	@Override
	public boolean equals(Object obj){
        
        if (!(obj instanceof Person)) return false;

        Person p = (Person)obj;
        return this.name.equals(p.name);
    }
}

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

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

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

НазадВперед

Protected Access Modifier — Protected

Variables, methods, and constructors, which are declared protected in a superclass can be accessed only by the subclasses in other package or any class within the package of the protected members’ class.

The protected access modifier cannot be applied to class and interfaces. Methods, fields can be declared protected, however methods and fields in a interface cannot be declared protected.

Protected access gives the subclass a chance to use the helper method or variable, while preventing a nonrelated class from trying to use it.

Example

The following parent class uses protected access control, to allow its child class override openSpeaker() method −

class AudioPlayer {
   protected boolean openSpeaker(Speaker sp) {
      // implementation details
   }
}

class StreamingAudioPlayer extends AudioPlayer {
   boolean openSpeaker(Speaker sp) {
      // implementation details
   }
}

Here, if we define openSpeaker() method as private, then it would not be accessible from any other class other than AudioPlayer. If we define it as public, then it would become accessible to all the outside world. But our intention is to expose this method to its subclass only, that’s why we have used protected modifier.

Access Control and Inheritance

The following rules for inherited methods are enforced −

  • Methods declared public in a superclass also must be public in all subclasses.

  • Methods declared protected in a superclass must either be protected or public in subclasses; they cannot be private.

  • Methods declared private are not inherited at all, so there is no rule for them.

java_modifier_types.htm

Previous Page Print Page

Next Page  

7.2 Отделение «описания методов» от их реализации.

Раньше мы уже рассказывали, что если вы хотите разрешить вызывать методы своего класса из других классов, то их нужно пометить ключевым словом . Если же хотите, чтобы какие-то методы можно было вызывать только из этого же класса, их нужно помечать ключевым словом private. Другими словами, мы делим методы класса на две категории: «для всех» и «только для своих».

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

Было Стало

Мы разбили наш класс на два: интерфейс и класс, унаследованный от интерфейса. И в чем тут преимущество?

Один и тот же интерфейс могут реализовывать (наследовать) различные классы. И у каждого может быть свое поведение. Так же, как и — это две различные реализации интерфейса .

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

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

Переменная суперкласса может ссылаться на объект подкласса

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

Например, переменная объявлена как , но она указывает на объект типа

Обратное не верно! Нельзя написать так:

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

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

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

Private Access Modifier — Private

Methods, variables, and constructors that are declared private can only be accessed within the declared class itself.

Private access modifier is the most restrictive access level. Class and interfaces cannot be private.

Variables that are declared private can be accessed outside the class, if public getter methods are present in the class.

Using the private modifier is the main way that an object encapsulates itself and hides data from the outside world.

Example

The following class uses private access control −

public class Logger {
   private String format;

   public String getFormat() {
      return this.format;
   }

   public void setFormat(String format) {
      this.format = format;
   }
}

Here, the format variable of the Logger class is private, so there’s no way for other classes to retrieve or set its value directly.

So, to make this variable available to the outside world, we defined two public methods: getFormat(), which returns the value of format, and setFormat(String), which sets its value.

Как работают классы в Java

Создавая программу, нужно объявить класс с её именем, а потом добавить метод main — из него начинается работа приложения:

В Java всё, что не является объектом, является классом. Даже System, с помощью которого выводится текст, — это объект.

Можно создать переменные для этого класса — атрибуты:

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

Пока не обращайте внимания на слова public и static — про них мы расскажем позже. Так же можно создавать методы, похожие на main. Для них укажите модификаторы доступа (public и static), возвращаемый тип и название:

Запустив программу, мы увидим результат работы метода GetCube():


Пока всё работает в пределах основного класса, но можно создать и другие. Для наглядности мы будем делать это на примере кода мессенджера. Здесь будут использоваться классы Сообщение (Message) и Пользователь (User).

Чтобы начать работать с классами, создайте папку для своего проекта: например, 01. Добавьте в неё ещё два каталога — src и bin. В первом будут храниться исходники, а во втором — скомпилированные файлы.

Теперь скомпилировать файл можно так:

А запустить — так:

Все классы должны находиться в отдельных файлах. которые нужно объединить в пакет. Его название должно выглядеть так: com.sitename.packagename. Хотя вы можете обойтись и без домена packagename. Чтобы создать пакет, сначала в папке src создайте следующую структуру:

В нашем случае для основного файла путь будет таким:

В тот же каталог поместите User.java и Message.java. После этого в начало каждого файла добавьте такую строчку:

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

Теперь можно компилировать программу с помощью команды:

Если вы всё сделали правильно, в папке bin появится такая же структура, как в src. Вот код корневого файла приложения:

Теперь этот код можно запустить, прописав такую команду:

Вот что выведет консоль:

Этот процесс можно ускорить, если скачать IDE. Там для добавления нового класса достаточно будет выполнить несколько действий в графическом интерфейсе. Например, в Eclipse можно нажать File -> new -> class — этого будет достаточно.

5.9 Разное

Так же есть еще 4 уникальных ключевых слова:

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

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

— тоже пришел в наследство от C++. С его помощью в код можно добавить дополнительные проверки (на то, что переменная не равна null, например). Штука в том, что он включается или выключается на этапе компиляции.

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

Ну а про модификатор и дополнительную точность процессоров Intel мы даже целую историю рассказывали.

4.4 Mutable vs Immutable объекты

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

В ответ на эту проблему в Java придумали объекты-константы. Или, как их еще называют, immutable-объекты — неизменяемые объекты.

Кстати, вы даже знаете один такой класс, чьи объекты нельзя менять — . Объект класса остается неизменным все время после создания. И как же разработчики Java добились этого?

Во-первых, все переменные класса скрыты – объявлены .

Во-вторых, наследоваться от класса нельзя: он имеет модификатор в объявлении класса.

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

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

Вот что будет в памяти после выполнения этого кода:

Так что смело передавайте ваши строки в любые методы: никто их не поменяет.

Что такое интерфейс?

Интерфейс это конструкция языка Java, в рамках которой принято описывать абстрактные публичные () методы и статические константы ().

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

Рассмотрим следующую картинку. У нас есть контракт (интерфейс), в котором описано какие действия должна выполнять мышка. Это например, клик по правой клавише и клик по левой. Разные производители мышки (классы), реализующие данный контракт (интерфейс), обязаны спроектировать мышки, у которых будут эти действия. Но как выглядят мышки, какие дополнительные опции будут иметь — все это решает сам производитель. 

Интерфейсы как и классы могут быть объявлены c уровнем доступа или .

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

Все методы интерфейса являются и эти модификаторы тоже необязательны. Объявляемые методы не содержат тел, их объявления завершаются точкой с запятой:

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

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

Класс Robot из вышеуказанной схемы:

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

Например, класс реализует только один метод интерфейса , поэтому он абстрактный:

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


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

Для указания того, что класс реализует несколько интерфейсов, после ключевого слова через запятую перечисляются нужные интерфейсы. Класс должен определить все методы реализуемых интерфейсов:

3.2 Папка src

В Java принято все классы одной программы хранить в одной папке (и ее подпапках). Такую папку обычно называют (сокращение от source).

Такая папка называется корнем проекта (source root), и все пути для пакетов считаются от нее. Примеры:

Папки Имя пакета

Программисты в такой ситуации скажут что-то типа «у нас есть проект по имени , который расположен в папке » или «у нас есть проект по имени , который расположен в папке »

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

В Java принято давать классам и пакетам осмысленные имена. Многие компании выпускают свои библиотеки (набор классов) и, чтобы не было путаницы, называют пакеты этих классов по имени компании/сайта/проекта:

Имя пакета Имя компании/проекта
org.apache.common org.apache.tomcat org.apache.util Проект «Apache»
com.oracle.jdbc Компания «Oracle»
java.iojavax.servlet Компания Oracle, проект Java
com.ibm.websphere Компания «IBM», проект WebSphere
com.jboss Проект «Jboss»

Создание объекта в Java

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

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

Создание объектов класса представляет собой двух этапный процесс:

  1. Объявление переменной типа класса. Эта переменная не определяет объект. Она является лишь переменной, которая может ссылаться на объект:

  2. Создание объекта. С помощью оператора new динамически (то есть во время выполнения) резервируется память для объекта и возвращается ссылка на него:

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

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

Добавляем методы в класс

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

Обратите внимание, что теперь мы объявляем методы нестатические (без ключевого слова static). В обоих методах мы имеем доступ к переменным класса

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

Which modifier to choose?

Access modifiers is a tool to help you to prevent accidentally breaking encapsulation(*). Ask yourself if you intend the member to be something that’s internal to the class, package, class hierarchy or not internal at all, and choose access level accordingly.

Examples:

  • A field should probably be private since it’s mutable and an implementation detail.
  • A class that should only be instantiated in a factory class (in the same package) should have a package restricted constructor, since it shouldn’t be possible to call it directly from outside the package.
  • An internal method called right before rendering and used as a hook in subclasses should be protected.
  • A method which is called from the GUI code should be public.

Что такое объект и класс в Java?

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

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

Рассмотрим картинку, приведенную ниже. Объявлен класс , у которого есть переменные и , а также методы и для установки этих значений. На основе этого класса создано несколько объектов: Jenna, John, Maria, James. У каждого объекта, то есть студента, есть  и , но они разные.

Отличие уровня доступа по умолчанию, public и private

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

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

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

3.4 Импорт классов

Имя класса + имя пакета формируют так называемое полное уникальное имя класса.

Примеры:

Полное уникальное имя Имя пакета Имя класса
отсутствует

Хорошая новость:

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

Плохая новость:

Полные имена классов обычно либо длинные, либо очень длинные. А ведь каждый раз писать в коде длинное имя, например java.util.ArrayList, очень неудобно.

Поэтому в Java добавили возможность «импортировать классы».

Вы можете использовать в своем коде короткое имя класса, но сначала вам нужно будет объяснить компилятору, какое именно «полное уникальное имя класса» соответствует короткому имени. Вдруг у вас в проекте несколько классов с таким именем. Или сначала был один, а потом еще 15 добавилось…

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

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

Пример:

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

А вот как бы выглядел этот же код, если бы мы не использовали :

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

Допустим, у вас в коллективе есть Серега, и никаких проблем с общением, не возникает — все знают кто это. Но если бы их было трое, чтобы их различать, пришлось бы использовать полные уникальные имена.

Примечание 1

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

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

Примечание 2

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


С этим читают