Ваше замешательство исходит из вашего понимания композиции. Объект, принадлежащий другому, зависит от времени жизни объекта-владельца. Это не означает, что вам нужно создать принадлежащий ему объект внутри класса владельца.
Если вы создаете объекты в классе, этот класс тесно связан с созданным классом. Вы не можете обменять реализацию, не меняя класс, который создает другой.
Пример: 
На картинке выше вы имеете класс клиента, который использует класс Server. Допустим, что это композиция, и у Клиента есть атрибут типа Server.
Если вы создаете экземпляр класса сервера внутри класса клиента, он может выглядеть следующим образом:
public class Client {
private Server server;
public Client(){
this.server = new Server();
}
}
Теперь предположим, вы хотите обменять реализацию сервера. Вам нужно изменить реализацию класса Client, потому что единственный способ его обмена - создать экземпляр другого класса (возможно, называется AnotherServer).
public class Client {
private AnotherServer anotherServer;
public Client(){
this.anotherServer = new AnotherServer();
}
}
Это показывает, что класс Client сильно зависит от класса Server.
Чтобы легко изменить используемую реализацию Сервера и, таким образом, изменить поведение Клиента, было бы лучше составить клиент из абстракций (абстрактных классов или интерфейсов). Это означает, что вы не можете создать нужный объект в собственном классе, потому что вы можете создавать только конкретные классы. Создание классов означает вызов конструктора и зависящий от этого класса, который был создан.
Лучший способ достижения композиции (- Клиент состоит из сервера) - путем инъекции его через метод сеттера или конструктор. Подобно этому вы можете скрыть классы реализации за интерфейсом.
Пример: 
На втором рисунке мы защитить клиента от знания о конкретной реализации сервера. Это зависит только от интерфейса сервера. Эта зависимость не настолько драматична, потому что Клиент определяет интерфейс. Он решает о необходимой функции интерфейса сервера. Чтобы указать, что интерфейс для серверов принадлежит клиенту, он называется «ClientServer».
Для составления вашего Клиента вам необходимо создать конкретные классы для интерфейса ClientServer вне класса и ввести его через конструктор или метод setter.
...
FirstServer first = new FirstServer();
Client client = new Client(first);
client.setServer(new SecondServer());
...
Нравится программа? Поделись с друзьями!
Этот механизм называется принципом инверсии зависимостей (DIP). Но почему? Класс Client по-прежнему зависит от интерфейса сервера. Если интерфейс изменяется, Клиент также должен измениться. Да, это правильно. Но Клиент решает, какие функции ему нужны в этом интерфейсе. Поэтому обычно интерфейс изменяется, когда Клиент говорит, что его нужно изменить. Интерфейс изменяется, поскольку Клиент изменяется.
Поскольку конкретные серверы «FirstServer» и «SecondServer» реализуют интерфейс ClientServer, они также зависят от этого интерфейса. И поскольку наследование является более сильной зависимостью, чем состав, конкретные классы серверов в большей степени зависят от интерфейса, чем от класса Client.
Именно поэтому зависимости инвертированы. Конкретные классы серверов теперь зависят от «Client-ClientServer» -колонтера.
Итак, ответ на ваш вопрос: вы не можете достичь DIP при создании своего класса внутри другого класса. Но вы можете достичь DIP с композицией, определив интерфейс, введя конкретные классы, которые наследуют этот интерфейс.
Я не вижу здесь никакого противоречия. Объект состоит из некоторых других объектов, которые передаются ему в конструкторе, и что? –
Я думаю, вы смешиваете зависимости между классами и зависимостями между объектами. Конечно, составной объект зависит от его компонентов. Но это не означает, что существуют зависимости между классами, если вы используете абстракции (интерфейсы). –
@FrankPuffer можно использовать композицию, используя инъекцию зависимостей? – justsomedev