问题是在Java中为什么不能定义抽象的静态方法?例如
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
问题是在Java中为什么不能定义抽象的静态方法?例如
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Answers:
因为“抽象”的意思是:“不实现任何功能”,而“静态”的意思是:“即使没有对象实例也有功能”。这是一个逻辑上的矛盾。
abstract static
将是很有意义的。这是子类对象必须实现的类对象本身的方法。当然,尽管我对语言一无所知,但事情的立场是正确的。
abstract static
:“在子类中实现”的函数X 不能 同时在“类上”执行-只能在子类上执行。然后它不再是抽象的了。
static
并不意味着“不为空”-这只是Java不允许将静态方法抽象化的结果。它的意思是“可上课”。(这应该意味着“ 只能在该类上调用”,但这是另一个问题。)如果Java支持的abstract static
方法,我希望它的意思是方法1)必须由子类实现,而2)是子类的类方法。有些方法只是没有实例方法的意义。不幸的是,Java在创建抽象基类(或接口)时不允许您指定。
语言设计不良。直接调用静态抽象方法比仅使用该抽象方法创建实例要有效得多。当使用抽象类作为枚举无法扩展的解决方法时,尤其如此,这是另一个糟糕的设计示例。希望他们在下一个版本中解决这些限制。
static
本身已经是违反了....
您无法覆盖静态方法,因此将其抽象化将毫无意义。而且,抽象类中的静态方法将属于该类,而不是重写类,因此无论如何都不能使用。
的 abstract
方法注释指示该方法必须在子类中被覆盖。
在Java中,static
成员(方法或字段)不能被子类覆盖(在其他面向对象的语言中不一定是正确的,请参阅SmallTalk。)static
成员可能是隐藏的,但与被覆盖的本质不同。
由于静态成员无法在子类中覆盖,因此 abstract
注释应用于它们。
顺便说一句-其他语言也支持静态继承,就像实例继承一样。从语法角度来看,这些语言通常要求将类名包含在语句中。例如,在Java中,假设您正在用ClassA编写代码,则它们是等效的语句(如果methodA()是静态方法,并且没有具有相同签名的实例方法):
ClassA.methodA();
和
methodA();
在SmallTalk中,类名不是可选的,因此语法是(请注意,SmallTalk不会使用。来分隔“主题”和“动词”,而是将其用作statemend终止符):
ClassA methodA.
因为始终需要类名,所以可以始终通过遍历类层次结构来确定方法的正确“版本”。对于它的价值,我偶尔会错过static
继承,并且在我刚开始使用Java时就因为缺少静态继承而感到痛苦。另外,SmallTalk是鸭子类型的(因此不支持按合同编程)。因此,它没有abstract
用于类成员的修饰符。
我也问了同样的问题,这就是为什么
既然Abstract类说了,它就不会给出实现,而允许子类来给出它
所以Subclass必须重写Superclass的方法,
RULE NO 1 - 静态方法不能被重写
因为静态成员和方法是编译时元素,所以为什么允许静态方法的Overloading(编译时多态)而不是Overriding(运行时多态)
因此,它们不能是Abstract。
没有什么像抽象静态 <--- Java Universe中不允许的
abstract static
见stackoverflow.com/questions/370962/...。Java不允许覆盖静态方法的真正原因是因为Java不允许覆盖静态方法。
foo(String)
不一样,仅foo(Integer)
此而已。
这是一个糟糕的语言设计,实际上没有理由无法做到这一点。
事实上,这里是如何实现CAN在做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;
}
}
}
=================下面的旧示例=================
查找getRequest,然后在进行调用之前可以调用getRequestImpl ... setInstance来更改实现。
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();
}
}
}
用法如下:
static {
Core.setSingleton(new Core.CoreDefaultImpl());
// Or
Core.setSingleton(new Core.CoreTestImpl());
// Later in the application you might use
Core.getRequest();
}
abstract static
了问题中所提出的方法的示例,而您以粗体写的可以在JAVA中完成。这完全是误导。
仅定义一个抽象方法,以便可以在子类中重写它。但是,静态方法不能被覆盖。因此,拥有抽象的静态方法是编译时错误。
现在,下一个问题是为什么静态方法不能被覆盖?
这是因为静态方法属于特定的类,而不属于其实例。如果您尝试覆盖静态方法,则不会得到任何编译或运行时错误,但是编译器只会隐藏超类的静态方法。
根据定义,静态方法不需要知道this
。因此,它不能是虚拟方法(根据可通过以下方式获得的动态子类信息进行重载:this
);相反,静态方法重载仅基于编译时可用的信息(这意味着:一旦引用了超类的静态方法,就可以调用超类方法,而不能调用子类方法)。
据此,抽象的静态方法将毫无用处,因为您将永远不会用某些已定义的主体替换其引用。
我看到已经有数不胜数的答案,但是我没有任何实际的解决方案。当然,这是一个实际的问题,没有充分的理由在Java中排除此语法。由于原始问题缺少可能需要的上下文,因此我提供了上下文和解决方案:
假设您在一堆相同的类中有一个静态方法。这些方法调用特定于类的静态方法:
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()
C1
和C2
中的方法相同。可能有很多这样的计算:C3
C4
等等。如果static abstract
允许的话,您可以通过执行以下操作来消除重复的代码:
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
}
}
但这不会编译,因为static abstract
不允许组合。但是,可以通过static class
构造来避免这种情况,这是允许的:
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();
}
}
使用此解决方案,唯一重复的代码是
public static void doWork() {
c.doWork();
}
C1.doWork()
或,C2.doWork()
但不能打电话C.doWork()
。同样在您提供的示例中,如果它不起作用,则假设它不起作用,那么该类将如何C
找到实现doMoreWork()
?最后,我将您的上下文代码称为错误的设计。为什么?仅仅是因为您已经为唯一的代码创建了一个单独的函数,而不是为常见的代码创建了一个函数,然后在类中实现了静态函数C
。这比较容易!!!
假设有两个类,Parent
和Child
。Parent
是abstract
。声明如下:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
这意味着任何实例都Parent
必须指定如何run()
执行。
但是,现在假设Parent
不是abstract
。
class Parent {
static void run() {}
}
这意味着Parent.run()
将执行静态方法。
abstract
方法的定义是“已声明但未实现的方法”,这意味着它本身不会返回任何内容。
static
方法的定义是“一个方法,它为相同的参数返回相同的值,而不管调用它的实例是什么”。
一种abstract
方法的返回值将作为实例的变化而变化。一种static
方法不会。一个static abstract
方法是相当多地方的返回值是恒定的一种方法,但不返回任何东西。这是一个逻辑矛盾。
而且,确实没有太多理由采用这种static abstract
方法。
一个抽象类不能有一个静态方法,因为抽象化是为了实现动态绑定而进行的,而静态方法是静态地绑定到其功能上的。静态方法意味着行为不依赖于实例变量,因此不需要实例/对象。静态方法属于类而不是对象。它们存储在称为PERMGEN的存储区中,该存储区与每个对象共享。抽象类中的方法动态绑定到其功能。
可以在没有类实例的情况下调用静态方法。在您的示例中,您可以调用foo.bar2(),但不能调用foo.bar(),因为对于bar,您需要一个实例。以下代码将起作用:
foo var = new ImplementsFoo();
var.bar();
如果调用静态方法,它将始终执行相同的代码。在上面的示例中,即使您在ImplementsFoo中重新定义bar2,对var.bar2()的调用也将执行foo.bar2()。
如果bar2现在没有实现(这就是抽象的意思),则可以调用没有实现的方法。那是非常有害的。
我相信我已经找到了这个问题的答案,其形式是为什么接口的方法(像父类中的抽象方法一样)不能是静态的。这是完整答案(不是我的)
基本上,静态方法可以在编译时绑定,因为要调用它们,您需要指定一个类。这与实例方法不同,实例方法的实例名称在编译时可能是未知的(因此,只能在运行时确定要调用的代码块)。
如果要调用静态方法,则已经知道实现该方法的类或该类的任何直接子类。如果您定义
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
那么任何Foo.bar();
通话显然都是非法的,您将始终使用Foo2.bar();
。
考虑到这一点,静态抽象方法的唯一目的是强制子类实现这种方法。您最初可能会认为这是非常错误的,但是如果您有泛型类型参数,<E extends MySuperClass>
则可以通过E
can 接口保证.doSomething()
。请记住,由于类型擦除,泛型仅在编译时存在。
那么,这会有用吗?是的,也许这就是为什么Java 8在接口中允许使用静态方法的原因(尽管只有默认实现)。为什么不使用类中的默认实现抽象静态方法?仅仅因为具有默认实现的抽象方法实际上是一种具体方法。
为什么不使用没有默认实现的抽象/接口静态方法?显然,仅仅是因为Java标识了它必须执行哪个代码块的方式(我的回答的第一部分)。
因为抽象类是OOPS概念,并且静态成员不是OOPS的一部分...。
现在,我们可以在接口中声明静态完整方法,并且可以通过在接口内部声明main方法来执行接口。
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
拥有抽象静态方法的想法是,您不能将特定的抽象类直接用于该方法,但只能使用一阶导数来实现该静态方法(或泛型:您所使用的泛型的实际类采用)。
这样,您可以创建例如sortableObject抽象类,甚至创建具有(自动)抽象静态方法的接口,这些接口定义排序选项的参数:
public interface SortableObject {
public [abstract] static String [] getSortableTypes();
public String getSortableValueByType(String type);
}
现在,您可以定义一个可排序的对象,该对象可以按与所有这些对象相同的主要类型进行排序:
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
}
}
现在您可以创建一个
public class SortableList<T extends SortableObject>
可以检索类型,构建弹出菜单以选择要排序的类型,并通过从该类型获取数据来重新排序列表,还可以使用添加功能,当选择了排序类型时,该功能可以自动对新项目进行排序。请注意,SortableList实例可以直接访问静态方法“ T”:
String [] MenuItems = T.getSortableTypes();
必须使用实例的问题是SortableList可能还没有项目,但是已经需要提供首选的排序。
奥拉夫(Chefio),奥拉夫(Olaf)。
根据Java doc:
静态方法是与其定义的类相关联的方法,而不是与任何对象相关联的方法。该类的每个实例都共享其静态方法
在Java 8中,接口中还允许使用默认方法以及默认方法。这使我们更容易在库中组织帮助程序方法。我们可以将特定于接口的静态方法保留在同一接口中,而不是在单独的类中。
一个很好的例子是:
list.sort(ordering);
代替
Collections.sort(list, ordering);
在文档本身中也给出了使用静态方法的另一个示例:
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));
}
}
因为“抽象”意味着要重写该方法,而不能覆盖“静态”方法。
您可以使用Java 8中的接口来执行此操作。
这是关于它的官方文档:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
因为如果类扩展了抽象类,则它必须重写抽象方法,这是强制性的。而且由于静态方法是在编译时解析的类方法,而重写方法是在运行时并遵循动态多态性解析的实例方法。