java - usar - ¿Tiene sentido tener un método no estático que no use una variable de instancia?
restricción de java al usar atributos y métodos estáticos. (7)
El compilador no permite que un método estático llame a un método no estático. Entiendo que lo hace porque un método no estático usualmente termina usando una variable de instancia.
Pero tiene sentido tener un método no estático que no use una variable de instancia. Si tenemos un comportamiento que no afecta o no se ve afectado por el estado de la instancia, dicho método no debe marcarse como estático.
Entiendo que lo hace porque un método no estático usualmente termina usando una variable de instancia.
Incluso si el método de instancia no usa una variable de instancia, aún está vinculada a la instancia de la clase. De hecho, tiene una referencia a this
implícitamente en los argumentos del método.
En otras palabras, en el siguiente método:
public void foo() {
}
this
se pasa implícitamente como la primera variable local en el método.
EDITAR:
Volver a leer la pregunta, es una pregunta más amplia que depende de la situación. En general, si el método no necesita la instancia (y está bastante seguro de que no lo hará), simplemente conviértala en static
.
¡Bien seguro! Supongamos que tienes en la interface IMyCollection
. Tiene un método boolean isMutable()
.
Ahora tiene dos clases, la class MyMutableList
y la class MyImmutableList
, que implementan IMyCollection
. Cada uno de ellos anularía el método de instancia isMutable()
, con MyMutableList
simplemente devolviendo true
y MyImmutableList
devolviendo false
.
isMutable()
en ambas clases es un método de instancia que (1) no utiliza variables de instancia, y (2) no afecta el estado de la instancia. Sin embargo, debido a restricciones en el lenguaje (es imposible anular los métodos estáticos), este diseño es el único práctico.
Además, me gustaría aclarar un concepto erróneo (como también lo hizo @manouti): los métodos no estáticos no son instancia porque usan variables de instancia o afectan el estado de la instancia; son métodos de instancia porque se definieron de esa manera (sin la palabra clave static
) y, por lo tanto, tienen un parámetro implícito (que, en idiomas como Python, ¡es realmente explícito!).
Creo que a veces es así, porque el método no estático puede anular para hacer diferentes tareas para diferentes clases, pero la tarea puede no involucrar variables de instancia, por ejemplo:
Fruit.java
public class Fruit{
public void printInfo(){
System.out.println("This is fruit");
}
}
Orange.java
public class Orange extends Fruit{
public void printInfo(){
System.out.println("This is orange");
}
}
Grape.java
public class Grape extends Fruit{
public void printInfo(){
System.out.println("This is grape");
}
}
imprime información del objeto:
Fruit f=new Grape();
f.printInfo();
Debido a que los métodos estáticos no pueden anularse, muchos desarrolladores que están preocupados por la capacidad de prueba de su código intentan evitar por completo los métodos estáticos en Java.
El código es más comprobable si las dependencias pueden reemplazarse con objetos simulados. Mockito y EasyMock son las herramientas más comunes para ayudar con esto, y confían en la herencia para crear subclases que le permiten anular fácilmente el método (a menudo complejo) que no desea probar ... para que su prueba se centre en lo que quieres probar
No voy al extremo de intentar con métodos estáticos cero, pero cuando concedo incluirlos, a menudo me arrepiento más tarde, por razones de prueba.
Todo esto es muy frustrante, porque no tiene nada que ver con lo que debería ser la consideración del diseño de los métodos estáticos vs instancia. Lo que me hace desear esos idiomas que te permiten tener funciones que no están conectadas con una clase ...
Muchas veces, no. Si el método no toca ningún estado de instancia, no hay razón para vincularlo a una instancia.
Por supuesto, los métodos estáticos no se pueden heredar ni anular, por lo que es un momento obvio que le gustaría tener un método de instancia que no utilice el estado de la instancia. El patrón de estrategia es un ejemplo clásico de esto.
Otro caso en el que puede vincularlo a una instancia de todos modos es si se trata de una API pública e imagina que es posible que desee vincular el método al estado de la instancia en el futuro. En ese caso, las preocupaciones de compatibilidad con versiones anteriores para las personas que usan su API pueden dificultar (o imposibilitar) convertir ese método estático en un método de instancia.
Si uno estuviera escribiendo una descripción legible por humanos del propósito del método, ¿haría mención de un objeto? Si es así, usa un método de instancia. Si no, usa un método estático. Tenga en cuenta que algunos métodos pueden describirse de cualquier manera, en cuyo caso uno debe usar el juicio sobre qué significado es mejor.
Considere, por ejemplo, "Obtener la dirección a la que debe enviarse un formulario de impuesto sobre la renta de Freedonian" frente a "Obtener la dirección a la que deben enviarse los formularios de impuestos sobre la renta de Freedonian". La primera pregunta debe ser respondida por un método de instancia; el segundo por un método estático. Es posible que Freedonia exija que todos los formularios de impuestos se envíen a la misma dirección (en cuyo caso el método anterior puede ignorar todos los campos de instancia), pero en el futuro puede tener oficinas diferentes para personas en diferentes regiones (en cuyo caso el método anterior podría mirar la identificación del contribuyente y seleccionar una dirección de correo basada en eso, mientras que el último método tendría que dirigir formularios a una oficina que podría aceptar formularios para cualquier persona y redirigirlos según sea necesario).
Un buen ejemplo es una codificación orientada a objetos de booleanos. La mayoría de los lenguajes, incluso los orientados a objetos como Java, optan por una codificación de booleanos orientada al tipo de datos abstractos, pero, por ejemplo, Smalltalk usa una codificación OO, y casi ninguno de los métodos utiliza ningún estado de instancia. Se parece un poco a esto:
import java.util.function.Supplier;
@FunctionalInterface interface Block { void call(); }
interface Bool {
Bool not();
Bool and(Bool other);
Bool or(Bool other);
<T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch);
void ifThenElse(Block thenBranch, Block elseBranch);
static final Bool T = new TrueClass();
static final Bool F = new FalseClass();
class TrueClass implements Bool {
public Bool not() { return F; }
public Bool and(Bool other) { return other; }
public Bool or(Bool other) { return this; }
public <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch) {
return thenBranch.get();
}
public void ifThenElse(Block thenBranch, Block elseBranch) {
thenBranch.call();
}
}
class FalseClass implements Bool {
public Bool not() { return T; }
public Bool and(Bool other) { return this; }
public Bool or(Bool other) { return other; }
public <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch) {
return elseBranch.get();
}
public void ifThenElse(Block thenBranch, Block elseBranch) {
elseBranch.call();
}
}
}
public class Main {
public static void main(String... args) {
Bool.F.ifThenElse(() -> System.out.println("True"), () -> System.out.println("False"));
// False
}
}
De hecho, si sigue un compromiso serio con OO, usa muchos métodos referencialmente transparentes y favorece el polimorfismo con respecto a los condicionales, con frecuencia terminará con métodos en muchas subclases, donde cada implementación en una de las clases devuelve un valor constante .