Java com café

Construtores - Java

Hoje vou falar sobre construtores:


Construtores são esses caras que constroem as coisas, ou melhor, objetos. Não estranhe a foto que usei para ilustrar esse post, é apenas uma homenagem ao homem trabalhador. Aquele que trabalha sob o sol, pegando no pesado, para construir nossos lares e etc. Bom, mas não vamos nos desviar do assunto.
Uma coisa é verdade: toda classe em java tem pelo menos um construtor(até abstratas, enums), exceto interfaces. Decore isto.
Mas é claro que interfaces não tem construtores, elas não fazem nada! Mas não subestime-as, elas são importantes para fornecer um acoplamento fraco entre as classes. Outro dia vou abordar este assunto.

Então mais uma vez: Todas as classes (até os enums) tem pelo menos um construtor, exceto as interfaces.
Mas o que são esses construtores? Um construtor é um "método" que é executado sempre que uma classe é instanciada. Toda vez que você digitar a palavra chave new o construtor será executado e inicializará o objeto. As vezes passamos algum parâmetro tipo new (2, 2, 2) .

Quando fazemos isto estamos inicializando a classe com os dados parâmetros. O construtor serve para inicializar as variáveis de instância da classe, como também executar códigos legais toda vez que inicializar uma classe. Entenda códigos legais como coisas que você gostaria que fossem executadas toda vez que criar um objeto, ficou claro?
Vamos ver o que é um construtor na prática:
class A {
 A(){
  super(); 
  System.out.println("Executou construtor A");
  //Códigos legais aqui
 }
}

Veja que o construtor é como um método mas ele não tem um tipo de retorno, nem void. Também tem o mesmo nome da classe e sempre terá. Ele pode ter modificador de acesso, até private (mas saiba das implicações disto). O compilador criará automaticamente um construtor igual o mostrado acima caso você não codifique nenhum. Porque ele faz isto? 

Todo construtor executa primeiramente uma chamada super() ou this() dependendo do caso, quando executado. Somente uma dessas chamadas é válida antes do resto. Mesmo que você não coloque explicitamente, o compilador irá colocar um super() pra você porque em algum momento ele vai ter que inicializar sua superclasse antes de inicializar a classe em si. 

Então você deve se perguntar se a classe A tem uma superclasse porque não está herdando de ninguém. Errado! Todas as classes herdam de Object implicitamente. Object é tipo uma classe "mãe" no Java (ela fornece métodos como equals por exemplo).
Se temos duas classes A e B, com B herdando A, quando criamos uma instância de B os construtores são executados em forma de pilha: B chama A e A chama Object. Object é executado, A é executado e por último B:

OBJECT
A
B

Mais adiante vou mostrar o resultado disto. Antes de continuar vamos rever alguns conceitos. Quando você digitar:

class A {
}

Seu compilador irá adicionar automaticamente o construtor:
class A {
 A(){
  super(); 
 }
}

O contrutor criado por ele sempre será sem argumentos. E se digitar só:
 
class A {
 A(){
 }
}

Não tem problema, o compilador adicionará o super();
O compilador só não vai fazer nada se for adicionado um construtor sobrecarregado:

class A {
 A(String s){
  super(); 
  System.out.println("Executou construtor A");
  //Códigos legais aqui
 }
}

Isso mesmo! Construtores podem ser sobrecarregados (mas não sobrescritos porque não são herdados), mas lembre-se:

Se houver um construtor sobrecarregado qualquer, o compilador não vai criar outro automaticamente
Sabendo disto você não cairá em pegadinhas do tipo:
class A {
 A(String s){
  super(); 
  System.out.println("Executou construtor A");
  //Códigos legais aqui
 }
}

public class B extends A{
 
 public static void main(String[] args) {
  new B();
 }
 
}

Acontece que a classe B possui aquele construtor automático que falei anteriomente. E na classe A, por ter definido um construtor sobrecarregado, não temos o construtor padrão sem argumentos, então código não compila:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Implicit super constructor A() is undefined for default constructor. Must define an explicit constructor

at B.(B.java:10)
at B.main(B.java:13)

