Por que métodos estáticos podem usar apenas dados estáticos?

38

Não entendo por que um método estático não pode usar dados não estáticos. Alguém pode explicar quais são os problemas e por que não podemos fazê-lo?

JAVA
fonte
11
Porque apenas dados estáticos existem do ponto de vista dos métodos estáticos.
Mouviciel 11/09/13
4
Compartilhar sua pesquisa ajuda a todos. Conte-nos o que você tentou e por que ele não atendeu às suas necessidades. Isso demonstra que você reservou um tempo para tentar ajudar a si mesmo, evita reiterar respostas óbvias e, acima de tudo, ajuda a obter uma resposta mais específica e relevante. Veja também How to Ask
gnat
19
@gnat neste caso, o OP está tentando entender o motivo por trás de uma decisão de design. O que você espera que ele tente neste caso?
113913 Geek
2
@ Geek - a existência de métodos estáticos, dados estáticos é uma questão de design de linguagem. Assumindo significados padrão, o fato de que métodos estáticos não podem acessar dados da instância não é. A limitação está implícita nas definições e no que é possível e faz sentido, e não por alguns fracassos de designers de linguagem.
Steve314
6
Parafraseando Gertrude Stein: "Não há isso lá".
Hippo-dancer

Respostas:

73

Na maioria das linguagens OO, quando você define um método dentro de uma classe, ele se torna um Método de Instância . Ao criar uma nova instância dessa classe, por meio da newpalavra - chave, você inicializa um novo conjunto de dados exclusivo para essa instância. Os métodos pertencentes a essa instância podem trabalhar com os dados que você definiu nela.

Os métodos estáticos , por outro lado, ignoram as instâncias de classe individuais. O método estático é semelhante a uma função livre em C ou C ++. Não está vinculado a uma instanciação específica da classe. É por isso que eles não podem acessar os valores da instância. Não há nenhum exemplo para obter um valor!

Dados estáticos é semelhante a um método estático. Um valor declarado staticnão possui instância associada. Existe para todas as instâncias e é declarado apenas em um único local na memória. Se alguma vez for alterado, será alterado para todas as instâncias dessa classe.

Um método estático pode acessar dados estáticos porque ambos existem independentemente de instâncias específicas de uma classe.

Pode ajudar a ver como você chama um método estático, comparado a um método de instância. Digamos que tivemos a seguinte classe (usando pseudocódigo semelhante ao Java):

class Foo {
    // This static value belongs to the class Foo
    public static final string name = "Foo";

    // This non-static value will be unique for every instance
    private int value;

    public Foo(int value) {
         this.value = value;
    }

    public void sayValue() {
        println("Instance Value: " + value);
    }

    public static void sayName() {
        println("Static Value: " + name);
    }
}

Foo foo1 = new Foo(10);
Foo foo2 = new Foo(20);

foo1.sayValue(); // Prints "Instance Value: 10" - called on foo1
foo2.sayValue(); // Prints "Instance Value: 20" - called on foo2

Foo.sayName(); // Prints "Static Value: Foo" - called on Foo (not foo1 or foo2)

Atualizar

Como COME FROM aponta nos comentários, um método estático é capaz de trabalhar com dados não estáticos, mas deve ser passado explicitamente. Vamos supor que a Fooclasse tenha outro método:

public static Foo Add(Foo foo1, Foo foo2) {
    return new Foo(foo1.value + foo2.value);
}

Addainda é estático e não possui valueinstâncias próprias, mas, sendo um membro da classe Foo, pode acessar os valuecampos particulares das entradas foo1e foo2instâncias. Nesse caso, estamos usando-o para retornar um novo Foo com os valores adicionados dos dois valores passados.

