JavaのStringクラスにメソッドAddDefaultNamespace()
を追加して、_DEFAULTNAMESPACE + "myString"
_の代わりに"myString".AddDefaultNamespace()
と入力できるようにします。 _"MyDefaultNameSpace.myString"
_のようなものを取得します。別の派生クラス(たとえば、PrefixedString
)も追加したくありません。
このアプローチはあなたにとって良くないかもしれませんが、私は個人的に_+
_を使うのが嫌いです。しかし、とにかく、JavaのStringクラスに新しいメソッドを追加することは可能ですか?
よろしくお願いします。
String
は最終クラスです。つまり、独自の実装で動作するように拡張することはできません。
まあ、実際には誰もが想像を絶するものです。大文字と小文字を区別しない独自のバージョンのstartsWithメソッドを作成する必要がありました。
class MyString{
public String str;
public MyString(String str){
this.str = str;
}
// Your methods.
}
次に、それは非常に簡単です。文字列を次のように作成します。
MyString StringOne = new MyString("Stringy stuff");
文字列ライブラリのメソッドを呼び出す必要がある場合は、次のように簡単に実行できます。
StringOne.str.equals("");
または同様の何か、そしてあなたはそれを持っています... Stringクラスの拡張。
他の誰もが指摘しているように、Stringを拡張することは許可されていません(finalのため)。ただし、本当にワイルドに感じている場合は、String自体を変更してjarに配置し、bootclasspathの前に-Xbootclasspath/p:myString.jarを追加して、組み込みのStringクラスを実際に置き換えることができます。
入らない理由で、私は実際にこれを以前に行ったことがあります。クラスを置き換えることはできますが、Javaのすべての面でStringが本質的に重要であることは、JVMの起動全体で使用され、一部の変更は単純に行われることを意味します。 JVMを壊します。新しいメソッドやコンストラクターを追加することは問題ないようです。新しいフィールドを追加することは非常に厄介です。特に、オブジェクトや配列を追加すると、プリミティブフィールドを追加することはできますが、問題が発生するようです。
StringはJavaの最終クラスであるため、これは不可能です。
何かにプレフィックスを付けたいときはいつでもヘルパーメソッドを使用できます。それが気に入らない場合は、GroovyまたはScalaを調べることができます。JRubyまたはJPythonはどちらも、Javaと互換性があり、そのような拡張機能を許可するJVM用の言語です。
他のみんなが言っているように、Stringは最終的なものなので、サブクラス化することはできません。しかし、次のようなものが役立つでしょうか?
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;
}
}
または多分:
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;
}
}
不可能です、そしてそれは良いことです。文字列は文字列です。その振る舞いは定義されており、それから逸脱することは悪です。また、finalとマークされているため、必要な場合でもサブクラス化できませんでした。
「組み込みクラスにメソッドを追加する」というキーワードで検索する人は、ここにたどり着くかもしれません。 HashMapなどの非最終クラスにメソッドを追加する場合は、次のようにすることができます。
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);
}
}
次に、このクラスの新しいインスタンスを次のように定義します。
ObjectMap objectMap = new ObjectMap(new HashMap<String, Object>();
これで、組み込みのMapクラスのすべてのメソッドと、新しく実装されたメソッドにアクセスできます。
objectMap.getInt("KEY");
編集:
上記のコードでは、マップクラスの組み込みメソッドにアクセスするには、次を使用する必要があります。
objectMap.map.get("KEY");
さらに良い解決策は次のとおりです。
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;
}
}
今、あなたは電話する必要はありません
objectMap.map.get("KEY");
単に電話する
objectMap.get("KEY");
いいえJavaで文字列クラスを変更することはできません。ファイナルクラスだから。そして、デフォルトでfinalクラスに存在するすべてのメソッドがfinalになります。
Stringが不変またはfinalであるという絶対的に最も重要な理由は、Stringがクラスのロードメカニズムによって使用されるため、セキュリティの面で深く基本的な側面があるためです。
Stringが変更可能であるか、最終的でない場合、「Java.io.Writer」をロードする要求は「mil.vogoon.DiskErasingWriter」をロードするように変更されている可能性があります。
はい!
要件に基づいて(別の名前空間を文字列に追加し、派生クラスを使用しない)、プロジェクトLombokを使用してそれを実行し、次のような文字列の機能を使用できます。
_String i = "This is my String";
i.numberOfCapitalCharacters(); // = 2
_
GradleとIntelliJのアイデアを使用するには、以下の手順に従います。
compileOnly 'org.projectlombok:lombok:1.16.20'
_"Settings > Build > Compiler > Annotation Processors"
_に移動し、注釈処理を有効にします拡張関数を使用してクラスを作成し、次のような静的メソッドを追加します。
_public class Extension {
public static String appendSize(String i){
return i + " " + i.length();
}
}
_
次のように、メソッドを使用するクラスに注釈を付けます。
_import lombok.experimental.ExtensionMethod;
@ExtensionMethod({Extension.class})
public class Main {
public static void main(String[] args) {
String i = "This is a String!";
System.out.println(i.appendSize());
}
}
_
これで、注釈を付けて上記の例で生成された結果を取得している限り、任意のクラスの任意の文字列でメソッド.appendSize()
を使用できます。
これはひもです!
だろう:
これはひもです! 17
メソッドappend()を持ち、必要なジョブを実行するStringBuilderを使用することをお勧めします。 Stringクラスはfinalであり、拡張できません。
すべては前に他の貢献者によって言われています。 Stringはfinalであるため、直接拡張することはできません。
Scalaを使用する場合は、次のような暗黙的な変換を使用できます。
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?
}
Java Stringクラスは最終クラスであり、不変になります。これは効率上の理由であり、エラーなしで論理的に拡張することは非常に困難です。したがって、実装者はこれを最終クラスにすることを選択しました。つまり、継承によって拡張することはできません。
クラスでサポートしたい機能は、 単一責任の原則 のように、文字列の通常の責任の一部ではありません。名前空間は別の抽象化であり、より専門的です。したがって、Stringメンバーを含み、必要な名前空間管理を提供するために必要なメソッドをサポートする新しいクラスを定義する必要があります。
抽象化(クラス)を追加することを恐れないでください。これらは優れたOO設計の本質です。
クラス責任コラボレーション(CRC)カード を使用して、必要な抽象化を明確にしてください。