问题是,在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?
}
当前回答
使用抽象静态方法的想法是,您不能直接为该方法使用特定的抽象类,但只允许一阶导数实现该静态方法(或者对于泛型:您使用的泛型的实际类)。
通过这种方式,您可以创建sortableObject抽象类甚至接口 使用(auto-)抽象静态方法,定义排序选项的参数:
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>
它可以检索类型,构建一个弹出菜单来选择要排序的类型,并通过从该类型获取数据来返回列表,以及hainv一个add函数,当选择了排序类型时,可以自动对新项进行排序。 注意SortableList实例可以直接访问“T”的静态方法:
String [] MenuItems = T.getSortableTypes();
必须使用实例的问题是SortableList可能还没有项目,但已经需要提供首选排序。
再见 奥拉夫。
其他回答
这是一个糟糕的语言设计,真的没有理由不可能。
事实上,这里有一个模式或方法可以在**Java中模仿它,让你至少能够修改自己的实现:
public static abstract class Request {
// Static method
public static void doSomething() {
get().doSomethingImpl();
}
// Abstract method
abstract void doSomethingImpl();
/////////////////////////////////////////////
private static Request SINGLETON;
private static Request get() {
if ( SINGLETON == null ) {
// If set(request) is never called prior,
// it will use a default implementation.
return SINGLETON = new RequestImplementationDefault();
}
return SINGLETON;
}
public static Request set(Request instance){
return SINGLETON = instance;
}
/////////////////////////////////////////////
}
两种实现:
/////////////////////////////////////////////////////
public static final class RequestImplementationDefault extends Request {
@Override void doSomethingImpl() {
System.out.println("I am doing something AAA");
}
}
/////////////////////////////////////////////////////
public static final class RequestImplementaionTest extends Request {
@Override void doSomethingImpl() {
System.out.println("I am doing something BBB");
}
}
/////////////////////////////////////////////////////
可以这样使用:
Request.set(new RequestImplementationDefault());
// Or
Request.set(new RequestImplementationTest());
// Later in the application you might use
Request.doSomething();
这将允许您静态地调用方法,同时还能够更改例如Test环境的实现。
理论上,您也可以在ThreadLocal上执行此操作,并且能够为每个线程上下文设置实例,而不是像这里所示的完全全局,然后可以执行Request。withRequest(anotherRequestImpl,() ->{…})或类似的。
现实世界通常不需要ThreadLocal方法,通常能够全局地改变测试环境的实现就足够了。
请注意,这样做的唯一目的是能够保留静态方法所提供的直接、轻松和干净地调用方法的能力,同时能够切换实现,以牺牲稍微复杂的实现为代价。
它只是一种绕过通常不可修改的静态代码的模式。
在一行中,这种危险的组合(抽象+静态)违反了面向对象的原则,即多态性。
在继承情况下,JVM将在运行时根据实现决定实例的类型(运行时多态性),而不是根据引用变量的类型(编译时多态性)。
@Overriding:
静态方法不支持@ override(运行时多态性),而只支持方法隐藏(编译时多态性)。
@Hiding:
但是在抽象静态方法的情况下,父(抽象)类没有方法的实现。因此,子类型引用是唯一可用的,而且它不是多态性。
子引用是唯一可用的:
出于这个原因(抑制oop特性),Java语言认为抽象+静态是非法(危险)的方法组合。
因为抽象类是一个OOPS概念,静态成员不是OOPS....的一部分 现在我们可以在接口中声明静态完整方法,我们可以通过在接口中声明主方法来执行接口
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
因为abstract是应用于abstract方法上的关键字,所以abstract方法不指定主体。而静态关键字则属于类区域。
方法的抽象注释表明该方法必须在子类中重写。
在Java中,静态成员(方法或字段)不能被子类覆盖(在其他面向对象语言中不一定是这样,请参阅SmallTalk)。静态成员可能被隐藏,但这与被覆盖有本质区别。
由于静态成员不能在子类中被重写,因此抽象注释不能应用于它们。
顺便说一句,其他语言确实支持静态继承,就像实例继承一样。从语法的角度来看,这些语言通常要求在语句中包含类名。例如,在Java中,假设你在ClassA中编写代码,这是等价的语句(如果methodA()是一个静态方法,并且没有具有相同签名的实例方法):
ClassA.methodA();
and
methodA();
在SmallTalk中,类名不是可选的,所以语法是(注意,SmallTalk不使用。将“主语”和“动词”分开,而是将其用作语句结束符):
ClassA methodA.
因为总是需要类名,所以总是可以通过遍历类层次结构来确定方法的正确“版本”。无论如何,我偶尔会错过静态继承,当我第一次开始使用Java时,我就被Java中缺乏静态继承所困扰。此外,SmallTalk是duck类型的(因此不支持契约式编程)。因此,类成员没有抽象修饰符。