Перейти к содержимому

Как связать классы в java

  • автор:

Как связать классы в java

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

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

Рассмотрим пример: у нас есть интерфейс Animal , который определяет методы для работы с животными. Класс Dog реализует интерфейс Animal и реализует методы интерфейса.

interface Animal  void eat(); void sleep(); > class Dog implements Animal  public void eat()  System.out.println("Dog is eating"); > public void sleep()  System.out.println("Dog is sleeping"); > > 
  • Здесь мы определяем интерфейс Animal , который имеет два абстрактных метода eat() и sleep() .
  • Затем мы определяем класс Dog , который реализует интерфейс Animal и реализует оба метода.

Когда мы создаем объект Dog , мы можем вызывать методы eat() и sleep() , определенные в интерфейсе Animal

Dog myDog = new Dog(); myDog.eat(); // => Dog is eating myDog.sleep(); // => Dog is sleeping 

Ключевое слово implements позволяет связать класс и интерфейс. Если класс реализует несколько интерфейсов, они перечисляются через запятую в списке implements

interface Animal  void eat(); > interface Sleepable  void sleep(); > class Dog implements Animal, Sleepable  public void eat()  System.out.println("Dog is eating"); > public void sleep()  System.out.println("Dog is sleeping"); > > 

Здесь класс Dog реализует два интерфейса Animal и Sleepable

можно ли как-то связать два исходных файла классов в java?

вот 2 класса, обведены красным

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

Отслеживать
задан 18 ноя 2018 в 17:35
37 6 6 бронзовых знаков
а что имеется в виду под «связать?»
18 ноя 2018 в 17:36

в одном файле только один public-класс. Если в двух файлах только один класс объявлен как public, то можно затолкать в один общий файл все. Если оба класса public, то только в двух файлах хранить

18 ноя 2018 в 17:43

@Maxgmer например, в 1-ом файле выполняется одно какое-то действие, а во 2-ом другое и чтобы они работали вместе, в одной программе

18 ноя 2018 в 20:24

@ТимурБаймагамбетов а если оба класса public, можно ли как-то, так скажем, передать данные из 2-го класса в первый?

18 ноя 2018 в 20:27

конечно. Можно в методе одного класса вызвать Class2 class2 = new Class2(); и далее вызвать его метод class2.foo();

1 дек 2018 в 14:29

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

То что вы хотите реализовать называется зависимостью.

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

Class Human < Dog dog; void walkWithDog(int speed) < walk(speed); dog.runAround(this, speed *2); >void walk(int speed) < // do somthing >> 

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

Вы усложняете класс Human , но заставляете собаку бегать. Есть и другие способы наладить зависимости между классами, например Аспектно-ориентированное программирование.

Отношения между классами

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

1. IS-A отношения

В ООП принцип IS-A основан на наследовании классов или реализации интерфейсов. Например, если класс HeavyBox наследует Box , мы говорим, что HeavyBox является Box ( HeavyBox IS-A Box ). Или другой пример — класс Lorry расширяет класс Car . В этом случае Lorry IS-A Car .

То же самое относится и к реализации интерфейсов. Если класс Transport реализует интерфейс Moveable , то они находятся в отношении Transport IS-A Moveable .

2. HAS-A отношения

HAS-A отношения основаны на использовании. Выделяют три варианта отношения HAS-A: ассоциация, агрегация и композиция.

Начнем с ассоциации. В этих отношениях объекты двух классов могут ссылаться друг на друга. Например, класс Horse HAS-A Halter если код в классе Horse содержит ссылку на экземпляр класса Halter :

Ассоциация

public class Halter <> 
public class Horse

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

Агрегация

Объект класса Halter создается извне Horse и передается в конструктор для установления связи. Если объект класса Horse будет удален, объект класса Halter может и дальше использоваться, если, конечно, на него останется ссылка:

public class Horse < private Halter halter; public Horse(Halter halter) < this.halter = halter; >> 

Композиция

Теперь посмотрим на реализацию композиции. Объект класса Halter создается в конструкторе, что означает более тесную связь между объектами. Объект класса Halter не может существовать без создавшего его объекта Horse:

public class Horse < private Halter halter; public Horse() < this.halter = new Halter(); >>

Как связать классы в java

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

class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >>

