Compreendendo a palavra-chave estática


15

Tenho alguma experiência no desenvolvimento de Java, Javascript e PHP.

Estou lendo o Microsoft Visual C # 2010 passo a passo, que considero um livro muito bom sobre como apresentar a linguagem C #.

Parece que estou tendo problemas para entender a palavra-chave estática. Pelo que entendi até agora, se uma classe é declarada estática, todos os métodos e variáveis ​​devem ser estáticos. O método principal sempre é um método estático, portanto, na classe em que o método principal existe, todas as variáveis ​​e métodos são declarados estáticos se você precisar chamá-los no método principal. Também notei que, para chamar um método estático de outra classe, você não precisa criar um objeto que possa usar o nome da classe.

Mas qual é o objetivo real da palavra-chave estática? Quando devo declarar métodos e variáveis ​​estáticas?


4
estático em C # é quase o mesmo que estático em Java. Se você compreendê-lo em Java, você não deve ter quaisquer problemas em C #
SuperM

Java foi a minha primeira linguagem de programação e eu não entendi este conceito either.I lá só tenho usado Java por um curto período de tempo
Nistor Alexandru

Resumindo: use "estático" quando não precisar de orientação para objetos, por exemplo, apenas alguns métodos ou variáveis ​​independentes. Declarar uma classe como estática significa colocar essas variáveis ​​e funções não orientadas a objetos apenas em um nome comum (espaço), o nome da classe.
Doc Brown

Respostas:


14

A palavra-chave 'estática' em C # refere-se a algo na classe, ou a própria classe, que é compartilhada entre todas as instâncias da classe. Por exemplo, um campo marcado como estático pode ser acessado de todas as instâncias dessa classe através do nome da classe.

public class SomeObject
{
    //Static Field
    static int Foo = 3;

    //instance field
    private int _Foo2 = 4;

    //instance property
    public int Foo2{get{return _Foo2;}set{_Foo2 = value;}}


    //static factory method
    public static SomeObject CreateSomeObject(int fooValue)
    {
        SomeObject retVal = new SomeObject();
        retVal.Foo2 = fooValue;
        return retVal;
    }

    //Parameterless instance constructor
    public SomeObject()
    {
    }

    public static int Add(int x)
    {
        //Static methods can only deal with local variables, or fields that
        //  are also static in the class.  This one adds x to the static member foo
        return x + Foo;

        //Foo2 is not accessable here!
    }

      //Instance method
    public int AddSomething(int x)
    {
        //Add x to the property value of Foo2
        return x + this.Foo2;

        //Note that Foo *is* accessable here as 'SomeObject.Foo'
    }

}

Posso dizer honestamente que nunca usei uma classe marcada como estática, com exceção da criação de métodos de extensão ( Tutorial rápido sobre métodos de extensão ).

De qualquer forma, existem padrões de design específicos para a utilização de métodos estáticos, como padrão de fábrica e padrão singleton , mas o importante é lembrar que métodos e construtores estáticos não lidam com nenhuma instância específica de uma classe (a menos que você passe uma) normalmente para fazer cálculos ou fazer uma comparação entre objetos. O método "Principal" ao qual você está se referindo é sempre estático, mas para vê-lo de um ponto de vista diferente, consulte este artigo .

Para acompanhar, aqui está como é chamada a diferença entre métodos, campos e propriedades estáticos e instanciados.

public static void Main(string[] args)
{
    //This is a static method that starts a thread in an application
    // space.  At this point not everything actually has to be static...

    //Here is an instantiation with a parameterless contruction
    SomeObject obj = new SomeObject();

    //Here is an instantiation using a static factory method
    SomeObject obj2 = SomeObject.CreateSomeObject(3);

    //Getting field value from static field
    // Notice that this references the class name, not an instance
    int fooValue1 = SomeObject.Foo;

    //Getting property value from instance
    //  Note that this references an object instance
    int fooValue2 = obj2.Foo2;

    //Instance method must be called through an object
    obj2.AddSomething(4);  //if default constructor, would return 8

    //Static methods must be called through class name
    SomeObject.Add(4); //Returns 7
}

Além disso, confira este post para uma análise mais profunda das classes estáticas.


18

Aqui está a maneira de Joshua Bloch explicar, que eu acho brilhante como quase tudo o que ele diz (sim, eu sou fã de Joshua Bloch :)). Isso é citado na memória.

Imagine que uma classe é o equivalente a uma planta para uma casa. Imagine então que uma casa é do tipo blueprint, como uma instância da classe é para a classe. Você pode ter uma classe (blueprint) e várias instâncias (casas) criadas a partir dela.

