2008-09-17 44 views
21

Tôi muốn thêm phương thức AddDefaultNamespace() vào lớp String trong Java để tôi có thể nhập "myString" .AddDefaultNamespace() thay vì DEFAULTNAMESPACE + "myString", để lấy một cái gì đó như "MyDefaultNameSpace.myString". Tôi không muốn thêm một lớp dẫn xuất khác (ví dụ PrefixedString).Tôi có thể thêm các phương thức mới vào lớp String trong Java không?

Có thể cách tiếp cận này không tốt cho bạn nhưng cá nhân tôi ghét sử dụng "+". Nhưng, dù sao, có thể thêm các phương thức mới vào lớp String trong Java không?

Cảm ơn và kính trọng.

+1

Nó sẽ được mát mẻ để có thể Java khỉ vá . – jjnguy

+2

Java hoàn toàn cần các phương thức mở rộng C# :) – Kurru

Trả lời

55

String là lớp cuối cùng có nghĩa là nó không thể được mở rộng để hoạt động khi bạn triển khai.

+0

Đơn giản và rõ ràng. Cảm ơn GustlyWind và những người còn lại của bạn. – user15546

6

Không thể, vì Chuỗi là lớp cuối cùng trong Java.

Bạn có thể sử dụng phương pháp trợ giúp tất cả thời gian bạn muốn thêm tiền tố vào thứ gì đó. Nếu bạn không thích điều đó, bạn có thể nhìn vào Groovy hoặc Scala, JRuby hoặc JPython cả hai đều là ngôn ngữ cho JVM tương thích với Java và cho phép các phần mở rộng đó.

2

Không thể, và đó là một điều tốt. Chuỗi là một chuỗi. Hành vi của nó được định nghĩa, lệch khỏi nó sẽ là điều ác. Ngoài ra, nó được đánh dấu cuối cùng, có nghĩa là bạn không thể phân lớp nó ngay cả khi bạn muốn.

1

Sử dụng tốt hơn StringBuilder, có phương thức chắp thêm() và thực hiện công việc bạn muốn. Lớp String là cuối cùng và không thể được mở rộng.

3

Việc khai báo lớp học nói rằng tất cả khá nhiều, vì bạn không thể kế thừa nó bởi vì nó là cuối cùng. Bạn có thể ofcourse thực hiện chuỗi lớp của riêng bạn, nhưng đó là probaby chỉ là một rắc rối.

public final class String 

C# (.net 3.5) có chức năng sử dụng metods mở rộng nhưng đáng tiếc java không. Có một số phần mở rộng java được gọi là đẹp http://nice.sourceforge.net/ mặc dù có vẻ như thêm chức năng tương tự cho java.

Đây là cách bạn sẽ viết ví dụ của bạn ở Nice ngôn ngữ (một phần mở rộng của Java):

private String someMethod(String s) 
{ 
    return s.substring(0,1); 

} 

void main(String[] args) 
{ 
    String s1 = "hello"; 
    String s2 = s1.someMethod(); 
    System.out.println(s2); 

} 

Bạn có thể tìm thêm về đẹp tại http://nice.sf.net

0

Java Chuỗi lớp được một trận chung kết , làm cho nó không thay đổi. Điều này là vì lý do hiệu quả và rằng nó sẽ vô cùng khó khăn để hợp lý mở rộng mà không có lỗi; do đó, những người thực hiện đã chọn làm cho nó trở thành một lớp cuối cùng có nghĩa là nó không thể được mở rộng với thừa kế.

Chức năng bạn muốn lớp học của bạn hỗ trợ không phải là một phần trách nhiệm thường xuyên của chuỗi theo single responsibility principle, một không gian tên nó trừu tượng khác, nó chuyên biệt hơn. Do đó, bạn nên định nghĩa một lớp mới, bao gồm String thành viên và hỗ trợ các phương thức bạn cần để cung cấp việc quản lý không gian tên mà bạn yêu cầu.

Đừng ngại thêm trừu tượng (các lớp) đây là bản chất của thiết kế OO tốt.

Hãy thử sử dụng class responsibility collaboration (CRC) card để làm rõ sự trừu tượng mà bạn cần.

+1

Tại sao lại là downvote? –

-2

Bạn có thể tạo phiên bản chuỗi lớp của riêng mình và thêm phương thức :-)

