Modificadores de Acesso e Herança

JavaBeginner
Pratique Agora

Introdução

Neste laboratório, você aprenderá sobre modificadores de acesso e herança. Com diferentes modificadores, os níveis de acesso são diferentes. A herança em Java é semelhante à herança biológica, pois os filhos podem manter as características dos pais e se comportar de maneira diferente em alguns aspectos.

Este é um Lab Guiado, que fornece instruções passo a passo para ajudá-lo a aprender e praticar. Siga as instruções cuidadosamente para completar cada etapa e ganhar experiência prática. Dados históricos mostram que este é um laboratório de nível iniciante com uma taxa de conclusão de 92%. Recebeu uma taxa de avaliações positivas de 100% dos estudantes.

Modificadores de Acesso

Até agora, já escrevemos algum código. No laboratório anterior, escrevemos uma classe. Existem alguns modificadores como public e private. Então, o que essas palavras significam?

Java fornece vários modificadores de acesso para definir os níveis de acesso para classes, variáveis, métodos e construtores. Os quatro níveis de acesso são:

  • default: Visível para o pacote, o padrão. Nenhum modificador é necessário.
  • private: Visível apenas para a classe que o define.
  • public: Visível para o Universo Java (todos os tipos). Você pode acessá-los em qualquer lugar.
  • protected: Visível para o pacote e todas as subclasses (mesmo aquelas em outros pacotes).
Diagrama de modificadores de acesso Java

Java fornece vários modificadores não-acesso para alcançar muitas outras maneiras de ajustar o comportamento:

  • static: Este modificador é usado para criar variáveis ou métodos que existirão independentemente de qualquer instância da classe. Apenas uma cópia da variável static existe para a classe, independentemente do número de instâncias criadas.
  • final: Uma variável final pode ser explicitamente inicializada apenas uma vez. Um método final não pode ser sobrescrito por nenhuma subclasse. Uma classe é declarada como final para impedir que a classe seja subclassificada.
  • abstract: Uma classe abstract nunca pode ser instanciada. Um método abstract é um método declarado sem nenhuma implementação.
  • synchronized/volatile: Os modificadores synchronized e volatile são usados em conexão com threads.

Exemplo:

Escreva o seguinte código no arquivo /home/labex/project/modifierTest.java:

public class modifierTest {
    // static variables are initialized when class is loaded.
    public static int i = 10;
    public static final int NUM = 5;
    // non-static variables are initialized when object is created.
    public int j = 1;

    /*
     * static code block here, this will execute when the class is loaded
     * creating new object will not execute the block again, run only once.
    */
    static{
        System.out.println("this is a class static block.");
    }
    public static void main(String[] args)
    {
        System.out.println("this is in main method");

        // you can access i and change it
        modifierTest.i = 20;  //the same with obj.i = 20
        System.out.println("Class variable i = " + modifierTest.i);
        // you can access NUM, but can't change it
        // HelloWorld.NUM = 10;     this will cause an error, NUM is final, it's immutable
        System.out.println("Class variable NUM = " + modifierTest.NUM);

        // create new object
        modifierTest obj = new modifierTest();
        // we can use both class and object to access static methods and static properties
        obj.staticMethod();  // the same with modifierTest.staticMethod()
        // you can't access j like this: modifierTest.j
        System.out.println("Object variable j = " + obj.j);
    }
    // the constructor, only new object being created will call this.
    public modifierTest(){
        System.out.println("this is in object's constructor.");
    }
    public static void staticMethod(){
        System.out.println("this is a static method");
    }
}

Saída:

Execute o arquivo modifierTest.java usando os seguintes comandos:

javac /home/labex/project/modifierTest.java
java modifierTest

Veja a saída:

this is a class static block.
this is in main method
Class variable i = 20
Class variable NUM = 5
this is in object's constructor.
this is a static method
Object variable j = 1

Herança

Em muitos casos, escrevemos uma classe. E, então, precisamos escrever uma nova classe apenas para modificar um pouco do código da classe anterior, e elas têm alguma relação na lógica. Podemos usar a herança aqui. Usamos a palavra-chave extends para implementar a herança. Subclasses obtêm todas as propriedades e métodos acessíveis da superclasse por herança, e subclasses também podem ter os seus próprios especiais. Em subclasses, podemos acessar aqueles que são declarados na superclasse como public ou protected, mas os private não podemos acessar diretamente. Veja um exemplo: A estrutura de herança é mostrada na imagem. Você pode implementar herança multinível (horizontal) ou herança hierárquica (vertical):

Diagrama da estrutura de herança

Exemplo:

Escreva o seguinte código no arquivo /home/labex/project/inheritanceTest.java:

class Animal{
    // what kind of animal i am.
    private String species;
    private int age = 8;

    public Animal(){
        System.out.println("Animal's constructor");
    }
    public void grow(){
        // In this class, we can access the private properties directly.
        System.out.println("I'm "+ this.age + " years old, " +"I grow up.");
    }
}
class Dog extends Animal{
    private String color;
    // In this class, we can't access superclass private attributes, but grow() is ok.
    public Dog(){
        System.out.println("Dog's constructor");
    }
    public void run(){
        this.grow();
        System.out.println("I'm dog, I can run.");
    }
}
class Bird extends Animal{
    private double weight;

    public Bird(){
        // if explicitly invoke superclass constructor, it must be at the first line here.
        // super();
        System.out.println("Bird's constructor");
    }
    public void fly(){
        this.grow();
        System.out.println("I'm bird, I can fly.");
    }
}
public class inheritanceTest{
    public static void main(String[] args){
        Dog dog = new Dog();
        dog.run();

        Bird bird = new Bird();
        bird.fly();
    }
}

Saída:

Execute o arquivo inheritanceTest.java usando os seguintes comandos:

javac /home/labex/project/inheritanceTest.java
java inheritanceTest

Veja a saída:

Animal's constructor
Dog's constructor
I'm 8 years old, I grow up.
I'm dog, I can run.
Animal's constructor
Bird's constructor
I'm 8 years old, I grow up.
I'm bird, I can fly.

Quando você vê esta saída, pode ficar confuso. Não se preocupe; explicaremos o porquê. Quando criamos um objeto de uma subclasse usando new, ele, por padrão, primeiro invoca o construtor padrão da superclasse da estrutura de árvore de herança "de cima para baixo" e, por último, executa seu próprio construtor. O construtor da superclasse pode ser chamado explicitamente usando a palavra-chave super, mas ele deve ser a primeira instrução em um construtor, se estiver lá. A palavra-chave super se refere à superclasse, imediatamente acima da classe de chamada na hierarquia.

Resumo

Com os modificadores de acesso, podemos escrever código seguro, ocultar detalhes e alcançar o controle de acesso. Outros usuários não precisam saber como implementamos os detalhes dos métodos. Fornecemos uma interface para outros invocadores. Para modificadores de acesso, você pode ler as bibliotecas de código-fonte Java para entender qual é a diferença. A herança, lembre-se da estrutura hierárquica, é a relação entre as classes.