¿Por qué los métodos estáticos no pueden ser abstractos en Java?

La pregunta es en Java ¿por qué no puedo definir un método estático abstracto? por ejemplo

abstract class foo { abstract void bar( ); // <-- this is ok abstract static void bar2(); //<-- this isn't why? } 

Porque “abstracto” significa: “No implementa ninguna funcionalidad”, y “estático” significa: “Hay funcionalidad incluso si no tiene una instancia de objeto”. Y esa es una contradicción lógica.

Diseño de lenguaje pobre. Sería mucho más efectivo llamar directamente a un método abstracto estático que crear una instancia solo para usar ese método abstracto. Especialmente cierto cuando se usa una clase abstracta como una solución alternativa para la incapacidad de extensión, que es otro ejemplo de diseño pobre. Espero que resuelvan esas limitaciones en un próximo lanzamiento.

No puede anular un método estático, por lo que hacerlo abstracto no tendría sentido. Además, un método estático en una clase abstracta pertenecería a esa clase, y no a la clase superior, por lo que no podría usarse de todos modos.

La anotación abstract de un método indica que el método DEBE ser anulado en una subclase.

En Java, un miembro static (método o campo) no puede ser anulado por subclases (esto no es necesariamente cierto en otros lenguajes orientados a objetos, consulte SmallTalk). Un miembro static puede estar oculto , pero eso es fundamentalmente diferente de anulado .

Como los miembros estáticos no pueden ser reemplazados en una subclase, la anotación abstract no puede aplicarse a ellos.

Como comentario aparte, otros lenguajes admiten herencia estática, al igual que la herencia de instancias. Desde una perspectiva de syntax, esos lenguajes generalmente requieren que el nombre de la clase se incluya en la statement. Por ejemplo, en Java, suponiendo que está escribiendo código en Clase A, estas son declaraciones equivalentes (si methodA () es un método estático, y no hay ningún método de instancia con la misma firma):

 ClassA.methodA(); 

y

 methodA(); 

En SmallTalk, el nombre de la clase no es opcional, por lo que la syntax es (tenga en cuenta que SmallTalk no usa el símbolo. Para separar el “sujeto” y el “verbo”, sino que lo usa como el terminador de enmendar):

 ClassA methodA. 

Debido a que siempre se requiere el nombre de la clase, la “versión” correcta del método siempre puede determinarse atravesando la jerarquía de clases. Por lo que vale, a veces echo de menos static herencia static y me picaba la falta de herencia estática en Java cuando comencé a usarla. Además, SmallTalk es de tipo pato (y por lo tanto no es compatible con el progtwig por contrato). Por lo tanto, no tiene un modificador abstract para los miembros de la clase.

También hice la misma pregunta, aquí está el porqué

Como dice la clase Abstract, no dará implementación y permitirá que la subclase la otorgue

entonces Subclass tiene que anular los métodos de Superclass,

REGLA NO 1Un método estático no puede ser anulado

Debido a que los miembros y métodos estáticos son elementos de tiempo de comstackción, es por eso que se permite la sobrecarga (polymorphism de tiempo de comstackción) de los métodos estáticos en lugar de anulación (polymorphism en tiempo de ejecución)

Entonces, ellos no pueden ser abstractos

No hay nada como abstracto estático < --- No permitido en Java Universe

Este es un diseño de lenguaje terrible y realmente no hay razón de por qué no puede ser posible.

De hecho, aquí hay una implementación sobre cómo se puede hacer en JAVA :

 public class Main { public static void main(String[] args) { // This is done once in your application, usually at startup Request.setRequest(new RequestImplementationOther()); Request.doSomething(); } public static final class RequestImplementationDefault extends Request { @Override void doSomethingImpl() { System.out.println("I am doing something AAAAAA"); } } public static final class RequestImplementaionOther extends Request { @Override void doSomethingImpl() { System.out.println("I am doing something BBBBBB"); } } // Static methods in here can be overriden public static abstract class Request { abstract void doSomethingImpl(); // Static method public static void doSomething() { getRequest().doSomethingImpl(); } private static Request request; private static Request getRequest() { // If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too. if ( request == null ) { return request = new RequestImplementationDefault(); } return request; } public static Request setRequest(Request r){ return request = r; } } } 

================= Ejemplo anterior a continuación =================

Busque getRequest y getRequestImpl … setInstance se puede llamar para modificar la implementación antes de realizar la llamada.