Foo foo3 = Foo.Add(foo1, foo2); // creates a new Foo with a value of 30
KChaloux
fonte
30
Expandindo em "Não há instância para a qual obter um valor" - mesmo se houver instâncias, o método estático não pode saber de qual instância obter um valor.
Steve314
9
Isso é muito menos complicado de explicar em linguagens que não forçam tudo a fazer parte de um objeto por padrão.
Mason Wheeler
3
@Mason Palavras verdadeiras. Linguagens como o Java meio que impõem uma noção falsa de que uma função é algo que necessariamente pertence a uma classe.
KChaloux
5
Essa é uma boa resposta, mas ainda não diz a verdade: métodos estáticos podem acessar dados não estáticos. Eles simplesmente não têm o objeto implícito ou this-referência disponível. Eu acho que isso é de vital importância para entender.
Vem
2
@COMEFROM Você quer dizer com passagem explícita? Posso fazer uma anotação, se estiver entendendo corretamente. Supus que estava implícito que um método estático poderia acessar dados não estáticos explicitamente transmitidos, uma vez que qualquer função pode funcionar com dados explicitamente transmitidos a ele.
KChaloux
22

Vamos explicar com uma amostra hipotética.

Imagine uma classe simples:

class User
{
User(string n) { name = n; };
string name;
}

Agora criamos 2 instâncias dessa classe:

User Bones = new User("Bones");
User Jim = new User("Jim");

Agora, pense - e se adicionarmos um novo método estático ao Usuário, por exemplo:

static string GetName();

e você chama:

string x = User::GetName()

o que x conteria? "Jim", "Bones", ou algo mais?

O problema é que um método estático é um método único, definido na classe, não nos objetos. Como resultado, você não sabe a qual objeto ele pode se aplicar. É por isso que é uma coisa especial. É melhor pensar em métodos estáticos como coisas individuais, como funções em C, por exemplo. O fato de linguagens como Java contê-las dentro de classes é principalmente um problema, pois o Java não permite que exista nada fora de uma classe; portanto, funções como essa devem ser forçadas dentro de uma classe de alguma maneira (um pouco como o main () é forçado a ser também dentro de uma classe quando todo o sentido diz que deve ser uma função singular e independente).

gbjbaanb
fonte
3

Pode usar dados de campo; considere o seguinte código java:

class MyBean {
    private String myString;

    static void myStaticMethod() {
        myString = "tada";/*not allowed; if this was possible how would 
                           be different from a field without static?*/

        MyBean myBean = new MyBean();//allowed if associated with an instance
        myBean.myString = "tada";
    }
}
m3th0dman
fonte
Embora tecnicamente esse seja um método estático usando dados não estáticos, ele não é o suficiente. Claro que você pode criar uma nova instância e acessá-la. Mas isso não tem nada a ver com staticness.
Bobson
2
Na verdade, acho que esse é um ótimo complemento para explicar o ponto. Ele destaca o ponto em que o método estático precisa de uma instância da classe antes de poder acessar dados não estáticos, fornecendo uma razão intuitiva para isso.
Ben Hocking
@ Bobson Você deve ler o código e os comentários também.
M3th0dman
@BenHocking "sim" mesmo eu acho que é bom revelador ponto que "variável de instância está sempre associada a objeto"
JAVA
2

Dados não estáticos estão associados a uma instância da classe. Métodos estáticos (e dados) não estão associados a uma instância específica da classe. Não é necessário que haja uma instância de uma classe para usar métodos estáticos nela. Mesmo que houvesse instância (s), não haveria como o Java garantir que você esteja operando na instância que espera ao chamar um método estático. Portanto, métodos estáticos não podem ter acesso a dados não estáticos.

smp7d
fonte
2

Eu acho que a questão aqui é de entendimento.

Do ponto de vista técnico, um método estático chamado de dentro de um objeto seria capaz de ver os campos da instância. Eu suspeito fortemente que foi isso que causou a pergunta em primeiro lugar.

O problema é que os métodos podem ser chamados de fora do objeto. Nesse ponto, não há dados da instância para fornecê-los - e, portanto, não há como o compilador resolver o código. Como permitir dados da instância causou uma contradição, não devemos permitir dados da instância.

