Как связать классы в 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?

Возможно глупый вопрос, но никак не могу понять, возможно ли связать каким-либо образом два файла классов, находящихся в одном пакете?
Отслеживать
задан 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 или динамический поиск метода или динамическая диспетчеризация методов.