Если речь о Java и интерфейсах, то пример - как-то так:
interface IObserver {
void notify(Event e); //I'm a callback ;)
...
}
interface IObservable {
void register(IObserver o);
void unregister(IObserver o);
...
}
Это не столько свойство интерфейса, сколько паттерн (идея, шаблон) на тему того,
как можно в программе организовать взаимодействие (обычно, асинхронное)
между двумя сущностями. В данном конкретном примере callback - это метод
notify() в первом интерфейсе.
В простейшем случае экземпляр класса, имплементирующего этот интерфейс (наблюдатель) сначала должен зарегистрироваться у какого-нибудь экземпляра, имплементирующего второй (наблюдаемого). После этого, всякий раз, когда в наблюдаемом будет происходить что-то, интересующее наблюдателя, наблюдаемое будет вызывать метод
notify() экземпляра наблюдателя (и, например, передавать в него информацию о произошедших изменениях, в виде
Event... но это - уже частности, не существенные для понимания сути callback). И так - до тех пор, пока наблюдатель не "попрощается" с наблюдаемым, вызвав его метод
unregister(). Кроме того, кто именно "познакомит" одного с другим, тоже не существенно: это может быть сам наблюдатель, или кто-то еще (например, какая-нибудь фабрика, брокер, менеджер и т.д.) Если говорить о "свойствах интерфейса", то суть паттерна состоит в договоренности: "я знаю, что у тебя есть метод, который я могу и буду вызывать, когда сочту нужным, и ты будешь знать, что этот вызов означает". Все остальное (в каком потоке вызывать, что конкретно должен делать этот метод и т.д.) обычно тоже регламентируется, но это, опять же, уже частности.
Для сравнения и отграничения понятия callback (от банальной инкапсуляции и IoC) можно привести пример
java.lang.Comparable<T> {
int compareTo(T o);
}
Все, что обещает этот интерфейс/метод: "если ты меня вызовешь и передашь мне ссылку на экземпляр такого же класса, как я сам, я сравню себя (по некоему, только мне известному алгоритму) с этим экземпляром и верну результат". Кто его будет вызывать, когда, зачем, что он станет делать с результатом... все это самому имплементирующему классу не важно. Это, хотя и очень похоже, но, строго говоря, не укладывается в понятие callback, т.к. вызываемому методу и всему экземпляру класса, в общем, нет никакого дела до того а. кто его вызовет и б. что это будет означать. А понятие callback подразумевает, что предоставляющий этот метод класс а. знает, кто и зачем его вызовет и б. непосредственно заинтересован в этом.
Ну и, для полноты картины, нужно также упомянуть, что в разных язакых есть много разных способов организации callback. В C# есть делегаты и события, в C можно передать указатель на функцию и т.д. В Java для этого удобно пользоваться интерфейсами. Но это ничего не меняет в самом понятии callback, заключаюшемся в том, что кто-то осознанно предоставляет другому определенный метод, а этот другой этот метод вызывает, и оба знают, что означает сам факт вызова.