И, возможно, впоследствии мы захотим добавить еще один класс, который описывает сотрудника предприятия — класс Employee. Так как этот класс реализует тот же функционал, что и класс Person, поскольку сотрудник — это также и человек, то было бы рационально сделать класс Employee производным (наследником, подклассом) от класса Person, который, в свою очередь, называется базовым классом, родителем или суперклассом:

class Employee extends Person < public Employee(String name)< super(name); // если базовый класс определяет конструктор // то производный класс должен его вызвать >>

Чтобы объявить один класс наследником от другого, надо использовать после имени класса-наследника ключевое слово extends , после которого идет имя базового класса. Для класса Employee базовым является Person, и поэтому класс Employee наследует все те же поля и методы, которые есть в классе Person.

Если в базовом классе определены конструкторы, то в конструкторе производного классы необходимо вызвать один из конструкторов базового класса с помощью ключевого слова super . Например, класс Person имеет конструктор, который принимает один параметр. Поэтому в классе Employee в конструкторе нужно вызвать конструктор класса Person. То есть вызов super(name) будет представлять вызов конструктора класса Person.

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

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

public class Program < public static void main(String[] args) < Person tom = new Person("Tom"); tom.display(); Employee sam = new Employee("Sam"); sam.display(); >> class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >> class Employee extends Person < public Employee(String name)< super(name); // если базовый класс определяет конструктор // то производный класс должен его вызвать >>

Производный класс имеет доступ ко всем методам и полям базового класса (даже если базовый класс находится в другом пакете) кроме тех, которые определены с модификатором private . При этом производный класс также может добавлять свои поля и методы:

public class Program < public static void main(String[] args) < Employee sam = new Employee("Sam", "Microsoft"); sam.display(); // Sam sam.work(); // Sam works in Microsoft >> class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >> class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company=company; >public void work() < System.out.printf("%s works in %s \n", getName(), company); >>

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

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

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

public class Program < public static void main(String[] args) < Employee sam = new Employee("Sam", "Microsoft"); sam.display(); // Sam // Works in Microsoft >> class Person < String name; public String getName()< return name; >public Person(String name) < this.name=name; >public void display() < System.out.println("Name: " + name); >> class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company=company; >@Override public void display() < System.out.printf("Name: %s \n", getName()); System.out.printf("Works in %s \n", company); >>

Перед переопределяемым методом указывается аннотация @Override . Данная аннотация в принципе необязательна.

При переопределении метода он должен иметь уровень доступа не меньше, чем уровень доступа в базовом класса. Например, если в базовом классе метод имеет модификатор public, то и в производном классе метод должен иметь модификатор public.

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

class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company=company; >@Override public void display() < super.display(); System.out.printf("Works in %s \n", company); >>

С помощью ключевого слова super мы также можем обратиться к реализации методов базового класса.

Запрет наследования

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

public final class Person

Если бы класс Person был бы определен таким образом, то следующий код был бы ошибочным и не сработал, так как мы тем самым запретили наследование:

class Employee extends Person

Кроме запрета наследования можно также запретить переопределение отдельных методов. Например, в примере выше переопределен метод display() , запретим его переопределение:

public class Person < //. public final void display()< System.out.println("Имя: " + name); >>

В этом случае класс Employee не сможет переопределить метод display.

Динамическая диспетчеризация методов

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

Person sam = new Employee("Sam", "Oracle");

Так как Employee наследуется от Person, то объект Employee является в то же время и объектом Person. Грубо говоря, любой работник предприятия одновременно является человеком.

Однако несмотря на то, что переменная представляет объект Person, виртуальная машина видит, что в реальности она указывает на объект Employee. Поэтому при вызове методов у этого объекта будет вызываться та версия метода, которая определена в классе Employee, а не в Person. Например:

public class Program < public static void main(String[] args) < Person tom = new Person("Tom"); tom.display(); Person sam = new Employee("Sam", "Oracle"); sam.display(); >> class Person < String name; public String getName() < return name; >public Person(String name) < this.name=name; >public void display() < System.out.printf("Person %s \n", name); >> class Employee extends Person < String company; public Employee(String name, String company) < super(name); this.company = company; >@Override public void display() < System.out.printf("Employee %s works in %s \n", super.getName(), company); >>

Консольный вывод данной программы:

Person Tom Employee Sam works in Oracle

При вызове переопределенного метода виртуальная машина динамически находит и вызывает именно ту версию метода, которая определена в подклассе. Данный процесс еще называется dynamic method lookup или динамический поиск метода или динамическая диспетчеризация методов.

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

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