문제는 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?
}
답변:
"추상"은 "기능 구현 없음"을 의미하고 "정적"은 "객체 인스턴스가 없어도 기능이 있음"을 의미하기 때문입니다. 그리고 그것은 논리적 모순입니다.
abstract static
이라면 완벽한 의미가 될 것입니다. 서브 클래스 객체가 구현 해야하는 클래스 객체 자체의 메소드 일 것입니다. 물론, 언어에 대한 나의 이해에도 불구하고 당신의 대답이 서있는 방식은 정확합니다.
abstract static
: "서브 클래스에서 구현 된"함수 X 는 동시에 "클래스에서 실행될 수 없습니다 "– 서브 클래스 에서만 . 그때 더 이상 추상적이지 않은 곳.
static
"비어 있지 않다"는 의미는 아닙니다. 이는 정적 메소드를 추상화 할 수없는 Java의 결과입니다. "수업 가능"을 의미합니다. (이것은 " 클래스 에서만 호출 가능"을 의미해야 하지만 또 다른 문제입니다.) Java가 abstract static
메소드를 지원 하는 경우 메소드 1)이 서브 클래스에 의해 구현되어야하고 2)가 서브 클래스의 클래스 메소드임을 의미합니다. 일부 메소드는 인스턴스 메소드로 의미가 없습니다. 불행히도 Java는 추상 기본 클래스 또는 인터페이스를 만들 때 지정할 수 없습니다.
언어 디자인이 잘못되었습니다. 해당 추상 메소드를 사용하기 위해 인스턴스를 작성하는 것보다 정적 추상 메소드를 직접 호출하는 것이 훨씬 더 효과적입니다. 열거를 확장 할 수없는 해결 방법으로 추상 클래스를 사용할 때 특히 그렇습니다. 이는 또 다른 열악한 디자인 예입니다. 다음 릴리스에서 이러한 한계를 해결하기를 바랍니다.
static
그 자체 의 단순한 개념 은 이미 위반 이라고 말하는 사람들이 있습니다 ....
정적 메서드를 재정의 할 수 없으므로 추상적으로 만드는 것은 의미가 없습니다. 또한 추상 클래스의 정적 메서드는 재정의 클래스가 아닌 해당 클래스에 속하므로 어쨌든 사용할 수 없었습니다.
abstract
메소드에 대한 주석은 메소드가 서브 클래스에서 대체되어야 함을 나타냅니다.
자바에서는 static
멤버 (메소드 나 필드) A (이것은 다른 객체 지향 언어로, 스몰 토크를 참조하십시오. 반드시 사실이 아니다) 서브 클래스에 의해 오버라이드 (override) 할 수없는 static
구성원이 될 수 있습니다 숨겨져 있지만,보다 근본적으로 다르다 오버라이드 (override) .
정적 멤버는 서브 클래스에서 재정의 abstract
할 수 없으므로 주석을 적용 할 수 없습니다.
다른 언어는 인스턴스 상속과 마찬가지로 정적 상속도 지원합니다. 구문 관점에서 이러한 언어는 일반적으로 명령문에 클래스 이름을 포함해야합니다. 예를 들어, Java에서 ClassA로 코드를 작성한다고 가정하면 다음과 같은 명령문입니다 (methodA ()가 정적 메소드이고 동일한 서명을 가진 인스턴스 메소드가없는 경우).
ClassA.methodA();
과
methodA();
SmallTalk에서 클래스 이름은 선택 사항이 아니므로 구문은 다음과 같습니다 (SmallTalk는.를 사용하여 "제목"과 "동사"를 구분하지 않고 대신이를 상태 수정 종료 자로 사용합니다).
ClassA methodA.
클래스 이름은 항상 필요하므로 클래스 계층 구조를 통과하여 메소드의 올바른 "버전"을 항상 결정할 수 있습니다. 그 가치가 있기 때문에 때로는 static
상속이 누락 되고 처음 시작할 때 Java에서 정적 상속이 부족하여 물 렸습니다. 또한 SmallTalk는 오리 형식이므로 계약별로 지원하지 않습니다. 따라서 abstract
클래스 멤버를위한 수정자가 없습니다 .
나는 또한 같은 질문을했다, 여기에 이유가있다.
Abstract 클래스가 말 했으므로 구현을 제공하지 않고 서브 클래스가 제공 할 수 있습니다
서브 클래스는 Superclass의 메소드를 재정의해야합니다.
규칙 NO 1 - 정적 메서드는 재정의 할 수 없습니다
정적 멤버와 메서드는 컴파일 타임 요소이므로 정적 메서드의 오버로드 (컴파일 타임 다형성)가 재정의 (런타임 다형성)보다 허용되는 이유
그래서 그들은 추상적 일 수 없습니다.
추상 정적 <--- 와 같은 것은 없습니다 . Java Universe에서는 허용되지 않습니다.
abstract static
참조 하면 확실히 가능합니다 . 진짜 이유 자바는 정적 메소드가 오버라이드 (override) 할 수 없기 때문에 자바는 정적 메소드 오버라이드 (override) 할 수 허용하지 않는 이유입니다.
foo(String)
과 같지 않습니다 foo(Integer)
– 그것이 전부입니다.
이것은 끔찍한 언어 디자인이며 실제로 불가능한 이유는 없습니다.
실제로 다음은 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
동일하다. 이 calsses이 많이있을 수 있습니다 : 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
construct 로 우회 할 수 있으며 다음과 같이 허용됩니다.
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
캔 .doSomething()
. 유형 삭제 제네릭으로 인해 컴파일시에만 존재한다는 점을 명심하십시오.
그렇다면 유용할까요? 예, 아마도 Java 8이 인터페이스에서 정적 메소드를 허용하는 이유입니다 (기본 구현에서만 가능). 클래스에서 기본 구현으로 정적 메소드를 추상화하지 않는 이유는 무엇입니까? 기본 구현을 가진 추상 메소드가 실제로 구체적인 메소드이기 때문입니다.
기본 구현이없는 추상 / 인터페이스 정적 메소드가 아닌 이유는 무엇입니까? 분명히, Java가 실행해야 할 코드 블록을 식별하는 방식 때문입니다 (제 답변의 첫 부분).
abstract 클래스는 OOPS 개념이고 정적 멤버는 OOPS의 일부가 아닙니다 ...
이제 인터페이스에서 정적 완료 메소드를 선언 할 수 있으며 인터페이스 내에서 메인 메소드를 선언하여 인터페이스를 실행할 수 있습니다.
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>
유형을 검색하고, 팝업 유형을 선택하여 정렬 할 유형을 선택하고 해당 유형에서 데이터를 가져 와서 목록을 수정하고, 정렬 유형을 선택할 때 자동으로 할 수있는 추가 기능을 hainv 할 수 있습니다. 새 항목을 정렬합니다. SortableList의 인스턴스는 "T"의 정적 메소드에 직접 액세스 할 수 있습니다.
String [] MenuItems = T.getSortableTypes();
인스턴스를 사용해야 할 때의 문제점은 SortableList에 아직 항목이 없지만 선호하는 정렬을 제공해야한다는 것입니다.
Cheerio, Olaf.
먼저, 추상 클래스에 대한 요점-추상 클래스는 인스턴스화 할 수 없습니다 ( wiki 참조 ). 그래서, 당신은 만들 수 없습니다 어떤 추상 클래스의 인스턴스를.
이제 java가 정적 메소드를 처리하는 방법은 해당 클래스의 모든 인스턴스 와 메소드를 공유하는 것입니다 .
따라서 클래스를 인스턴스화 할 수 없으면 추상 메소드가 확장되기를 구걸하기 때문에 해당 클래스에 추상 정적 메소드를 가질 수 없습니다.
팔.
Java doc에 따라 :
정적 메소드는 객체가 아니라 정의 된 클래스와 연관된 메소드입니다. 클래스의 모든 인스턴스는 정적 메소드를 공유합니다
Java 8에서는 기본 메소드와 함께 인터페이스에서 정적 메소드도 허용됩니다. 이를 통해 라이브러리에서 헬퍼 메소드를 쉽게 구성 할 수 있습니다. 우리는 별도의 클래스가 아닌 동일한 인터페이스에서 인터페이스에 특정한 정적 메소드를 유지할 수 있습니다.
이에 대한 좋은 예는 다음과 같습니다.
list.sort(ordering);
대신에
Collections.sort(list, ordering);
정적 메소드를 사용하는 또 다른 예는 doc 자체 에도 있습니다.
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));
}
}
'abstract'는 메서드가 재정의되고 'static'메서드를 재정의 할 수 없음을 의미하기 때문입니다.
Java 8의 인터페이스를 사용하여이 작업을 수행 할 수 있습니다.
다음은 공식 문서입니다.
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html