Подтвердить что ты не робот

Могу ли я добавить новые методы в класс String в Java?

Я хотел бы добавить метод AddDefaultNamespace() к классу String в Java, чтобы я мог напечатать "myString".AddDefaultNamespace() вместо DEFAULTNAMESPACE + "myString", чтобы получить что-то вроде "MyDefaultNameSpace.myString". Я не хочу добавлять другой производный класс (например, PrefixedString).

Возможно, такой подход не очень хорош для вас, но я лично ненавижу использовать +. Но, в любом случае, возможно ли добавить новые методы в класс String в Java?

Спасибо и всего наилучшего.

4b9b3361

Ответ 1

String - это последний класс, который означает, что он не может быть расширен для работы над вашей собственной реализацией.

Ответ 2

Ну, на самом деле все невообразимо. Мне нужно было написать собственную версию метода startsWith, потому что мне нужен был тот, который был нечувствителен к регистру.

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

Тогда это довольно просто, вы создаете свою строку как таковую:

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

и когда вам нужно вызвать метод в библиотеке String, выполните следующие действия:

StringOne.str.equals("");

или что-то подобное, и там у вас есть... расширение класса String.

Ответ 3

Как все остальные отметили, вам не разрешено расширять String (из-за окончательного). Однако, если вы чувствуете себя действительно дико, вы можете сами изменить строку, поместить ее в банку и добавить путь bootclasspath к -Xbootclasspath/p: myString.jar, чтобы фактически заменить встроенный класс String.

По причинам, в которые я не буду вдаваться, я уже делал это раньше. Вам может быть интересно узнать, что, хотя вы можете заменить класс, внутренняя важность String во всех аспектах Java означает, что он используется во время запуска JVM, и некоторые изменения просто разрушают JVM. Добавление новых методов или конструкторов, кажется, не проблема. Добавление новых полей очень рискованное - в частности добавление объектов или массивов, похоже, ломает ситуацию, хотя, похоже, добавление примитивных полей работает.

Ответ 4

Это невозможно, так как String является окончательным классом в Java.

Вы можете использовать вспомогательный метод все время, когда хотите что-то префикс. Если вам не нравится это, вы можете посмотреть в Groovy или Scala, JRuby или JPython - это языки для JVM, совместимые с Java, и которые разрешают такие расширения.

Ответ 5

В объявлении класса сказано, что все это в значительной степени, так как вы не можете наследовать его, потому что оно окончательное. Вы можете, конечно, реализовать свой собственный строковый класс, но это probaby просто хлопот.

public final class String

С# (.net 3.5) имеют функциональность для использования меток расширителя, но, к сожалению, java этого не делает. Существует некоторое расширение java, называемое nice http://nice.sourceforge.net/, хотя похоже, что для java существует такая же функциональность.

Вот как вы могли бы написать свой пример на Ниццком языке (расширение 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);

}

Вы можете найти больше о Ницце в http://nice.sf.net

Ответ 6

Невозможно, и это хорошо. Строка - это строка. Это поведение определено, отклонение от него было бы злым. Кроме того, он был помечен как окончательный, то есть вы не могли подклассифицировать его, даже если хотите.

Ответ 7

Как и все остальные, нет, вы не можете подклассифицировать 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;
    }

}

Ответ 8

ДА!

Основываясь на ваших требованиях (добавьте другое пространство имен в String и не используйте производный класс), вы можете использовать проект Lombok для этого и использовать функциональность на String следующим образом:

String i = "This is my String";
i.numberOfCapitalCharacters(); // = 2

Используя идеи Gradle и IntelliJ, выполните следующие действия:

  1. Загрузите плагин lombok из репозитория плагинов intelliJ.
  2. добавьте lombok в зависимости от градиента, например: compileOnly 'org.projectlombok:lombok:1.16.20'
  3. перейдите в "Settings > Build > Compiler > Annotation Processors" и включите обработку аннотаций
  4. создайте класс с вашими расширениями и добавьте статический метод следующим образом:

    public class Extension { public static String appendSize(String i){ return я + " " + i.length(); } }

  5. аннотируйте класс, в котором вы хотите использовать свой метод следующим образом:

    import lombok.experimental.ExtensionMethod; @ExtensionMethod({Extension.class}) public class Main { public static void main(String[] args) { String я = "This is a String!"; System.out.println(i.appendSize()); } }

Теперь вы можете использовать метод .appendSize() для любой строки в любом классе, если у вас есть (аннотированный), и полученный результат для приведенного выше примера (This is a String!) Будет: This is a String! 17 This is a String! 17

Ответ 9

Лучше использовать StringBuilder, который имеет метод append() и выполняет задание, которое вы хотите. Класс String является окончательным и не может быть расширен.

Ответ 10

Поиск людей с ключевыми словами "добавить метод к встроенному классу" может оказаться здесь. Если вы хотите добавить метод к конечному классу, например 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");

EDIT:

В приведенном выше коде для доступа к встроенным методам класса карты вам нужно будет использовать

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");

Ответ 11

Нет. Вы не можете изменить класс строк в java. Потому что это последний класс. и каждый метод, присутствующий в конечном классе по умолчанию, будет окончательным.

Абсолютно важная причина, по которой String является неизменной или окончательной, заключается в том, что она используется механизмом загрузки классов и, следовательно, имеет глубокие и фундаментальные аспекты безопасности.

Если String была изменчивой или окончательной, запрос на загрузку "java.io.Writer" можно было бы изменить, чтобы загрузить "mil.vogoon.DiskErasingWriter"

Ответ 12

Класс Java String является окончательным, что делает его неизменным. Это по соображениям эффективности и что было бы чрезвычайно сложно логически распространяться без ошибок; поэтому разработчики решили сделать его окончательным классом, означающим, что он не может быть расширен с наследованием.

Функциональность, которую вы хотите, чтобы ваш класс поддерживал, не является должным образом частью регулярных обязанностей строки в соответствии с принципом единой ответственности , пространство имен - это другая абстракция, более специализированная. Поэтому вы должны определить новый класс, который включает в себя элемент String и поддерживает методы, необходимые для обеспечения требуемого управления пространством имен.

Не бойтесь добавлять абстракции (классы), это суть хорошего дизайна OO.

Попробуйте использовать коллекцию совместной работы (CRC), чтобы уточнить требуемую абстракцию.

Ответ 13

Все сказано другими участниками ранее. Вы не можете напрямую передавать строку, потому что она является окончательной.

Если вы используете 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?
  }

Ответ 14

Вы можете создать свою собственную версию класса String и добавить метод: -)

Ответ 15

Собственно, вы можете изменить класс String. Если вы отредактируете файл String.java, расположенный в src.zip, а затем перестройте rt.jar, класс String будет содержать больше методов, добавленных вами. Недостатком является то, что этот код будет работать только на вашем компьютере или если вы предоставите свой String.class и поместите его в путь к классу до того, как он по умолчанию.