Sempre tente detectar isto quando uma questão abordar construtores e como funciona a pilha. Logicamente o código terá mais alguma lógica obscura tentando lhe desviar do problema e tentando esconder o obvio. Neste caso, para resolver o problema, você mesmo deve criar construtor em A sem argumentos ou em B passando o parametro como pede:
 B(String s) {
  super(s);
 }

E a chamada a B deverá ser:

  new B(null);

Veja que o construtor de B recebe o parâmetro e o passa para a superclasse, isto é perfeitamente possível.
Um ponto importante é que nada pode ser feito sem que o construtor seja executado. Nenhum acesso a variável de instância ou método antes que o super() final seja chamado e construa Object. Isto que dizer que um objeto não pode ser utilizado até ser inicializado, o que é obvio, mas também significa que você não pode tentar sabotar o construtor do objeto antes de chamar super():
class A {
 A(String s){
  System.out.println("Antes de executar o super de Object");
  super(); // Problema!!!
  System.out.println("Executou construtor A");
  //Códigos legais aqui
 }
}

Outra coisa é que um construtor pode chamar outro. Um construtor só pode ser chamado dentro de outro. Isto que dizer que ou você chama outro construtor da mesma classe que tenha sido sobrecarregado utilizando o this() ou chama o da superclasse utilizando super(). Como já foi dito, somente uma dessas chamadas poderá ser feita dentro do contrutor e deverá ser a primeira coisa a ser feita.
public class B{
 B() {
  super();
  System.out.println("Executou o construtor padrão.");
 }

 B(String s){
  this();
  System.out.println("Chamou o construtor padrão.");
 }
 
 public static void main(String[] args) {
  new B(null);
 }
}

Veja que o código produz a seguinte saída:

Executou o construtor padrão.
Chamou o construtor padrão.



A saída é "invertida" por causa da pilha. O main chamou o construtor B sobrecarregado, antes de qualquer coisa ele chamou B padrão que chamou super(). Então Object foi criado e volta pra B padrão, então é executado. Volta para o B sobrecarregado e mostra que "Chamou.." no final, ele ja tinha chamado mas estava esperando os outros.
Agora veja o seguinte exemplo:
class A {
 void A(){
  super();
  System.out.println("Executou construtor A");
  //Códigos legais aqui
 }
}

O que tem de errado com a classe? Não... aquilo não é um construtor, é apenas um método qualquer porque ele tem um tipo de retorno e construtores não tem. Tome cuidado.
Só pra finalizar o post porque já está ficando cansativo, analise este código:
class A {
 A(){
  System.out.println("A");
 }
}

class B extends A{
 B() {
  System.out.println("B");
 }
}

public class C extends B{
 C() {
  System.out.println("C");
 }
 
 public static void main(String[] args) {
  new C();
 }
}

Qual será a saída?? Não vou responder...
Bons estudos e até a próxima!

Modificadores de acesso - Java

Hoje vou mudar de assunto e falar um pouco sobre Java. Assim como outras linguagens de programação, o Java tem níveis de acesso que podemos definir para classes, métodos e variáveis. Existem 3 modificares de acesso: Public, Protected e Private. Mas os níveis de acesso são 4, porque implicitamente se nenhum desdes modificadores forem usados o acesso é definido como Default.
Os níveis de acesso podem dizer se um método por exemplo pode ser acessado somente pela classe, por outras classes dentro do seu pacote ou fora dele:
Classe > Pacote > Global

Public e Private

Primeiramente, se você está começando a aprender agora, entenda estes dois modificadores pois são os mais simples. O Public é o menos restritivo de todos. Ele permite que sua classe, método ou variável possa ser acessada globalmente no projeto.
O Private é o mais restritivo. Ele permite que sua variável ou método só seja visto dentro da classe em que se encontra. Classes e interfaces não podem ser Private (nem Protected).
Private é muito usado para encapsular atributos da classe. Neste caso, o acesso aos atributos é feito por um método Public que poderá validar os dados, por exemplo:
private int x = 0;

A variável não poderia ser acessada diretamente. Somente através do método:
 public void setX(int x){
if (x > 0){
this.x = x;
}
}

Default

Default é o nível de acesso usado quando não colocamos nenhum modificador:
 class Animal{}
Quando não usamos modificadores, estamos dizendo que a classe, método ou variável só é visível dentro do seu pacote. O Default então cria uma restrição de pacote. Por este motivo ele é o meio termo entre o Private e Public.

