A questão está em Java, por que não consigo definir um método estático abstrato? por exemplo
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
A questão está em Java, por que não consigo definir um método estático abstrato? por exemplo
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Respostas:
Como "abstrato" significa: "Não implementa funcionalidade" e "estático" significa: "Existe funcionalidade mesmo que você não tenha uma instância de objeto". E isso é uma contradição lógica.
abstract static
faria todo o sentido. Seria um método do próprio objeto de classe que os objetos da subclasse devem implementar. Obviamente, a maneira como as coisas estão de acordo com a sua resposta está correta, apesar de eu ter me preocupado com o idioma.
abstract static
: Uma função X que é "implementada na subclasse" não pode ao mesmo tempo ser "executada na classe" - apenas na subclasse . Onde então não é mais abstrato.
static
não significa "não vazio" - isso é apenas uma consequência do Java não permitir que métodos estáticos sejam abstratos. Significa "callable na classe". (Deveria significar "que pode ser chamado apenas na classe", mas isso é outro problema.) Se o Java suportasse abstract static
métodos, eu esperaria que isso significasse que o método 1) deve ser implementado pelas subclasses e 2) é um método de classe da subclasse. Alguns métodos simplesmente não fazem sentido como métodos de instância. Infelizmente, o Java não permite que você especifique isso ao criar uma classe base abstrata (ou uma interface).
Design de linguagem ruim. Seria muito mais eficaz chamar diretamente um método abstrato estático do que criar uma instância apenas para usar esse método abstrato. Especialmente verdadeiro ao usar uma classe abstrata como uma solução alternativa para a incapacidade de extensão, que é outro exemplo ruim de design. Espero que eles resolvam essas limitações em um próximo lançamento.
static
si já é uma violação ....
Você não pode substituir um método estático, tornando-o abstrato não faria sentido. Além disso, um método estático em uma classe abstrata pertenceria a essa classe, e não a classe de substituição, portanto não poderia ser usado de qualquer maneira.
A abstract
anotação para um método indica que o método DEVE ser substituído em uma subclasse.
Em Java, um static
membro (método ou campo) não pode ser substituído por subclasses (isso não é necessariamente verdadeiro em outras linguagens orientadas a objetos, consulte SmallTalk.) Um static
membro pode estar oculto , mas isso é fundamentalmente diferente de substituído .
Como os membros estáticos não podem ser substituídos em uma subclasse, a abstract
anotação não pode ser aplicada a eles.
Como um aparte - outras linguagens suportam herança estática, assim como herança de instância. De uma perspectiva de sintaxe, esses idiomas geralmente exigem que o nome da classe seja incluído na declaração. Por exemplo, em Java, supondo que você esteja escrevendo código na ClassA, estas são instruções equivalentes (se methodA () for um método estático e não houver um método de instância com a mesma assinatura):
ClassA.methodA();
e
methodA();
No SmallTalk, o nome da classe não é opcional; portanto, a sintaxe é (observe que o SmallTalk não usa o.
ClassA methodA.
Como o nome da classe sempre é obrigatório, a "versão" correta do método sempre pode ser determinada percorrendo a hierarquia da classe. Pelo que vale, às vezes sinto falta da static
herança e fui mordido pela falta de herança estática no Java quando comecei com ela. Além disso, o SmallTalk é do tipo pato (e, portanto, não oferece suporte a programa por contrato.) Portanto, ele não possui abstract
modificadores para os membros da classe.
Eu também fiz a mesma pergunta, aqui está o porquê
Como a classe Abstract diz, ela não dará implementação e permitirá que a subclasse dê
então a subclasse precisa substituir os métodos da superclasse,
REGRA Nº 1 - Um método estático não pode ser substituído
Como membros e métodos estáticos são elementos de tempo de compilação, é por isso que Sobrecarga (Polimorfismo em tempo de compilação) de métodos estáticos é permitida, em vez de Substituir (Polimorfismo em tempo de execução)
Então, eles não podem ser abstratos.
Não existe algo como estática abstrata <--- Não é permitido no Universo Java
abstract static
consulte stackoverflow.com/questions/370962/… . A verdadeira razão pela qual o Java não permite que os métodos estáticos sejam substituídos é porque o Java não permite que os métodos estáticos sejam substituídos.
foo(String)
não é o mesmo que foo(Integer)
- isso é tudo.
Este é um design de linguagem terrível e realmente não há razão para que isso não seja possível.
De fato, aqui está uma implementação de como PODE ser feito em 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;
}
}
}
================= Exemplo antigo abaixo =================
Procure getRequest e getRequestImpl ... setInstance pode ser chamado para alterar a implementação antes que a chamada seja feita.
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();
}
}
}
Usado como segue:
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, conforme solicitado na pergunta, e escreveu em negrito PODE SER FEITO EM JAVA . Isso é completamente errado.
Um método abstrato é definido apenas para que possa ser substituído em uma subclasse. No entanto, métodos estáticos não podem ser substituídos. Portanto, é um erro em tempo de compilação ter um método estático abstrato.
Agora, a próxima pergunta é por que métodos estáticos não podem ser substituídos?
É porque os métodos estáticos pertencem a uma classe específica e não a sua instância. Se você tentar substituir um método estático, não receberá nenhum erro de compilação ou tempo de execução, mas o compilador apenas ocultará o método estático da superclasse.
Um método estático, por definição, não precisa saber this
. Portanto, não pode ser um método virtual (sobrecarregado de acordo com as informações da subclasse dinâmica disponíveis por meio dethis
); em vez disso, uma sobrecarga de método estático é baseada exclusivamente nas informações disponíveis no tempo de compilação (isto significa: depois de consultar um método estático de superclasse, você chama o método de superclasse, mas nunca um método de subclasse).
De acordo com isso, métodos estáticos abstratos seriam bastante inúteis porque você nunca terá sua referência substituída por algum corpo definido.
Vejo que já existem um zilhão de respostas, mas não vejo soluções práticas. É claro que esse é um problema real e não há boas razões para excluir essa sintaxe em Java. Como a pergunta original não possui um contexto em que isso possa ser necessário, forneço um contexto e uma solução:
Suponha que você tenha um método estático em várias classes idênticas. Esses métodos chamam um método estático específico da classe:
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 C1
e C2
são idênticos. Pode haver muitas dessas calsses: C3
C4
etc. Se static abstract
fosse permitido, você eliminaria o código duplicado fazendo 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
}
}
mas isso não seria compilado porque a static abstract
combinação não é permitida. No entanto, isso pode ser contornado com a static class
construção, que é 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();
}
}
Com esta solução, o único código duplicado é
public static void doWork() {
c.doWork();
}
C1.doWork()
ou C2.doWork()
Mas você não pode ligar C.doWork()
. Também no exemplo que você forneceu, que não funcionará, suponha que se fosse permitido, então como a classe C
encontrará a implementação dedoMoreWork()
? Finalmente, eu chamaria seu código de contexto de um design ruim. Por quê? simplesmente porque você criou uma função separada para o código exclusivo, em vez de criar uma função comum para o código e implementar uma função estática na classe C
. Isso é mais fácil !!!
Suponha que há duas classes Parent
e Child
. Parent
é abstract
. As declarações são as seguintes:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Isso significa que qualquer instância de Parent
deve especificar como run()
é executada.
No entanto, assuma agora que Parent
não é abstract
.
class Parent {
static void run() {}
}
Isso significa que Parent.run()
irá executar o método estático.
A definição de um abstract
método é "Um método declarado, mas não implementado", o que significa que ele não retorna nada.
A definição de um static
método é "Um método que retorna o mesmo valor para os mesmos parâmetros, independentemente da instância na qual é chamado".
O abstract
valor de retorno de um método será alterado conforme a instância. Um static
método não. Um static abstract
método é basicamente um método em que o valor de retorno é constante, mas não retorna nada. Isso é uma contradição lógica.
Além disso, não há realmente um motivo para um static abstract
método.
Uma classe abstrata não pode ter um método estático porque a abstração é feita para obter DYNAMIC BINDING enquanto os métodos estáticos estão estaticamente ligados à sua funcionalidade.Um método estático significa comportamento não dependente de uma variável de instância, portanto, nenhuma instância / objeto é necessário. Os métodos estáticos pertencem à classe e não ao objeto. Eles são armazenados em uma área de memória conhecida como PERMGEN, de onde é compartilhada com todos os objetos. Métodos na classe abstrata são ligados dinamicamente à sua funcionalidade.
Declarar um método como static
meio, podemos chamá-lo por seu nome de classe e, se essa classe abstract
também for, não faz sentido chamá-lo, pois ele não contém nenhum corpo e, portanto, não podemos declarar um método como static
e abstract
.
Como os métodos abstratos pertencem à classe e não podem ser substituídos pela classe de implementação. Mesmo se houver um método estático com a mesma assinatura, ele oculta o método, não o substitui. Portanto, é irrelevante declarar o método abstrato tão estático quanto nunca obterá o corpo. Assim, compile o erro de tempo.
Um método estático pode ser chamado sem uma instância da classe. No seu exemplo, você pode chamar foo.bar2 (), mas não foo.bar (), porque para bar você precisa de uma instância. O código a seguir funcionaria:
foo var = new ImplementsFoo();
var.bar();
Se você chamar um método estático, ele será executado sempre com o mesmo código. No exemplo acima, mesmo se você redefinir bar2 no ImplementsFoo, uma chamada para var.bar2 () executaria foo.bar2 ().
Se bar2 agora não tem implementação (é isso que significa abstrato), você pode chamar um método sem implementação. Isso é muito prejudicial.
Acredito que encontrei a resposta para essa pergunta, na forma de por que os métodos de uma interface (que funcionam como métodos abstratos em uma classe pai) não podem ser estáticos. Aqui está a resposta completa (não a minha)
Métodos basicamente estáticos podem ser vinculados em tempo de compilação, pois para chamá-los, você precisa especificar uma classe. Isso é diferente dos métodos de instância, para os quais a classe da referência da qual você está chamando o método pode ser desconhecida no momento da compilação (portanto, qual bloco de código é chamado pode ser determinado apenas em tempo de execução).
Se você está chamando um método estático, já conhece a classe em que é implementado ou qualquer subclasse direta dele. Se você definir
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
Qualquer Foo.bar();
ligação é obviamente ilegal e você sempre usará Foo2.bar();
.
Com isso em mente, o único objetivo de um método abstrato estático seria impor subclasses para implementar esse método. Você pode inicialmente achar que isso é MUITO errado, mas se você tiver um parâmetro de tipo genérico <E extends MySuperClass>
, seria bom garantir via interface E
possível .doSomething()
. Lembre-se de que, devido ao tipo de apagamento, os genéricos existem apenas no momento da compilação.
Então, seria útil? Sim, e talvez seja por isso que o Java 8 esteja permitindo métodos estáticos nas interfaces (embora apenas com uma implementação padrão). Por que não abstrair métodos estáticos com uma implementação padrão nas classes? Simplesmente porque um método abstrato com uma implementação padrão é realmente um método concreto.
Por que não abstrair / métodos estáticos de interface sem implementação padrão? Aparentemente, apenas por causa da maneira como o Java identifica qual bloco de código ele deve executar (primeira parte da minha resposta).
Como classe abstrata é um conceito OOPS e membros estáticos não fazem parte do OOPS ....
Agora, podemos declarar métodos estáticos completos na interface e podemos executar a interface declarando o método principal dentro de uma interface
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
A idéia de ter um método estático abstrato seria que você não pode usar essa classe abstrata específica diretamente para esse método, mas somente a primeira derivada poderá implementar esse método estático (ou para genéricos: a classe real do genérico você usar).
Dessa forma, você pode criar, por exemplo, uma classe abstrata sortableObject ou até mesmo fazer interface com métodos estáticos (auto-) abstratos, que definem os parâmetros das opções de classificação:
public interface SortableObject {
public [abstract] static String [] getSortableTypes();
public String getSortableValueByType(String type);
}
Agora você pode definir um objeto classificável que pode ser classificado pelos principais tipos que são iguais para todos esses 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
}
}
Agora você pode criar um
public class SortableList<T extends SortableObject>
que pode recuperar os tipos, criar um menu pop-up para selecionar um tipo para classificar e recorrer à lista, obtendo os dados desse tipo, bem como criar uma função de adição que, quando um tipo de classificação foi selecionado, pode ser ativada automaticamente -sorte novos itens. Observe que a instância de SortableList pode acessar diretamente o método estático de "T":
String [] MenuItems = T.getSortableTypes();
O problema de ter que usar uma instância é que o SortableList pode ainda não ter itens, mas já precisa fornecer a classificação preferida.
Cheerio, Olaf.
Primeiro, um ponto chave sobre as classes abstratas - Uma classe abstrata não pode ser instanciada (consulte o wiki ). Portanto, você não pode criar nenhuma instância de uma classe abstrata.
Agora, a maneira como o java lida com métodos estáticos é compartilhando o método com todas as instâncias dessa classe.
Portanto, se você não pode instanciar uma classe, essa classe não pode ter métodos estáticos abstratos, pois um método abstrato implora para ser estendido.
Estrondo.
Conforme o documento Java :
Um método estático é um método associado à classe em que está definido, e não a qualquer objeto. Cada instância da classe compartilha seus métodos estáticos
No Java 8, junto com os métodos padrão, os métodos estáticos também são permitidos em uma interface. Isso facilita a organização de métodos auxiliares em nossas bibliotecas. Podemos manter métodos estáticos específicos para uma interface na mesma interface, em vez de em uma classe separada.
Um bom exemplo disso é:
list.sort(ordering);
ao invés de
Collections.sort(list, ordering);
Outro exemplo de uso de métodos estáticos também é fornecido no próprio 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));
}
}
Como 'abstrato' significa que o método deve ser substituído e não se pode substituir os métodos 'estáticos'.
Os métodos regulares podem ser abstratos quando devem ser substituídos por subclasses e fornecidos com funcionalidade. Imagine que a classe Foo
é estendida porBar1, Bar2, Bar3
etc. Portanto, cada um terá sua própria versão da classe abstrata de acordo com suas necessidades.
Agora, os métodos estáticos por definição pertencem à classe, eles não têm nada a ver com os objetos da classe ou os objetos de suas subclasses. Eles nem precisam que eles existam, eles podem ser usados sem instanciar as classes. Portanto, eles precisam estar prontos para uso e não podem depender das subclasses para adicionar funcionalidade a eles.
Como abstract é uma palavra-chave aplicada sobre métodos Abstract, não especifica um corpo. E se falamos de palavra-chave estática, ela pertence à área de classe.
Você pode fazer isso com interfaces no Java 8.
Esta é a documentação oficial sobre o assunto:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Porque se uma classe estende uma classe abstrata, ela deve substituir os métodos abstratos, e isso é obrigatório. E como os métodos estáticos são métodos de classe resolvidos em tempo de compilação, enquanto os métodos substituídos são métodos de instância resolvidos em tempo de execução e após o polimorfismo dinâmico.