¿Por qué los métodos estáticos solo pueden usar datos estáticos?

38

No entiendo por qué un método estático no puede usar datos no estáticos. ¿Alguien puede explicar cuáles son los problemas y por qué no podemos hacerlo?

JAVA
fuente
11
Porque solo existen datos estáticos desde el punto de vista de los métodos estáticos.
mouviciel
44
Compartir su investigación ayuda a todos. Cuéntanos qué has probado y por qué no satisfizo tus necesidades. Esto demuestra que te has tomado el tiempo para tratar de ayudarte a ti mismo, nos evita reiterar respuestas obvias y, sobre todo, te ayuda a obtener una respuesta más específica y relevante. También vea Cómo preguntar
mosquito
19
@gnat en este caso OP está tratando de entender la razón detrás de una decisión de diseño. ¿Qué esperas que intente en este caso?
Geek
2
@ Geek: la existencia de métodos estáticos, los datos estáticos es un problema de diseño de lenguaje. Suponiendo significados estándar, el hecho de que los métodos estáticos no puedan acceder a los datos de la instancia no lo es. La limitación está implícita en las definiciones y lo que es posible y tiene sentido, no en las debilidades de algunos diseñadores de idiomas.
Steve314
66
Parafraseando a Gertrude Stein: "No hay esto allí".
Bailarina de hipopótamos

Respuestas:

73

En la mayoría de los lenguajes OO, cuando define un método dentro de una clase, se convierte en un Método de instancia . Cuando crea una nueva instancia de esa clase, a través de la newpalabra clave, inicializa un nuevo conjunto de datos exclusivo de esa instancia. Los métodos que pertenecen a esa instancia pueden funcionar con los datos que definió en ella.

Los métodos estáticos , por el contrario, ignoran las instancias de clases individuales. El método estático es similar a una función libre en C o C ++. No está vinculado a una instanciación específica de la clase. Es por eso que no pueden acceder a los valores de instancia. ¡No hay una instancia para tomar un valor!

Los datos estáticos son similares a un método estático. Un valor que se declara staticno tiene una instancia asociada. Existe para cada instancia, y solo se declara en un solo lugar en la memoria. Si alguna vez se cambia, cambiará para cada instancia de esa clase.

Un método estático puede acceder a datos estáticos porque ambos existen independientemente de instancias específicas de una clase.

Puede ser útil observar cómo invocar un método estático, en comparación con un método de instancia. Digamos que teníamos la siguiente clase (usando pseudocódigo similar a 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)

Actualizar

Como COME FROM señala en los comentarios, un método estático es capaz de trabajar con datos no estáticos, pero debe pasarse explícitamente. Asumamos que la Fooclase tenía otro método:

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

Addsigue siendo estático y no tiene valueinstancias propias, pero al ser miembro de la clase Foo puede acceder a los valuecampos privados de las instancias foo1y de las transferencias foo2. En este caso, lo estamos utilizando para devolver un nuevo Foo con los valores agregados de ambos valores pasados.

Foo foo3 = Foo.Add(foo1, foo2); // creates a new Foo with a value of 30
KChaloux
fuente
30
Expandiendo "No hay una instancia de la que tomar un valor", incluso si hay instancias, el método estático no puede saber de qué instancia tomar un valor.
Steve314
9
Esto es mucho menos complicado de explicar en lenguajes que no obligan a todo a ser parte de un objeto por defecto.
Mason Wheeler
3
@Mason Palabras verdaderas. Los lenguajes como Java imponen una noción falsa de que una función es algo que necesariamente pertenece a una clase.
KChaloux
55
Esta es una buena respuesta, pero aún no dice toda la verdad: los métodos estáticos pueden acceder a datos no estáticos. Simplemente no tienen el objeto implícito o la thisreferencia disponible. Creo que es de vital importancia entenderlo.
VENIDO del
2
@COMEFROM ¿Quiere decir con paso explícito? Puedo tomar nota de ello, si te entiendo correctamente. Supuse que estaba implícito que un método estático podría acceder a datos no estáticos pasados ​​explícitamente, dado que cualquier función puede funcionar en los datos que se le pasan explícitamente.
KChaloux
22

Vamos a explicarlo con una muestra hipotética.

Imagina una clase simple:

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

Ahora creamos 2 instancias de esta clase:

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

ahora, piense: ¿y si agregamos un nuevo método estático al Usuario, por ejemplo:

static string GetName();

y lo llamas:

string x = User::GetName()

¿Qué contendría x? "Jim", "Bones", o algo más?