 import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; /** * @author Mo. Joseph * @date 16 mar 2012 **/ public abstract class Core { // --------------------------------------------------------------- private static Core singleton; private static Core getInstance() { if ( singleton == null ) setInstance( new Core.CoreDefaultImpl() ); // See bottom for CoreDefaultImpl return singleton; } public static void setInstance(Core core) { Core.singleton = core; } // --------------------------------------------------------------- // Static public method public static HttpServletRequest getRequest() { return getInstance().getRequestImpl(); } // A new implementation would override this one and call setInstance above with that implementation instance protected abstract HttpServletRequest getRequestImpl(); // ============================ CLASSES ================================= // ====================================================================== // == Two example implementations, to alter getRequest() call behaviour // == getInstance() have to be called in all static methods for this to work // == static method getRequest is altered through implementation of getRequestImpl // ====================================================================== /** Static inner class CoreDefaultImpl */ public static class CoreDefaultImpl extends Core { protected HttpServletRequest getRequestImpl() { return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); } } /** Static inner class CoreTestImpl : Alternative implementation */ public static class CoreTestImpl extends Core { protected HttpServletRequest getRequestImpl() { return new MockedRequest(); } } } 
  • Un método abstracto se define solo para que pueda ser anulado en una subclase. Sin embargo, los métodos estáticos no pueden ser anulados. Por lo tanto, es un error en tiempo de comstackción tener un método abstracto y estático.

    Ahora la siguiente pregunta es ¿por qué los métodos estáticos no pueden ser anulados?

  • Es porque los métodos estáticos pertenecen a una clase particular y no a su instancia. Si intentas anular un método estático, no obtendrás ningún error de comstackción o de tiempo de ejecución, pero el comstackdor simplemente ocultaría el método estático de la superclase.

Supongamos que hay dos clases, Parent e Child . Parent es abstract Las declaraciones son las siguientes:

 abstract class Parent { abstract void run(); } class Child extends Parent { void run() {} } 

Esto significa que cualquier instancia de Parent debe especificar cómo se run() .

Sin embargo, asum ahora que Parent no es abstract .

 class Parent { static void run() {} } 

Esto significa que Parent.run() ejecutará el método estático.

La definición de un método abstract es “Un método que se declara pero no se implementa”, lo que significa que no devuelve nada en sí mismo.

La definición de un método static es “Un método que devuelve el mismo valor para los mismos parámetros, independientemente de la instancia a la que se llama”.

El valor de retorno de un método abstract cambiará a medida que la instancia cambie. Un método static no lo hará. Un método static abstract es más o menos un método en el que el valor de retorno es constante, pero no devuelve nada. Esta es una contradicción lógica.

Además, realmente no hay muchas razones para un método static abstract .

Una clase abstracta no puede tener un método estático porque la abstracción se realiza para lograr VINCULACIÓN DINÁMICA mientras que los métodos estáticos están vinculados estáticamente a su funcionalidad. Un método estático significa un comportamiento que no depende de una variable de instancia, por lo que no se requiere instancia / objeto. Solo la clase. Los métodos estáticos pertenecen a la clase y no al objeto. Se almacenan en un área de memoria conocida como PERMGEN desde donde se comparte con cada objeto. Los métodos en la clase abstracta están vinculados dinámicamente a su funcionalidad.

Un método estático, por definición, no necesita saber this . Por lo tanto, no puede ser un método virtual (que está sobrecargado según la información de subclase dinámica disponible a través de this ); en cambio, una sobrecarga de método estático se basa únicamente en la información disponible en el momento de la comstackción (esto significa que una vez que refiere un método estático de superclase, llama el método de la superclase, pero nunca el método de una subclase).

De acuerdo con esto, los métodos estáticos abstractos serían bastante inútiles porque nunca se sustituirá su referencia por un cuerpo definido.

Veo que ya hay un millón de respuestas, pero no veo ninguna solución práctica. Por supuesto, este es un problema real y no hay una buena razón para excluir esta syntax en Java. Dado que la pregunta original carece de un contexto donde esto pueda ser necesario, proporciono tanto un contexto como una solución:

Supongamos que tiene un método estático en un grupo de clases que son idénticas. Estos métodos llaman a un método estático que es específico de clase:

 class C1 { static void doWork() { ... for (int k: list) doMoreWork(k); ... } private static void doMoreWork(int k) { // code specific to class C1 } } class C2 { static void doWork() { ... for (int k: list) doMoreWork(k); ... } private static void doMoreWork(int k) { // code specific to class C2 } } 

doWork() métodos doWork() en C1 y C2 son idénticos. Puede haber muchos de estos calses: C3 C4 etc. Si se permitiera el static abstract , eliminaría el código duplicado haciendo algo como:

 abstract class C { static void doWork() { ... for (int k: list) doMoreWork(k); ... } static abstract void doMoreWork(int k); } class C1 extends C { private static void doMoreWork(int k) { // code for class C1 } } class C2 extends C { private static void doMoreWork(int k) { // code for class C2 } } 

pero esto no comstackría porque no está permitida la combinación static abstract . Sin embargo, esto se puede eludir con static class construcción de static class , que está permitido:

 abstract class C { void doWork() { ... for (int k: list) doMoreWork(k); ... } abstract void doMoreWork(int k); } class C1 { private static final C c = new C(){ @Override void doMoreWork(int k) { System.out.println("code for C1"); } }; public static void doWork() { c.doWork(); } } class C2 { private static final C c = new C() { @Override void doMoreWork(int k) { System.out.println("code for C2"); } }; public static void doWork() { c.doWork(); } } 

Con esta solución, el único código que se duplica es

  public static void doWork() { c.doWork(); } 

Se puede invocar un método estático sin una instancia de la clase. En su ejemplo, puede llamar a foo.bar2 (), pero no a foo.bar (), porque para la barra necesita una instancia. El siguiente código funcionaría:

 foo var = new ImplementsFoo(); var.bar(); 

Si llama a un método estático, se ejecutará siempre el mismo código. En el ejemplo anterior, incluso si redefine bar2 en ImplementsFoo, una llamada a var.bar2 () ejecutará foo.bar2 ().

Si bar2 ahora no tiene implementación (eso es lo que significa abstracto), puede llamar a un método sin implementación. Eso es muy dañino.

Creo que he encontrado la respuesta a esta pregunta, en la forma de por qué los métodos de una interfaz (que funcionan como métodos abstractos en una clase principal) no pueden ser estáticos. Aquí está la respuesta completa (no la mía)

Básicamente, los métodos estáticos pueden vincularse en tiempo de comstackción, ya que para llamarlos debe especificar una clase. Esto es diferente de los métodos de instancia, para los cuales la clase de la referencia desde la que llama al método puede ser desconocida en tiempo de comstackción (por lo tanto, a qué bloque de código se llama solo se puede determinar en tiempo de ejecución).

Si llama a un método estático, ya conoce la clase en la que se implementa, o cualquier subclases directa de la misma. Si defines

 abstract class Foo { abstract static void bar(); } class Foo2 { @Override static void bar() {} } 

Entonces cualquier Foo.bar(); la llamada es obviamente ilegal, y siempre usará Foo2.bar(); .

Con esto en mente, el único propósito de un método abstracto estático sería hacer cumplir las subclases para implementar dicho método. Inicialmente, podría pensar que esto es MUY incorrecto, pero si tiene un parámetro de tipo genérico sería bueno garantizar a través de la interfaz que E pueda .doSomething() . Tenga en cuenta que debido a los tipos generics de borrado solo existen en tiempo de comstackción.

Entonces, ¿sería útil? Sí, y tal vez por eso Java 8 permite métodos estáticos en las interfaces (aunque solo con una implementación predeterminada). ¿Por qué no abstraer los métodos estáticos con una implementación predeterminada en las clases? Simplemente porque un método abstracto con una implementación predeterminada es en realidad un método concreto.

¿Por qué no abstraer / interactuar métodos estáticos sin implementación predeterminada? Aparentemente, simplemente por la forma en que Java identifica qué bloque de código debe ejecutar (la primera parte de mi respuesta).

La idea de tener un método estático abstracto sería que no se puede usar esa clase abstracta particular directamente para ese método, sino que solo la primera derivada podría implementar ese método estático (o para generics: la clase real del genérico utilizar).

De esta forma, podría crear, por ejemplo, una clase abstracta de clase sortableObject o incluso una interfaz con métodos estáticos (auto) abstractos, que define los parámetros de las opciones de clasificación:

 public interface SortableObject { public [abstract] static String [] getSortableTypes(); public String getSortableValueByType(String type); } 

Ahora puede definir un objeto clasificable que puede ordenarse por los tipos principales que son iguales para todos estos objetos:

 public class MyDataObject implements SortableObject { final static String [] SORT_TYPES = { "Name","Date of Birth" } static long newDataIndex = 0L ; String fullName ; String sortableDate ; long dataIndex = -1L ; public MyDataObject(String name, int year, int month, int day) { if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed."); if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date."); this.fullName = name ; this.sortableDate = MyUtils.createSortableDate(year,month,day); this.dataIndex = MyDataObject.newDataIndex++ ; } public String toString() { return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")"; } // override SortableObject public static String [] getSortableTypes() { return SORT_TYPES ; } public String getSortableValueByType(String type) { int index = MyUtils.getStringArrayIndex(SORT_TYPES, type); switch(index) { case 0: return this.name ; case 1: return this.sortableDate ; } return toString(); // in the order they were created when compared } } 

Ahora puedes crear un

 public class SortableList 

que puede recuperar los tipos, crear un menú emergente para seleccionar un tipo para ordenar y recurrir a la lista obteniendo los datos de ese tipo, así como también agregar una función que, cuando se ha seleccionado un tipo de ordenación, puede -sortar nuevos elementos en. Tenga en cuenta que la instancia de SortableList puede acceder directamente al método estático de “T”:

 String [] MenuItems = T.getSortableTypes(); 

El problema de tener que usar una instancia es que SortableList puede no tener elementos todavía, pero ya debe proporcionar la ordenación preferida.

Cheerio, Olaf.

Primero, un punto clave sobre las clases abstractas: una clase abstracta no puede ser instanciada (ver wiki ). Entonces, no puedes crear ninguna instancia de una clase abstracta.

Ahora, la forma en que Java trata los métodos estáticos es compartiendo el método con todas las instancias de esa clase.

Por lo tanto, si no puede instanciar una clase, esa clase no puede tener métodos abstractos estáticos ya que un método abstracto pide extenderse.

Auge.

Según el documento de Java:

Un método estático es un método que está asociado con la clase en la que está definido en lugar de con cualquier objeto. Cada instancia de la clase comparte sus métodos estáticos

En Java 8, junto con los métodos predeterminados, también se permiten métodos estáticos en una interfaz. Esto nos facilita la organización de métodos de ayuda en nuestras bibliotecas. Podemos mantener métodos estáticos específicos para una interfaz en la misma interfaz en lugar de en una clase separada.

Un buen ejemplo de esto es:

 list.sort(ordering); 

en lugar de

 Collections.sort(list, ordering); 

Otro ejemplo del uso de métodos estáticos también se da en el documento en sí:

 public interface TimeClient { // ... static public ZoneId getZoneId (String zoneString) { try { return ZoneId.of(zoneString); } catch (DateTimeException e) { System.err.println("Invalid time zone: " + zoneString + "; using default time zone instead."); return ZoneId.systemDefault(); } } default public ZonedDateTime getZonedDateTime(String zoneString) { return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); } } 

Porque ‘abstracto’ significa que el método está destinado a ser anulado y uno no puede anular los métodos ‘estáticos’.

Puede hacer esto con interfaces en Java 8.

Esta es la documentación oficial al respecto:

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

Los métodos regulares pueden ser abstractos cuando están destinados a ser reemplazados por subclases y provistos de funcionalidad. Imagine que la clase Foo se amplía con Bar1, Bar2, Bar3 etc. Por lo tanto, cada uno tendrá su propia versión de la clase abstracta de acuerdo con sus necesidades.

Ahora, los métodos estáticos por definición pertenecen a la clase, no tienen nada que ver con los objetos de la clase o los objetos de sus subclases. Ni siquiera necesitan que existan, se pueden usar sin instanciar las clases. Por lo tanto, deben estar listos para usar y no pueden depender de las subclases para agregarles funcionalidad.

Debido a que el resumen es una palabra clave que se aplica sobre los métodos abstractos, no se especifica un cuerpo. Y si hablamos de palabra clave estática pertenece al área de clase.

porque si está utilizando cualquier miembro estático o variable estática en la clase, se cargará en el tiempo de carga de la clase.

Declarar un método como static significa que podemos llamar a ese método por su nombre de clase y si esa clase también es abstract , no tiene sentido llamarlo ya que no contiene ningún cuerpo, y por lo tanto no podemos declarar un método como static y abstract .

Porque si una clase extiende una clase abstracta, entonces tiene que anular los métodos abstractos y eso es obligatorio. And since static methods are class methods resolved at compile time whereas overridden methods are instance methods resolved at runtime and following dynamic polymorphism.