Oi Taina,
O da classe Data segue a mesma ideia de passar o Funcionario para a Empresa.
Imagine que você queira colocar uma data de admissão na classe Funcionario e você tenha a seguinte classe Data:
class Data {
    int dia;
    int mes;
    int ano;
    Data(int dia, int mes, int ano) {
        this.dia = dia;
        this.mes = mes;
        this.ano = ano;
    }
}
Aí você precisa acrescentar um atributo do tipo Data pois o Funcionario TEM uma dataAdmissao. Sua classe Funcionario ficaria:
class Funcionario {
    Data dataAdmissao;
    String nome;
    // outros atributos
    Funcionario(String nome) {
        this.nome = nome;
    }
}
Na hora de colocar a dataAdmissao no  Funcionario você precisa primeiro criar o objeto do tipo Data (através do new)  e depois passar a referência deste objeto para o Funcionario. Ficaria assim o código com o main:
class TestaFuncionario {
    public static void main(String [] args) {
        Data dataDeHoje = new Data(15, 7, 2016);
        Funcionario taina = new Funcionario("Taina");
        taina.dataAdmissao = dataDeHoje;
    }
}
Deste jeito você consegue copiar a referência da dataDeHoje para o objeto referenciado pela variável taina.
Quanto a sua outra dúvida: entao se eu colocar if empregados == null, nao daria?
Dá sim! Você pode fazer tanto:
void adiciona (Funcionario f) {
    for (int i = 0; i < funcionarios.length; i++) {
        if (funcionarios[i] == null) {
            this.funcionarios[i] = f;
        } else {
            continue;
        }
    }
}
quanto:
void adiciona(Funcionario f) {
    if (this.livre < this.empregados.length) {
        this.empregados[this.livre] = f;
        this.livre++;
    }
}
Não tinha entendido sua dúvida anterior, as duas soluções funcionam, na segunda você só precisa verificar se ainda tem posições livres no array, conforme fiz acima.
Abraço!