Câu hỏi là trong Java tại sao tôi không thể định nghĩa một phương thức tĩnh trừu tượng? ví dụ
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Câu hỏi là trong Java tại sao tôi không thể định nghĩa một phương thức tĩnh trừu tượng? ví dụ
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Câu trả lời:
Bởi vì "trừu tượng" có nghĩa là: "Thực hiện không có chức năng" và "tĩnh" có nghĩa là: "Có chức năng ngay cả khi bạn không có một đối tượng đối tượng". Và đó là một mâu thuẫn logic.
abstract static
sẽ có ý nghĩa hoàn hảo. Nó sẽ là một phương thức của chính đối tượng lớp mà các đối tượng lớp con phải thực hiện. Tất nhiên, cách mọi thứ diễn ra câu trả lời của bạn là chính xác mặc dù tôi không hiểu gì về ngôn ngữ.
abstract static
: Hàm X được "triển khai trong lớp con" không thể đồng thời được "thực thi trên lớp" - chỉ trên lớp con . Nơi đó không còn trừu tượng nữa.
static
không có nghĩa là "không trống rỗng" - đó chỉ là hậu quả của việc Java không cho phép các phương thức tĩnh trở nên trừu tượng. Nó có nghĩa là "có thể gọi được trên lớp." (Nó có nghĩa là " chỉ có thể gọi được trên lớp" nhưng đó là một vấn đề khác.) Nếu các abstract static
phương thức được Java hỗ trợ, tôi mong muốn nó có nghĩa là phương thức 1) phải được các lớp con triển khai và 2) là một phương thức lớp của lớp con. Một số phương thức không có ý nghĩa như các phương thức ví dụ. Thật không may, Java không cho phép bạn xác định rằng khi tạo một lớp cơ sở trừu tượng (hoặc một giao diện).
Thiết kế ngôn ngữ kém. Sẽ hiệu quả hơn nhiều nếu gọi trực tiếp một phương thức trừu tượng tĩnh hơn là tạo một thể hiện chỉ để sử dụng phương thức trừu tượng đó. Đặc biệt đúng khi sử dụng một lớp trừu tượng như một cách giải quyết cho enum không có khả năng mở rộng, đó là một ví dụ thiết kế kém. Hy vọng họ giải quyết những hạn chế trong một phiên bản tiếp theo.
static
nó đã là một sự vi phạm ....
Bạn không thể ghi đè một phương thức tĩnh, vì vậy làm cho nó trừu tượng sẽ là vô nghĩa. Hơn nữa, một phương thức tĩnh trong một lớp trừu tượng sẽ thuộc về lớp đó, và không phải là lớp ghi đè, vì vậy dù sao cũng không thể được sử dụng.
Các abstract
chú thích đến một phương pháp chỉ ra rằng phương pháp này PHẢI được overriden trong một lớp con.
Trong Java, một static
thành viên (phương thức hoặc trường) không thể bị ghi đè bởi các lớp con (điều này không nhất thiết đúng trong các ngôn ngữ hướng đối tượng khác, xem SmallTalk.) Một static
thành viên có thể bị ẩn , nhưng về cơ bản thì khác với ghi đè .
Vì các thành viên tĩnh không thể được ghi đè trong một lớp con, nên abstract
chú thích có thể được áp dụng cho chúng.
Như một bên - các ngôn ngữ khác hỗ trợ kế thừa tĩnh, giống như kế thừa thể hiện. Từ góc độ cú pháp, các ngôn ngữ đó thường yêu cầu tên lớp được bao gồm trong câu lệnh. Ví dụ, trong Java, giả sử bạn đang viết mã trong ClassA, đây là các câu lệnh tương đương (nếu phương thứcA () là một phương thức tĩnh và không có phương thức cá thể nào có cùng chữ ký):
ClassA.methodA();
và
methodA();
Trong SmallTalk, tên lớp không phải là tùy chọn, vì vậy cú pháp là (lưu ý rằng SmallTalk không sử dụng. Để tách "chủ ngữ" và "động từ", mà thay vào đó sử dụng nó làm dấu kết thúc stHRend):
ClassA methodA.
Vì tên lớp luôn được yêu cầu, "phiên bản" chính xác của phương thức luôn có thể được xác định bằng cách duyệt qua hệ thống phân cấp lớp. Đối với những gì nó có giá trị, đôi khi tôi bỏ lỡ static
sự kế thừa và bị cắn bởi sự thiếu kế thừa tĩnh trong Java khi tôi lần đầu tiên bắt đầu với nó. Ngoài ra, SmallTalk được gõ vịt (và do đó không hỗ trợ theo hợp đồng theo chương trình.) Vì vậy, nó không có công cụ abstract
sửa đổi cho các thành viên lớp.
Tôi cũng hỏi cùng một câu hỏi, đây là lý do tại sao
Vì lớp Trừu tượng nói, nó sẽ không thực hiện và cho phép lớp con cung cấp cho nó
Vì vậy, lớp con phải ghi đè lên các phương thức của Superclass,
Quy tắc số 1 - Một phương thức tĩnh không thể bị ghi đè
Bởi vì các thành viên và phương thức tĩnh là các phần tử thời gian biên dịch, đó là lý do tại sao Quá tải (Đa hình thời gian biên dịch) của các phương thức tĩnh được cho phép thay vì ghi đè (Đa hình thời gian chạy)
Vì vậy, họ không thể là Tóm tắt.
Không có thứ gì giống như tĩnh trừu tượng <--- Không được phép trong Vũ trụ Java
abstract static
xem stackoverflow.com/questions/370962/ . Các lý do thực sự tại sao Java không cho phép phương pháp tĩnh được ghi đè là do Java không cho phép phương pháp tĩnh được ghi đè.
foo(String)
không giống như foo(Integer)
- đó là tất cả.
Đây là một thiết kế ngôn ngữ khủng khiếp và thực sự không có lý do tại sao nó không thể thực hiện được.
Trên thực tế, đây là một triển khai về cách nó có thể được thực hiện trong 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;
}
}
}
================= Ví dụ cũ bên dưới =================
Tìm kiếm getRequest và getRequestImpl ... setInstance có thể được gọi để thay đổi việc thực hiện trước khi cuộc gọi được thực hiện.
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();
}
}
}
Được sử dụng như sau:
static {
Core.setSingleton(new Core.CoreDefaultImpl());
// Or
Core.setSingleton(new Core.CoreTestImpl());
// Later in the application you might use
Core.getRequest();
}
abstract static
phương pháp như đã hỏi trong câu hỏi và bạn đã viết bằng chữ đậm CÓ THỂ ĐƯỢC LÀM TRONG JAVA . Điều này là hoàn toàn sai lầm.
Một phương thức trừu tượng chỉ được định nghĩa để nó có thể được ghi đè trong một lớp con. Tuy nhiên, các phương thức tĩnh không thể bị ghi đè. Do đó, đó là một lỗi thời gian biên dịch để có một phương thức tĩnh, trừu tượng.
Bây giờ câu hỏi tiếp theo là tại sao các phương thức tĩnh không thể bị ghi đè ??
Đó là bởi vì các phương thức tĩnh thuộc về một lớp cụ thể chứ không thuộc về thể hiện của nó. Nếu bạn cố gắng ghi đè một phương thức tĩnh, bạn sẽ không gặp phải bất kỳ lỗi biên dịch hoặc thời gian chạy nào nhưng trình biên dịch sẽ chỉ ẩn phương thức tĩnh của siêu lớp.
Một phương pháp tĩnh, theo định nghĩa, không cần phải biết this
. Vì vậy, nó không thể là một phương thức ảo (bị quá tải theo thông tin lớp con động có sẵn thông qua this
); thay vào đó, quá tải phương thức tĩnh chỉ dựa trên thông tin có sẵn tại thời gian biên dịch (điều này có nghĩa là: một khi bạn tham khảo một phương thức tĩnh của siêu lớp, bạn gọi cụ thể là phương thức siêu lớp, nhưng không bao giờ là phương thức lớp con).
Theo đó, các phương thức tĩnh trừu tượng sẽ khá vô dụng vì bạn sẽ không bao giờ có tham chiếu của nó được thay thế bởi một số phần xác định.
Tôi thấy rằng đã có hàng trăm câu trả lời thần thánh nhưng tôi không thấy bất kỳ giải pháp thực tế nào. Tất nhiên đây là một vấn đề thực sự và không có lý do chính đáng để loại trừ cú pháp này trong Java. Vì câu hỏi ban đầu thiếu một bối cảnh mà điều này có thể cần, tôi cung cấp cả bối cảnh và giải pháp:
Giả sử bạn có một phương thức tĩnh trong một nhóm các lớp giống hệt nhau. Các phương thức này gọi một phương thức tĩnh là lớp cụ thể:
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()
phương pháp trong C1
và C2
giống hệt nhau. Có thể có rất nhiều các calsodes này: C3
C4
vv Nếu static abstract
được phép, bạn sẽ loại bỏ mã trùng lặp bằng cách thực hiện một số thứ như:
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
}
}
nhưng điều này sẽ không được biên dịch vì static abstract
sự kết hợp không được phép. Tuy nhiên, điều này có thể được phá vỡ bằng static class
cấu trúc, được phép:
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();
}
}
Với giải pháp này, mã duy nhất được sao chép là
public static void doWork() {
c.doWork();
}
C1.doWork()
hoặc C2.doWork()
Nhưng bạn không thể gọi C.doWork()
. Cũng trong ví dụ mà bạn đã cung cấp, sẽ không hoạt động, giả sử nếu nó được cho phép, thì lớp sẽ C
tìm cách thực hiện như doMoreWork()
thế nào? Cuối cùng tôi sẽ gọi mã bối cảnh của bạn là một thiết kế xấu. Tại sao? đơn giản vì bạn đã tạo một hàm riêng cho mã duy nhất thay vì tạo một hàm cho mã phổ biến và sau đó thực hiện một hàm tĩnh trong lớp C
. Điều này dễ dàng hơn !!!
Giả sử có hai lớp, Parent
và Child
. Parent
là abstract
. Các khai báo như sau:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Điều này có nghĩa là bất kỳ trường hợp nào Parent
phải chỉ định cách run()
thực hiện.
Tuy nhiên, giả sử bây giờ Parent
là không abstract
.
class Parent {
static void run() {}
}
Điều này có nghĩa là Parent.run()
sẽ thực thi phương thức tĩnh.
Định nghĩa của một abstract
phương thức là "Một phương thức được khai báo nhưng không được thực hiện", có nghĩa là nó không trả về bất cứ thứ gì.
Định nghĩa của một static
phương thức là "Một phương thức trả về cùng một giá trị cho cùng các tham số bất kể trường hợp mà nó được gọi là".
abstract
Giá trị trả về của một phương thức sẽ thay đổi khi thể hiện thay đổi. Một static
phương pháp sẽ không. Một static abstract
phương thức gần như là một phương thức trong đó giá trị trả về là hằng số, nhưng không trả về bất cứ thứ gì. Đây là một mâu thuẫn logic.
Ngoài ra, thực sự không có nhiều lý do cho một static abstract
phương pháp.
Một lớp trừu tượng không thể có một phương thức tĩnh bởi vì sự trừu tượng được thực hiện để đạt được BINDING NĂNG ĐỘNG trong khi các phương thức tĩnh được liên kết tĩnh với chức năng của chúng. Phương thức tĩnh có nghĩa là hành vi không phụ thuộc vào một biến đối tượng, do đó không yêu cầu đối tượng / đối tượng. Các phương thức tĩnh thuộc về lớp và không phải đối tượng. Chúng được lưu trữ trong một vùng nhớ được gọi là PERMGEN từ nơi nó được chia sẻ với mọi đối tượng. Các phương thức trong lớp trừu tượng được liên kết động với chức năng của chúng.
Khai báo một phương thức như static
là phương tiện chúng ta có thể gọi phương thức đó bằng tên lớp của nó và nếu lớp đó abstract
cũng vậy, sẽ không có ý nghĩa gì khi gọi nó vì nó không chứa bất kỳ phần thân nào, và do đó chúng ta không thể khai báo một phương thức cả static
và abstract
.
Vì các phương thức trừu tượng thuộc về lớp và không thể bị ghi đè bởi lớp triển khai. Ngay cả khi có một phương thức tĩnh có cùng chữ ký, nó sẽ ẩn phương thức đó, không ghi đè lên nó. Vì vậy, nó là không quan trọng để khai báo phương thức trừu tượng là tĩnh vì nó sẽ không bao giờ có được cơ thể. Vì vậy, biên dịch lỗi thời gian.
Một phương thức tĩnh có thể được gọi mà không cần một thể hiện của lớp. Trong ví dụ của bạn, bạn có thể gọi foo.bar2 (), nhưng không phải foo.bar (), vì đối với thanh bạn cần một thể hiện. Mã sau sẽ hoạt động:
foo var = new ImplementsFoo();
var.bar();
Nếu bạn gọi một phương thức tĩnh, nó sẽ được thực thi luôn cùng một mã. Trong ví dụ trên, ngay cả khi bạn xác định lại bar2 trong ImplementsFoo, một lệnh gọi tới var.bar2 () sẽ thực thi foo.bar2 ().
Nếu bar2 bây giờ không có triển khai (đó là ý nghĩa trừu tượng), bạn có thể gọi một phương thức mà không cần thực hiện. Điều đó rất có hại.
Tôi tin rằng tôi đã tìm thấy câu trả lời cho câu hỏi này, dưới dạng lý do tại sao các phương thức của giao diện (hoạt động giống như các phương thức trừu tượng trong lớp cha) không thể tĩnh. Đây là câu trả lời đầy đủ (không phải của tôi)
Về cơ bản các phương thức tĩnh có thể bị ràng buộc tại thời gian biên dịch, vì để gọi chúng, bạn cần chỉ định một lớp. Điều này khác với các phương thức cá thể, trong đó lớp tham chiếu mà bạn đang gọi phương thức có thể không xác định tại thời điểm biên dịch (do đó, khối mã nào được gọi chỉ có thể được xác định khi chạy).
Nếu bạn đang gọi một phương thức tĩnh, bạn đã biết lớp nơi nó được triển khai hoặc bất kỳ lớp con trực tiếp nào của nó. Nếu bạn xác định
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
Sau đó, bất kỳ Foo.bar();
cuộc gọi rõ ràng là bất hợp pháp, và bạn sẽ luôn luôn sử dụng Foo2.bar();
.
Với ý nghĩ này, mục đích duy nhất của một phương thức trừu tượng tĩnh sẽ là bắt buộc các lớp con thực hiện một phương thức như vậy. Ban đầu bạn có thể nghĩ rằng điều này RẤT sai, nhưng nếu bạn có một tham số loại chung <E extends MySuperClass>
thì sẽ rất tốt để đảm bảo thông qua giao diện E
có thể .doSomething()
. Hãy nhớ rằng do loại tổng quát xóa chỉ tồn tại ở thời gian biên dịch.
Vì vậy, nó sẽ hữu ích? Có, và có lẽ đó là lý do tại sao Java 8 cho phép các phương thức tĩnh trong các giao diện (mặc dù chỉ với cách triển khai mặc định). Tại sao không phải là các phương thức tĩnh trừu tượng với việc triển khai mặc định trong các lớp? Đơn giản là vì một phương thức trừu tượng với cách triển khai mặc định thực sự là một phương thức cụ thể.
Tại sao các phương thức tĩnh trừu tượng / giao diện không có triển khai mặc định? Rõ ràng, chỉ vì cách Java xác định khối mã nào nó phải thực thi (phần đầu tiên trong câu trả lời của tôi).
Bởi vì lớp trừu tượng là một khái niệm OOPS và các thành viên tĩnh không phải là một phần của OOPS ....
Bây giờ, điều chúng ta có thể khai báo các phương thức hoàn thành tĩnh trong giao diện và chúng ta có thể thực thi giao diện bằng cách khai báo phương thức chính bên trong một giao diện
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
Ý tưởng có một phương thức tĩnh trừu tượng là bạn không thể sử dụng trực tiếp lớp trừu tượng cụ thể đó cho phương thức đó, nhưng chỉ có đạo hàm đầu tiên mới được phép thực hiện phương thức tĩnh đó (hoặc cho khái quát: lớp thực tế của chung chung bạn sử dụng).
Bằng cách đó, bạn có thể tạo ví dụ một lớp trừu tượng sortableObject hoặc thậm chí giao diện với các phương thức tĩnh trừu tượng (tự động), xác định các tham số của các tùy chọn sắp xếp:
public interface SortableObject {
public [abstract] static String [] getSortableTypes();
public String getSortableValueByType(String type);
}
Bây giờ bạn có thể định nghĩa một đối tượng có thể sắp xếp có thể được sắp xếp theo các loại chính giống nhau cho tất cả các đối tượng này:
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
}
}
Bây giờ bạn có thể tạo một
public class SortableList<T extends SortableObject>
có thể truy xuất các loại, xây dựng menu bật lên để chọn loại để sắp xếp và sử dụng danh sách bằng cách lấy dữ liệu từ loại đó, cũng như chức năng thêm, khi loại đã được chọn, có thể tự động -ort các mục mới trong. Lưu ý rằng phiên bản của SortableList có thể truy cập trực tiếp vào phương thức tĩnh của "T":
String [] MenuItems = T.getSortableTypes();
Vấn đề với việc phải sử dụng một thể hiện là SortableList có thể chưa có các mục, nhưng đã cần cung cấp sắp xếp ưu tiên.
Cổ vũ, Olaf.
Đầu tiên, một điểm chính về các lớp trừu tượng - Một lớp trừu tượng không thể được khởi tạo (xem wiki ). Vì vậy, bạn không thể tạo bất kỳ trường hợp nào của một lớp trừu tượng.
Bây giờ, cách java xử lý các phương thức tĩnh bằng cách chia sẻ phương thức với tất cả các thể hiện của lớp đó.
Vì vậy, nếu bạn không thể khởi tạo một lớp, thì lớp đó không thể có các phương thức tĩnh trừu tượng vì một phương thức trừu tượng xin được mở rộng.
Bùng nổ.
Theo tài liệu Java :
Một phương thức tĩnh là một phương thức được liên kết với lớp trong đó nó được định nghĩa chứ không phải với bất kỳ đối tượng nào. Mỗi thể hiện của lớp chia sẻ các phương thức tĩnh của nó
Trong Java 8, cùng với các phương thức mặc định, các phương thức tĩnh cũng được cho phép trong một giao diện. Điều này giúp chúng tôi dễ dàng tổ chức các phương thức trợ giúp trong các thư viện của chúng tôi. Chúng ta có thể giữ các phương thức tĩnh cụ thể cho một giao diện trong cùng một giao diện chứ không phải trong một lớp riêng biệt.
Một ví dụ hay về điều này là:
list.sort(ordering);
thay vì
Collections.sort(list, ordering);
Một ví dụ khác về việc sử dụng các phương thức tĩnh cũng được đưa ra trong chính 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));
}
}
Bởi vì 'trừu tượng' có nghĩa là phương thức có nghĩa là bị ghi đè và người ta không thể ghi đè các phương thức 'tĩnh'.
Các phương thức thông thường có thể là trừu tượng khi chúng có nghĩa là bị ghi đè bởi các lớp con và được cung cấp chức năng. Hãy tưởng tượng lớp học Foo
được mở rộng bởiBar1, Bar2, Bar3
v.v ... Vì vậy, mỗi lớp sẽ có phiên bản riêng của lớp trừu tượng theo nhu cầu của họ.
Bây giờ, các phương thức tĩnh theo định nghĩa thuộc về lớp, chúng không liên quan gì đến các đối tượng của lớp hoặc các đối tượng của các lớp con của nó. Họ thậm chí không cần chúng tồn tại, chúng có thể được sử dụng mà không cần khởi tạo các lớp. Do đó, chúng cần phải sẵn sàng hoạt động và không thể phụ thuộc vào các lớp con để thêm chức năng cho chúng.
Bởi vì trừu tượng là một từ khóa được áp dụng trên các phương thức Trừu tượng không chỉ định phần thân. Và nếu chúng ta nói về từ khóa tĩnh, nó thuộc về khu vực lớp.
Bạn có thể làm điều này với các giao diện trong Java 8.
Đây là tài liệu chính thức về nó:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Bởi vì nếu một lớp mở rộng một lớp trừu tượng thì nó phải ghi đè các phương thức trừu tượng và đó là bắt buộc. Và vì các phương thức tĩnh là các phương thức lớp được giải quyết tại thời gian biên dịch trong khi các phương thức được ghi đè là các phương thức thể hiện được giải quyết trong thời gian chạy và theo đa hình động.