Protected

O Protected é o mais incompreendido de todos. Ele é parecido com Default (restrição de pacote) mas permite que o membro seja acessado através de herança. Isto gera uma certa confusão mas preste atenção: O método ou variável protected só pode ser acessado de fora do pacote através da herança e nunca diretamente! Vejamos o que estou querendo dizer:

package Superclasse;

public class Animal {

private int x = 1;

protected int getX() {
return x;
}
}
Temos um pacote Superclasse contendo a classe Animal. Animal tem uma variável x private e um método protected para retornar o valor desta variável. Até aí tudo bem, vamos criar uma classe em outro pacote que herde de Animal:

package Subclasse;
import Superclasse.Animal;

public class Homem extends Animal{

public static void main(String[] args) {

Homem homem = new Homem();
System.out.println(homem.getX()); //Ok, homem herda de animal
}
}

Vimos que homem herda o método protected getX de Animal. Mas agora tente fazer o seguinte:
package Subclasse;
import Superclasse.Animal;

public class Homem extends Animal{

public static void main(String[] args) {

Homem homem = new Homem();
System.out.println(homem.getX());


Animal animal = new Animal();
System.out.println(animal.getX()); //Erro, tentou acessar diretamente

}
}
Ao tentar acessar o método getX através da instancia de Animal, fazendo isto diretamente o código não compila e mostra o seguinte erro:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method getX() from the type Animal is not visible

at Subclasse.Homem.main(Homem.java:13)

E se outra classe de outro pacote instanciar Homem, terá acesso ao método? Não, novamente somente através da herança poderá ter acesso.
Para não esquecer como isso funciona eu imaginei a seguinte situação: Temos o pai, o filho e o amigo do filho. O pai tem dinheiro e pode gastá-lo. Ele dá a mesada ao filho. O filho pode gastar a mesada, mas nunca o dinheiro do pai. O filho pode emprestar dinheiro ao amigo. O amigo pode gastar o dinheiro emprestado, mas nunca o do filho e nem o do pai. Resumindo, você pode ter acesso ao que lhe foi dado, mas não pode acessar de quem lhe deu.
Espero ter deixado claro o funcionamento do protected.

Bons estudos!

Calculo do Overhead em transmissões digitais - Redes

Qual a eficiência de um determinado meio de transmissão digital?

Esta é uma questão que o calculo de overhead pode responder.
Quando dados são transmitidos digitalmente, os bits de dados não são simplesmente enviados de qualquer forma pela portadora. Existem bits de controle que servem para indicar quando a transmissão vai iniciar e finalizar, entre outros propósitos.
Overhead nada mais é do que uma grande quantidade destes bits de controle na transmissão, fazendo com que parte da banda que deveria ser usada para transmitir dados, esteja transmitindo bits de controle.
Ok, então o overhead pode ser calculado como uma razão entre os bits de controle e a soma de todos os bits transmitidos:
Overhead = (bits de controle / (bits de controle + bits de dados)) x 100
Também deve ser levado em conta o meio de transmissão utilizado. No caso de uma transmissão síncrona, os bits de controle vêm somente no inicio e no final da transmissão. E assíncrona, a cada byte transmitido, os bits de controle estão lá. Isto porque como não é sincronizada, não se sabe quando está vindo um dado.
Vamos transmitir a frase “CLUSTER ONE”, e foi dado que os bits de START são 2 e apenas 1 bit para STOP. No caso de uma transmissão síncrona seria:
Overhead = (3 / (11 * 8) + 3) * 100 = 3,29 %

Temos 11 * 8 porque cada letra é um byte, contando com o espaço. Todos os valores devem estar na mesma medida, neste caso são bits. 3,29 é um overhead aceitável.
No caso de uma transmissão assíncrona, cada byte é acompanhado dos bits de controle:
Overhead = ((3 * 11) / (11 * 8) + (3 * 11)) * 100 = 27,27%

Com isto, vimos que as transmissões assíncronas são pouco eficientes comparadas as transmissões síncronas.

Editado 20/10/2011: Obrigado a leitora Roberta de Carvalho Nobre por ter observado que tinha um erro na soma dos bits de controle.