Vamos por partes.
Você entende que isso FloatingActionButton fab ou suas variações private FloatingActionButton fab; ou FloatingActionButton fab = null; é a declaração da variável fab?
Declaração de uma variável é a indicação ao compilador (e, depois, à JVM) que você poderá utilizar, em algum momento, um espaço de memória onde irá criar (ou já existe) um objeto compatível com o tipo da variável declarada.
Partindo daí, temos o seguinte, o Java (o “normal” e o utilizado no Android) permite a declaração e instanciação de objetos a qualquer tempo (algumas linguagens limitam a declaração de variáveis a locais específicos no código).
Instanciação é isso: int x = 10; ou String nome = "Adão";, ou seja, atribuir à variável declarada um correspondente que se adeque ao tipo declarado. Este tipo deve ser capaz de “armazenar” o objeto/primitivo compatível ou menor que ele.
Por exemplo: int x = 10; ou long x = 10; ou Serializable teste = "Teste 123"; (aqui String é uma implementação da interface Serializable).
No caso do Android, a arquitetura definida diz que cada elemento das telas (que são definidos nos activity_xxxx.xml) terá um identificador único (o famoso id) dentro da classe R.
Assim sendo, quando você cria um EditText na tua tela, a IDE que você está utilizando já declara o objeto correspondente na classe R e associa a este um identificador único (o id) que, por questões de amarração, possui o mesmo nome dado ao elemento no xml do layout.
A partir daí, utilizar o método herdado da classe Activity, findViewById(int) é simples e intuitivo.
O findViewById irá, a partir do id (que é uma constante da classe R), devolver uma instância da classe View (android.view.View).
Lembra do que disse acima? Que uma variável declarada deve ser capaz de receber um objeto compatível ou “menor”? Pois é, aqui entra uma outra característica do java. Quando declaramos e instanciamos long x = 10;, estamos colocando um número inteiro (32 bits) em um long (64 bits). Agora, se formos utilizar: long x = 10; int y = x; Teremos erro de compilação.
Para corrigir isso, uma vez que o int tem capacidade de armazenar números menores que o long, precisamos forçar o cast long x = 10; int y = (int) x;
O mesmo ocorre com o findViewById. Por devolver uma instância de View, é obrigatório ao desenvolvedor realizar o cast (downcasting, na verdade), adequando o objeto recebido ao tipo declarado para a variável.
Resumindo, o casting ocorre quando o método findViewById já foi completamente executado e já retornou o objeto desejado.