Agora, o senso comum determina que a maioria das funções / comportamentos que uma casa (instância) pode ter / realizar, mesmo que sejam declaradas na planta, não pode ser usada até que uma casa real (instância) seja feita desse azul -print (classe). Assim, seu projeto pode conter nele o lugar onde as luzes e as lâmpadas devem ir, mas você não tem como fazer isso funcionar no projeto, você precisa construir a casa para poder para ligar e desligar o interruptor e ligar e desligar determinadas lâmpadas.

No entanto, você pode ter algum comportamento aplicável diretamente ao blueprint e que você pode usar / acessar diretamente no blueprint sem precisar criar uma casa real com esse blueprint. Imagine que sua planta azul tenha um botão que, ao pressionar, exibirá a área da casa contida nessa planta (calculando todos os comprimentos das paredes e outras). Obviamente, você PODE construir uma casa primeiro e depois medir sua pegada, mas você pode fazer isso apenas com a planta azul, por isso seria mais útil ter esse comportamento implementado na planta. Esse botão incorporado de planta azul que calcula a área ocupada da casa é o equivalente a ter uma função estática em uma classe.


Ou você teria uma Blueprintclasse que implementa a funcionalidade do blueprint, incluindo a capacidade de calcular a pegada da casa expressa pelo blueprint. Essa instância do blueprint é então alimentada a uma Builder(que por sua vez provavelmente é uma instância), que, por sua vez, faz o necessário para construir e gerar um número potencialmente arbitrário de Buildinginstâncias com base em um blueprint.
a CVn

11

Olhar dessa maneira me ajuda a:

  • Todo tipo tem uma instância estática.
  • A instância estática é criada na primeira vez em que você acessa o tipo - por meio da instância estática ou criando outra instância.
  • Você pode criar quantas instâncias não estáticas quiser, mas há apenas uma instância estática.
  • Qualquer coisa dentro de uma classe declarada como estática pertence à instância estática e, portanto, não tem acesso a nenhuma outra instância que você criar. Mas as outras instâncias têm acesso à instância estática.
  • Se uma classe for declarada como estática, você não poderá criar outras instâncias, apenas a instância estática poderá existir.
  • Você pode declarar um construtor estático para a instância estática, assim como um construtor para uma instância normal (mas declarando-o estático).

Quanto a quando usar a palavra-chave estática:

  • Qualquer método que não precise acessar propriedades locais pode e provavelmente deve ser declarado estático.
  • As classes auxiliares que não possuem nenhum estado (o que deve ser raro de qualquer maneira) e que nunca serão ridicularizadas podem ser declaradas estáticas. Se eles deveriam é outra questão; use essa funcionalidade com moderação.
  • Propriedades e campos que devem ser acessados ​​por todas as instâncias de uma classe devem ser declarados estáticos. Mas use isso somente quando não houver outra opção.

+1, para um bom resumo, eu não sabia que todo tipo tem uma instância estática e acho estranho dizer a verdade.
NoChance

2
@EmmadKareem Esse é apenas um modelo mental que o pdr usa, porque "Looking at it this way helps"ele. Você acha estranho porque não é exatamente verdade, mas pode pensar assim se quiser. Você conhece o modelo Bohr? É um apresenta um conjunto de regras e idéias de como átomos e elétrons interagem entre si. O modelo funciona dependendo do que você faz, mas não é a realidade.
Phant0m

@ phant0m, obrigado pela explicação, fiquei com a impressão de que não era um modelo real e fiquei surpresa por causa disso.
NoChance

Na verdade, às vezes há razões pelas quais você pode não querer criar um método, staticmesmo que não use propriedades locais. Fazer coisas staticpode adicionar acoplamento aos clientes porque eles precisam abordar a classe diretamente. Por exemplo, isso pode dificultar o teste de unidade com simulação.
Allan

@ Allan: Sem dúvida, se você está chamando um método público em uma classe que não afeta o estado de uma instância dessa classe, deve ser estático, para deixar isso claro para o desenvolvedor do cliente. Se esse método faz tanto que precisa ser zombado, é um problema diferente que pode ser resolvido de várias maneiras diferentes.
PDR

3

Explicação mais simples --- Estática => Somente uma cópia existirá por ambiente.

Portanto, dentro de uma VM ou CLR, haverá apenas uma cópia de uma classe estática e, qualquer outra classe de referência terá que compartilhar seus métodos e dados com todas as outras classes de referência.

Para uma variável estática, haverá apenas uma instância dessa variável no ambiente de tempo de execução, não importa quantas cópias da classe proprietária sejam criadas quando fizerem referência a uma variável estática, todas elas farão referência ao mesmo pedaço de armazenamento.


1

Membros estáticos estão associados à classe, não a nenhuma instância dessa classe.

Como estamos falando de .Net, considere a classe String , em particular os métodos Split e Join .

