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?
}
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?
}
Respuestas:
Porque "abstracto" significa: "No implementa ninguna funcionalidad", y "estático" significa: "Hay funcionalidad incluso si no tiene una instancia de objeto". Y eso es una contradicción lógica.
abstract static
tendría mucho sentido. Sería un método del propio objeto de clase que los objetos de subclase deben implementar. Por supuesto, la forma en que las cosas resuelven su respuesta es correcta a pesar de mi comprensión del idioma.
abstract static
: Una función X que está "implementada en la subclase" no puede al mismo tiempo "ejecutarse en la clase", solo en la subclase . Donde entonces ya no es abstracto.
static
no significa "no vacío", eso es solo una consecuencia de que Java no permite que los métodos estáticos sean abstractos. Significa "invocable en la clase". (Debería significar "invocable solo en la clase", pero ese es otro problema). Si Java admite abstract static
métodos, esperaría que signifique que el método 1) debe ser implementado por subclases, y 2) es un método de clase de la subclase. Algunos métodos simplemente no tienen sentido como métodos de instancia. Desafortunadamente, Java no le permite especificar eso al crear una clase base abstracta (o una interfaz).
Mal diseño del lenguaje. Sería mucho más efectivo llamar directamente a un método abstracto estático que crear una instancia solo por usar ese método abstracto. Especialmente cierto cuando se utiliza una clase abstracta como solución alternativa para la incapacidad de enumeración, que es otro mal ejemplo de diseño. Espero que resuelvan esas limitaciones en un próximo lanzamiento.
static
sí mismo ya es una violación ...
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 abstract
anotación a un método indica que el método DEBE ser anulado en una subclase.
En Java, un static
miembro (método o campo) no puede ser anulado por subclases (esto no es necesariamente cierto en otros lenguajes orientados a objetos, vea SmallTalk). Un static
miembro puede estar oculto , pero eso es fundamentalmente diferente de anulado .
Dado que los miembros estáticos no se pueden reemplazar en una subclase, la abstract
anotación no se puede aplicar a ellos.
Por otro lado, otros lenguajes admiten herencia estática, al igual que la herencia de instancia. Desde una perspectiva de sintaxis, esos idiomas generalmente requieren que se incluya el nombre de la clase en la declaración. Por ejemplo, en Java, suponiendo que está escribiendo código en la Clase A, estas son declaraciones equivalentes (si el método A () es un método estático y no hay un 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 sintaxis es (tenga en cuenta que SmallTalk no usa. Para separar el "sujeto" y el "verbo", sino que lo usa como el terminador de enmienda de estado):
ClassA methodA.
Debido a que siempre se requiere el nombre de la clase, la "versión" correcta del método siempre se puede determinar atravesando la jerarquía de la clase. Por lo que vale, ocasionalmente extraño la static
herencia, y me mordió la falta de herencia estática en Java cuando comencé con ella. Además, SmallTalk es de tipo pato (y, por lo tanto, no es compatible con el programa por contrato). Por lo tanto, no tiene un abstract
modificador para los miembros de la clase.
También hice la misma pregunta, aquí es por qué
Como dice la clase Abstract, no dará implementación y permitirá que la subclase le dé
entonces la subclase tiene que anular los métodos de la superclase,
REGLA NO 1 - Un método estático no puede ser anulado
Debido a que los miembros y métodos estáticos son elementos de tiempo de compilación, es por eso que se permite la sobrecarga (polimorfismo en tiempo de compilación) de métodos estáticos en lugar de anulación (polimorfismo de tiempo de ejecución)
Por lo tanto, no pueden ser abstractos.
No hay nada como abstracto estático <--- No permitido en Java Universe
abstract static
ver stackoverflow.com/questions/370962/… . La verdadera razón por la que Java no permite que se anulen los métodos estáticos es porque Java no permite que se anulen los métodos estáticos.
foo(String)
que no es lo mismo que foo(Integer)
eso es todo.
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 PUEDE hacerse 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;
}
}
}
================= Viejo ejemplo a continuación =================
Busque getRequest y getRequestImpl ... se puede llamar a setInstance para alterar 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();
}
}
}
Utilizado de la siguiente manera:
static {
Core.setSingleton(new Core.CoreDefaultImpl());
// Or
Core.setSingleton(new Core.CoreTestImpl());
// Later in the application you might use
Core.getRequest();
}
abstract static
método como se le preguntó en la pregunta y ha escrito en negrita SE PUEDE HACER EN JAVA . Esto es completamente equivocado.
Un método abstracto se define solo para que pueda ser anulado en una subclase. Sin embargo, los métodos estáticos no se pueden anular. Por lo tanto, es un error en tiempo de compilación tener un método abstracto y estático.
Ahora la siguiente pregunta es ¿por qué los métodos estáticos no se pueden anular?
Es porque los métodos estáticos pertenecen a una clase particular y no a su instancia. Si intenta anular un método estático, no obtendrá ningún error de compilación o tiempo de ejecución, pero el compilador simplemente ocultará el método estático de la superclase.
Un método estático, por definición, no necesita saberlo this
. Por lo tanto, no puede ser un método virtual (que se sobrecarga de acuerdo con la información de subclase dinámica disponible a través de this
); en cambio, la sobrecarga de un método estático se basa únicamente en la información disponible en el momento de la compilación (esto significa: una vez que hace referencia a un método estático de superclase, llama al método de superclase, pero nunca a un método de subclase).
De acuerdo con esto, los métodos estáticos abstractos serían bastante inútiles porque nunca se sustituirá su referencia por algún 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 sintaxis en Java. Como la pregunta original carece de un contexto en el que esto pueda ser necesario, proporciono tanto un contexto como una solución:
Suponga 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 la 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()
Los métodos C1
y C2
son idénticos. Puede haber muchas de estas clases: C3
C4
etc. Si static abstract
se permitiera, 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 se compilaría porque la static abstract
combinación no está permitida. Sin embargo, esto se puede evitar con la static class
construcción, que está permitida:
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();
}
C1.doWork()
o C2.doWork()
Pero no puede llamar C.doWork()
. También en el ejemplo que ha proporcionado, que no funcionará, suponga que si estuviera permitido, ¿cómo C
encontrará la implementación la clase doMoreWork()
? Finalmente, llamaría a su código de contexto un mal diseño. ¿Por qué? simplemente porque ha creado una función separada para el código que es única en lugar de crear una función para el código que es común y luego implementar una función estática en la clase C
. ¡Esto es más fácil!
Suponga que hay dos clases, Parent
y 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 run()
se ejecuta.
Sin embargo, suponga que ahora Parent
no lo es abstract
.
class Parent {
static void run() {}
}
Esto significa que Parent.run()
ejecutará el método estático.
La definición de un abstract
método es "Un método que se declara pero no se implementa", lo que significa que no devuelve nada por sí mismo.
La definición de un static
método es "Un método que devuelve el mismo valor para los mismos parámetros, independientemente de la instancia en la que se llame".
El abstract
valor de retorno de un método cambiará a medida que cambie la instancia. Un static
método no lo hará. Un static abstract
método es más o menos un método donde 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 static abstract
método.
Una clase abstracta no puede tener un método estático porque la abstracción se realiza para lograr la 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 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.
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 lo 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
.
Como los métodos abstractos pertenecen a la clase y no pueden ser anulados por la clase implementadora. Incluso si hay un método estático con la misma firma, oculta el método, no lo anula. Por lo tanto, es irrelevante declarar el método abstracto como estático, ya que nunca obtendrá el cuerpo. Por lo tanto, error de tiempo de compilación.
Se puede llamar a 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ía 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 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 compilación, ya que para llamarlos debe especificar una clase. Esto es diferente a los métodos de instancia, para los cuales la clase de la referencia desde la que está llamando al método puede ser desconocida en el momento de la compilación (por lo tanto, qué bloque de código se llama solo se puede determinar en tiempo de ejecución).
Si está llamando a un método estático, ya conoce la clase donde se implementa, o cualquier subclase directa de la misma. Si usted define
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
Entonces, cualquier Foo.bar();
llamada es obviamente ilegal, y siempre la usará Foo2.bar();
.
Con esto en mente, el único propósito de un método abstracto estático sería imponer 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 <E extends MySuperClass>
, sería bueno garantizarlo a través de la interfaz que E
puede .doSomething()
. Tenga en cuenta que debido al tipo de borrado, los genéricos solo existen en el momento de la compilació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 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 los métodos estáticos abstractos / de interfaz sin implementación predeterminada? Aparentemente, simplemente por la forma en que Java identifica qué bloque de código tiene que ejecutar (primera parte de mi respuesta).
Debido a que la clase abstracta es un concepto OOPS y los miembros estáticos no son parte de OOPS ...
Ahora, podemos declarar métodos completos estáticos en la interfaz y podemos ejecutar la interfaz declarando el método principal dentro de una interfaz
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
La idea de tener un método estático abstracto sería que no puede usar esa clase abstracta en particular directamente para ese método, pero solo la primera derivada podría implementar ese método estático (o para genéricos: la clase real del genérico que utilizar).
De esa manera, podría crear, por ejemplo, una clase abstracta de objeto sortable o incluso una interfaz con métodos estáticos (auto) abstractos, que definen 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 ordenable que se pueda ordenar 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<T extends SortableObject>
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 tener una función de agregar que, cuando se ha seleccionado un tipo de clasificación, puede auto -ordenar nuevos elementos. Tenga en cuenta que la instancia de SortableList puede acceder directamente al método estático de "T":
String [] MenuItems = T.getSortableTypes();
El problema con tener que usar una instancia es que SortableList puede no tener elementos todavía, pero ya necesita proporcionar la clasificación preferida.
Cheerio, Olaf.
Primero, un punto clave sobre las clases abstractas: una clase abstracta no se puede instanciar (ver wiki ). Por lo tanto, no puede 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.
Entonces, si no puede crear una instancia de una clase, esa clase no puede tener métodos estáticos abstractos ya que un método abstracto pide que se extienda.
Auge.
Según el documento de Java :
Un método estático es un método asociado con la clase en la que se define 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 auxiliares 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 vez de
Collections.sort(list, ordering);
Otro ejemplo de uso de métodos estáticos también se da en el propio documento :
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 debe ser anulado y uno no puede anular los métodos 'estáticos'.
Los métodos regulares pueden ser abstractos cuando están destinados a ser anulados por subclases y provistos de funcionalidad. Imagina que la clase Foo
se extiende porBar1, 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 crear instancias de las clases. Por lo tanto, deben estar listos y no pueden depender de las subclases para agregarles funcionalidad.
Debido a que abstract es una palabra clave que se aplica sobre los métodos Abstract, no se especifica un cuerpo. Y si hablamos de palabras clave estáticas, pertenece al área de clase.
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
Porque si una clase extiende una clase abstracta, tiene que anular los métodos abstractos y eso es obligatorio. Y dado que los métodos estáticos son métodos de clase resueltos en tiempo de compilación, mientras que los métodos anulados son métodos de instancia resueltos en tiempo de ejecución y siguiendo un polimorfismo dinámico.