El problema es que un método estático es un método único, definido en la clase, no en los objetos. Como resultado, no sabe a qué objeto podría aplicarse. Por eso es algo especial. Es mejor pensar en los métodos estáticos como cosas individuales, como funciones en C, por ejemplo. Que los lenguajes como Java los contengan dentro de las clases es principalmente un problema con Java que no permite que exista nada fuera de una clase, por lo que funciones como esta deben forzarse dentro de una clase de alguna manera (un poco como cómo se obliga a main () dentro de una clase también cuando todo sentido dice que debería ser una función singular e independiente).

gbjbaanb
fuente
3

Puede usar datos de campo; considere el siguiente código de 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
fuente
Si bien esto puede ser técnicamente un método estático que utiliza datos no estáticos, no tiene sentido. Por supuesto, puede crear una nueva instancia y acceder a ella. Pero eso no tiene nada que ver con staticness.
Bobson
2
En realidad, creo que esta es una muy buena adición para explicar el punto. Resalta el punto de que el método estático necesita una instancia de la clase antes de que pueda acceder a datos no estáticos al tiempo que proporciona una razón intuitiva por la que es así.
Ben Hocking
@Bobson Deberías leer el código y los comentarios también.
m3th0dman
@BenHocking "sí", incluso creo que es bueno decir que "la variable de instancia siempre está asociada con el objeto"
JAVA
2

Los datos no estáticos están asociados a una instancia de la clase. Los métodos estáticos (y los datos) no están asociados a una instancia particular de la clase. No es necesario que haya una instancia de una clase para usar métodos estáticos en ella. Incluso si hubiera instancias, Java no garantizaría que está operando en la instancia que espera cuando llama a un método estático. Por lo tanto, los métodos estáticos no pueden tener acceso a datos no estáticos.

smp7d
fuente
2

Creo que el problema aquí es de comprensión.

Desde un punto de vista técnico, un método estático llamado desde un objeto sería bastante capaz de ver los campos de instancia. Sospecho firmemente que esto es lo que causó la pregunta en primer lugar.

El problema es que los métodos pueden llamarse desde fuera del objeto. En ese momento no hay datos de instancia para proporcionarlos, y por lo tanto no hay forma de que el compilador resuelva el código. Dado que permitir datos de instancia causó una contradicción, no debemos permitir datos de instancia.

Loren Pechtel
fuente
Estoy en desacuerdo. Un método estático no puede acceder a los datos de la instancia porque se debe acceder a los datos de la instancia a través de una instancia del objeto y el método estático no está asociado con ninguna instancia dada (sino con la definición de clase).
Phill W.
Echas de menos mi punto. Si se llama desde dentro de la clase, el compilador podría pasar un puntero de instancia como lo hace cuando no es una clase estática. El problema surge si se llama desde otro lugar, lo que significa que los métodos estáticos privados podrían acceder a los datos de la instancia (aunque básicamente ignorando internamente la estática)
Loren Pechtel
Sí, el compilador / podría / pero ¿por qué debería hacerlo? Pasar dicho puntero esencialmente lo reduce a un método de instancia. Su estipulación de que solo los métodos privados pueden hacer esto es discutible: las tecnologías de reflexión hacen que / all / method sea accesible, privado o no, lo que hace que esta sea una propuesta aún más arriesgada. Nuestros amigos en Redmond han ido en la otra dirección; sus idiomas generan una advertencia si intenta llamar a un método estático contra una instancia de objeto (y no la clase en sí).
Phill W.
1

Piense en ello como métodos estáticos que viven en una dimensión no orientada a objetos.

En la "dimensión orientada a objetos", una clase puede generar múltiples egos (instancias), cada ego tiene conciencia de sí mismo a través de su estado.

En la dimensión plana, no OO, una clase es ajena a sus egos que viven en la dimensión OO. Su mundo es plano y procesal, casi como si la POO aún no se hubiera inventado, y como si la clase fuera un pequeño programa procesal y los datos estáticos fueran solo variables globales.

Tulains Córdova
fuente
1

Creo que la forma más fácil de explicar esto es mirar algún código y luego considerar qué resultados esperaríamos que produzca el código.

// 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, aquí está la clase de automóvil:

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
fuente
¿Cómo responde esto a la pregunta que se hace?
mosquito
1
@gnat Actualizado con comentarios para aclarar.
sixtyfootersdude
1

Las otras respuestas lo dicen todo, sin embargo, hay algunos "detalles" que me gustaría agregar.

Los métodos estáticos (digamos aquellos en Java) simplemente no tienen un objeto implícito asociado a ellos (accesible a través this) a cuyos miembros se puede acceder generalmente directamente por nombre.

Eso no significa que no puedan acceder a datos no estáticos.

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

Sé que esto es solo un detalle, pero encontré tu pregunta extraña cuando la leí. "Solo se pueden usar datos estáticos" es demasiado restrictivo.

Por cierto, no probé el código, simplemente lo escribí aquí para ejemplificar lo que estaba diciendo.

Pedro Henrique A. Oliveira
fuente