Split é um método de instância . Crie uma variável String, forneça um valor e você pode chamar Split () nessa variável / valor e recuperar uma matriz de "bits":

String s1 = "abc,def,ghi" ; 
String[] array2 = s1.Split( ',' ) ; 

Portanto, por exemplo, métodos, o valor mantido dentro da instância de classe especificada é importante .

Join é um método estático . OK, ele produz uma String resultado quando recebe um delimitador e uma matriz de String para mastigar, por isso é "algo a ver com" a classe String, mas é não associado a qualquer determinado valor em qualquer instância String (de fato, valores de instância são não disponível para métodos estáticos).
Em outros idiomas, o método Join pode ter sido "preso" à classe Array (ou, talvez melhor, uma classe StringArray), mas Our Friends in Redmond decidiu que era mais "relevante" para a classe String, então eles a colocaram lá .

String[] array3 = { ... } 
s1 = String.Join( array3, "," ) ; 

Outra alternativa poderia ter sido um método Join de instância , em que o valor mantido dentro da String [instância de classe] nos era usado como delimitador de junção, algo como:

// Maybe one day ... 
String s4 = "," ; 
s1 = s4.Join( array3 ) ; 

1

A staticpalavra-chave pode ser um pouco difícil de entender para iniciantes. Seu objetivo principal é identificar um membro da classe como não pertencente a nenhuma instância única da classe, mas à própria classe.

Sem entrar em muitos detalhes, o C # (e Java) impõe rigidamente o ideal orientado a objetos de que todo o código e dados devem pertencer a um objeto e, portanto, é limitado em escopo, visibilidade e tempo de vida. Geralmente, é uma prática recomendada sempre que o princípio fundamental de um objeto que representa alguma coisa do mundo real se aplica. No entanto, nem sempre; às vezes, o que você precisa é de uma função ou variável que você possa acessar de qualquer lugar no código, sem exigir que você passe uma referência a um objeto que o contenha e com a garantia de que os dados que você está vendo ou alterando sejam exatamente o que todos else está lidando com, e não uma cópia dele pertencente a uma instância diferente de um objeto.

Esse comportamento estava disponível em C e C ++ na forma da função ou variável "global", que não estava encapsulada em um objeto. Portanto, como compromisso, C # e Java suportam "escopo estático", um ponto intermediário entre código verdadeiramente global sem objeto pai e membros de instância de escopo limitado.

Qualquer "membro do código" (função, propriedade, campo) declarado como staticentra no escopo a partir da primeira linha da main()função do programa e não o deixa até que a main()função seja encerrada. Em inglês simples, um membro estático existe e pode ser usado enquanto o programa estiver em execução. Além disso, os membros estáticos são invocados chamando-os como membros do próprio tipo, não membros de nenhuma instância desse tipo:

public class Foo
{
   public int MyInt {get;set;} //this is an "instance member"
   public static int MyStaticInt {get;set;} //this is a "static member"
}

...

var myFoo = new Foo();
myFoo.MyInt = 5; //valid
myFoo.MyStaticInt = 5; //invalid; MyStaticInt doesn't belong to any one Foo

Foo.MyInt = 5; //invalid; MyInt only has meaning in the context of an instance
Foo.MyStaticInt = 2; //valid

Isso torna os membros estáticos visíveis para qualquer código que tenha conhecimento do tipo, sabendo ou não sobre uma única instância dele.

Para responder sua pergunta, o principal benefício de marcar algo como estático é que ele se torna visível onde quer que o próprio tipo seja conhecido, independentemente de o código consumidor ter ou poder obter uma instância do objeto que o contém. Há também um pequeno benefício de desempenho; como o método está no escopo estático, ele pode acessar apenas outros membros estáticos (da mesma classe ou de outros) e o que for passado como parâmetro. Portanto, o tempo de execução não precisa resolver nenhuma referência à instância atual do objeto que contém, como normalmente seria necessário para um método de instância para fornecer informações de estado específicas do contexto.

Classes inteiras também podem ser marcadas como estáticas; ao fazer isso, você informa ao compilador que a declaração de classe consistirá apenas em membros estáticos e, portanto, não poderá ser instanciada. Essa é uma maneira fácil de garantir que exista uma e apenas uma cópia de um objeto na memória; torne a classe e tudo nela estático. No entanto, é muito raro que esta seja a melhor solução para essa necessidade. Em uma situação em que exatamente uma cópia de um conjunto de dados é necessária, o "singleton" é normalmente recomendado; essa é uma classe não estática, que usa um acessador estático e um construtor não público para fornecer acesso a uma única instância. Teoricamente, um singleton oferece os mesmos benefícios de uma classe totalmente estática, mas com a capacidade adicional de usar a classe de uma maneira orientada a objeto e baseada em instância.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.