-2

Thực ra, bạn có thể sửa đổi lớp Chuỗi. Nếu bạn chỉnh sửa tệp String.java nằm trong src.zip và sau đó xây dựng lại rt.jar, lớp String sẽ có thêm các phương thức do bạn thêm vào. Nhược điểm là mã đó sẽ chỉ hoạt động trên máy tính của bạn, hoặc nếu bạn cung cấp String.class của bạn, và đặt nó trong classpath trước lớp mặc định.

2

Như mọi người khác đã nói, không bạn không thể phân lớp chuỗi vì nó là cuối cùng. Nhưng có thể điều gì đó giống như sự giúp đỡ sau đây?

public final class NamespaceUtil { 

    // private constructor cos this class only has a static method. 
    private NamespaceUtil() {} 

    public static String getDefaultNamespacedString(
      final String afterDotString) { 
     return DEFAULT_NAMESPACE + "." + afterDotString; 
    } 

} 

hoặc có thể:

public final class NamespacedStringFactory { 

    private final String namespace; 

    public NamespacedStringFactory(final String namespace) { 
     this.namespace = namespace; 
    } 

    public String getNamespacedString(final String afterDotString) { 
     return namespace + "." + afterDotString; 
    } 

} 
16

Như mọi người khác đã lưu ý, bạn không được phép để mở rộng chuỗi (do cuối cùng). Tuy nhiên, nếu bạn cảm thấy thực sự hoang dã, bạn có thể sửa đổi chính String, đặt nó vào một cái bình và thêm lớp bootclasspath với -Xbootclasspath/p: myString.jar để thực sự thay thế lớp String dựng sẵn.

Vì lý do tôi sẽ không tham gia, tôi đã thực sự thực hiện việc này trước đây. Bạn có thể quan tâm để biết rằng mặc dù bạn có thể thay thế lớp, tầm quan trọng nội tại của String trong mọi khía cạnh của Java có nghĩa là nó được sử dụng trong suốt quá trình khởi động của JVM và một số thay đổi sẽ đơn giản phá vỡ JVM. Việc thêm các phương thức hoặc các hàm tạo mới dường như không có vấn đề gì. Thêm các trường mới là rất dicey - đặc biệt là thêm các đối tượng hoặc mảng dường như phá vỡ mọi thứ mặc dù thêm các trường nguyên thủy có vẻ hoạt động.

+0

tôi sẽ thử điều này. chuỗi cần phải được lặp lại. và trong khi chúng tôi đang ở đó: làm thế nào đến java là như vậy damn khủng khiếp? không có người sane nào sẽ chỉ định 'remove' trong một giao diện, chỉ để thêm' throws UnsupportedOperationException - nếu thao tác remove không được hỗ trợ bởi Iterator' này. –

+0

Thử nghiệm tốt nhưng vì chỉ an toàn khi thêm các nhà xây dựng mới hoặc các phương pháp dường như không có lý do hợp lệ nào để thực hiện cách tiếp cận này qua những gì @ aldo-barreras đề xuất – Ozzy

0

Tất cả được nói bởi những người đóng góp khác trước đây. Bạn không thể mở rộng chuỗi trực tiếp bởi vì nó là cuối cùng.

Nếu bạn muốn sử dụng Scala, bạn có thể sử dụng chuyển đổi ngầm như thế này:

object Snippet { 
    class MyString(s:String) { 
    def addDefaultNamespace = println("AddDefaultNamespace called") 
    } 
    implicit def wrapIt(s:String) = new MyString(s) 

    /** test driver */ 
    def main(args:Array[String]):Unit = { 
    "any java.io.String".addDefaultNamespace // !!! THAT is IT! OR? 
    } 
20

Vâng, thực sự tất cả mọi người đang được unimaginative. Tôi cần viết phiên bản startWith của riêng mình vì tôi cần một phương thức không phân biệt chữ hoa chữ thường.

class MyString{ 
    public String str; 
    public MyString(String str){ 
     this.str = str; 
    } 
    // Your methods. 
} 

Sau đó, nó khá đơn giản, bạn thực hiện chuỗi của bạn như vậy:

MyString StringOne = new MyString("Stringy stuff"); 

và khi bạn cần phải gọi một phương thức trong thư viện String, làm đơn giản quá như thế này:

StringOne.str.equals(""); 

hoặc một cái gì đó tương tự, và ở đó bạn có nó ... mở rộng của lớp String.

+2

Suy nghĩ ra khỏi hộp =). – Ozzy