Loren Pechtel
fonte
Discordo. Um método estático não pode acessar os dados da instância porque os dados da instância devem ser acessados ​​por meio de uma instância do objeto e o método estático não está associado a nenhuma instância (mas à definição da classe).
Phill W.
Você sente falta do meu ponto. Se for chamado de dentro da classe, o compilador pode passar um ponteiro de instância como acontece quando não é uma classe estática. O problema surge se ele é chamado de outros lugares - (. Ainda que por internamente basicamente ignorando a estática) o que significa que métodos estáticos privados poderiam acessar dados de instância
Loren Pechtel
Sim, o compilador / poderia / mas por que deveria? Passar esse ponteiro essencialmente o reduz a um método de instância. Sua estipulação de que apenas métodos privados podem fazer isso é discutível - as tecnologias de reflexão tornam / todos / os métodos acessíveis - privados ou não - tornando essa proposta ainda mais arriscada. Nossos amigos em Redmond foram na outra direção; os idiomas deles emitem um aviso se você tentar chamar um método estático contra uma instância do objeto (e não a própria classe).
Phill W.
1

Pense nisso como métodos estáticos que vivem em uma dimensão não orientada a objetos.

Na "dimensão orientada a objetos", uma classe pode gerar múltiplos egos (instâncias), cada ego tem consciência de si mesmo através de seu estado.

No plano, sem dimensão OO, uma classe não percebe seus egos vivendo na dimensão OO. O mundo deles é plano e processual, quase como se o OOP ainda não tivesse sido inventado, e como se a classe fosse um pequeno programa processual, e os dados estáticos fossem apenas variáveis ​​globais.

Tulains Córdova
fonte
1

Acho que a maneira mais fácil de explicar isso é olhar para algum código e depois considerar quais resultados esperaríamos que o código produzisse.

// Create three new cars.  Cars have a name attribute.  
Car car1 = new Car("Mazda3");
Car car2 = new Car("FordFocus");
Car car3 = new Car("HondaFit");

// Now we would like to print the names of some cars: 
// First off why don't we try this: 

Car.printCarName();

// Expected behaviour: 
// If we think about what we are trying to do here it doesn't
// really make sense.  What instance of car name should this 
// print?  Should it print Mazda3?  FordFoucs?
// What is the expected behaviour?  If we are going to have a
// static call on car call printCarName it should probably do
// something like print all car names or a random car name or
// throw an error.  


//Now lets try this instead: 

Car.printCarName(car1);

// Expected Behaviour: 
// Luckily the expected behaviour is very clear here.  This
// should print Mazda3.  This works as expected.  


// Finally lets try this: 

car1.printMyName();

// Expected Behaviour:
// Same as previous example, however this is the *right* way
// to do it.  

Para completar, aqui está a classe do carro:

public class Car{

    public String name;

    public Car(String name){
        this.name = name;
    }

    public static printCarName(){
        print "Not sure what to do here...  Don't know which car you are talking about.";
    }

    public static printCarName(Car c){
        print c.name;
    }

    public /*NOT static*/ printMyName(){
        print this.name;
    }

}
sixtyfootersdude
fonte
Como isso responde à pergunta?
gnat 11/09
1
@gnat Atualizado com comentários para esclarecer.
sixtyfootersdude
1

As outras respostas praticamente dizem tudo, no entanto, há alguns "detalhes" que gostaria de acrescentar.

Os métodos estáticos (digamos aqueles em Java) simplesmente não têm um objeto implícito associado a eles (acessível por this) cujos membros você pode acessar geralmente diretamente pelo nome.

Isso não significa que eles não podem acessar dados não estáticos.

class MyClass {
  public static void foo(MyOtherClass object) {
    System.out.println(object.member);
  }
}
class MyOtherClass { public int member = 10; }

Sei que isso é apenas um detalhe, mas achei sua pergunta estranha quando a li. "Pode usar apenas dados estáticos" é muito restritivo.

A propósito, eu não testei o código, apenas o escrevi aqui para exemplificar o que estava dizendo.

Pedro Henrique A. Oliveira
fonte