1

Những người đang tìm kiếm bằng từ khóa "thêm phương thức vào lớp học tích hợp" có thể kết thúc ở đây. Nếu bạn đang tìm cách thêm phương thức vào một lớp không phải cuối cùng như HashMap, bạn có thể làm một cái gì đó như thế này.

public class ObjectMap extends HashMap<String, Object> { 

    public Map<String, Object> map; 

    public ObjectMap(Map<String, Object> map){ 
     this.map = map; 
    } 

    public int getInt(String K) { 
     return Integer.valueOf(map.get(K).toString()); 
    } 

    public String getString(String K) { 
     return String.valueOf(map.get(K)); 
    } 

    public boolean getBoolean(String K) { 
     return Boolean.valueOf(map.get(K).toString()); 
    } 

    @SuppressWarnings("unchecked") 
    public List<String> getListOfStrings(String K) { 
     return (List<String>) map.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public List<Integer> getListOfIntegers(String K) { 
     return (List<Integer>) map.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public List<Map<String, String>> getListOfMapString(String K) { 
     return (List<Map<String, String>>) map.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public List<Map<String, Object>> getListOfMapObject(String K) { 
     return (List<Map<String, Object>>) map.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public Map<String, Object> getMapOfObjects(String K) { 
     return (Map<String, Object>) map.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public Map<String, String> getMapOfStrings(String K) { 
     return (Map<String, String>) map.get(K); 
    } 
} 

Bây giờ xác định một Instance mới của lớp này như:

ObjectMap objectMap = new ObjectMap(new HashMap<String, Object>(); 

Bây giờ bạn có thể truy cập vào tất cả các phương pháp của built-in Class Bản đồ, và cũng là phương pháp mới được thực hiện.

objectMap.getInt("KEY"); 

EDIT:

Trong đoạn mã trên, để truy cập vào các phương pháp tích hợp các lớp bản đồ, bạn sẽ phải sử dụng

objectMap.map.get("KEY"); 

Dưới đây là một giải pháp tốt hơn:

public class ObjectMap extends HashMap<String, Object> { 

    public ObjectMap() { 

    } 

    public ObjectMap(Map<String, Object> map){ 
     this.putAll(map); 
    } 

    public int getInt(String K) { 
     return Integer.valueOf(this.get(K).toString()); 
    } 

    public String getString(String K) { 
     return String.valueOf(this.get(K)); 
    } 

    public boolean getBoolean(String K) { 
     return Boolean.valueOf(this.get(K).toString()); 
    } 

    @SuppressWarnings("unchecked") 
    public List<String> getListOfStrings(String K) { 
     return (List<String>) this.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public List<Integer> getListOfIntegers(String K) { 
     return (List<Integer>) this.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public List<Map<String, String>> getListOfMapString(String K) { 
     return (List<Map<String, String>>) this.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public List<Map<String, Object>> getListOfMapObject(String K) { 
     return (List<Map<String, Object>>) this.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public Map<String, Object> getMapOfObjects(String K) { 
     return (Map<String, Object>) this.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public Map<String, String> getMapOfStrings(String K) { 
     return (Map<String, String>) this.get(K); 
    } 

    @SuppressWarnings("unchecked") 
    public boolean getBooleanForInt(String K) { 
     return Integer.valueOf(this.get(K).toString()) == 1 ? true : false; 
    } 
} 

Bây giờ bạn không phải gọi

objectMap.map.get("KEY"); 

chỉ cần gọi

objectMap.get("KEY"); 
1

Không Bạn Không thể Sửa Chuỗi Class trong java. Bởi vì đó là lớp cuối cùng. và mọi phương thức có trong lớp cuối cùng theo mặc định sẽ là cuối cùng.

Lý do quan trọng nhất là String không thay đổi hoặc cuối cùng là nó được cơ chế tải lớp sử dụng và do đó có các khía cạnh bảo mật sâu sắc và cơ bản.

Có phải Chuỗi được có thể thay đổi hoặc không chính thức, một yêu cầu để tải "java.io.Writer" có thể đã được thay đổi để nạp "mil.vogoon.DiskErasingWriter"

Các vấn đề liên quan