Я хотел бы добавить метод AddDefaultNamespace() к классу String в Java, чтобы я мог ввести "myString".AddDefaultNamespace() вместо DEFAULTNAMESPACE + "myString", чтобы получить что-то вроде "MyDefaultNameSpace.myString". Я также не хочу добавлять еще один производный класс (например, PrefixedString).
Возможно, этот подход вам не подходит, но я лично ненавижу использование +. Но, в любом случае, можно ли добавлять новые методы в класс String в Java?
Спасибо и привет.
Java полностью нуждается в методах расширения C# :)
java.lang.String. Learn more: http://manifold.systems/docs.htmlhttps://github.com/manifold-systems/manifold



String - это последний класс, что означает, что его нельзя расширить для работы над вашей собственной реализацией.
Это невозможно, поскольку String - это последний класс в Java.
Вы можете использовать вспомогательный метод все время, когда хотите что-то префикс. Если вам это не нравится, вы можете изучить Groovy или Scala, JRuby или JPython, оба являются языками для JVM, совместимыми с Java и допускающими такие расширения.
Невозможно, и это хорошо. Строка - это Строка. Его поведение определено, отклоняться от него было бы злом. Кроме того, он помечен как final, что означает, что вы не можете создать его подкласс, даже если бы захотели.
Лучше использовать StringBuilder, у которого есть метод append () и который выполняет нужную вам работу. Класс String является окончательным и не может быть расширен.
В объявлении класса все сказано, потому что вы не можете унаследовать его, потому что он окончательный. Вы, конечно, можете реализовать свой собственный строковый класс, но это, вероятно, просто хлопот.
public final class String
C# (.net 3.5) имеет возможность использовать методы расширения, но, к сожалению, java этого не делает. Существует некоторое расширение java, называемое nice http://nice.sourceforge.net/, хотя оно, похоже, добавляет ту же функциональность к 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.
Класс Java String является последним, что делает его неизменным. Это сделано из соображений эффективности, и что было бы чрезвычайно сложно логически расширить без ошибок; поэтому разработчики решили сделать его окончательным классом, что означает, что он не может быть расширен с помощью наследования.
Функциональность, которую вы хотите, чтобы ваш класс поддерживал, не является должным образом частью обычных обязанностей String в соответствии с принцип единой ответственности, пространство имен - это другая абстракция, она более специализирована. Поэтому вам следует определить новый класс, который включает String a member и поддерживает методы, необходимые для обеспечения требуемого управления пространством имен.
Не бойтесь добавлять абстракции (классы) - это суть хорошего объектно-ориентированного дизайна.
Попробуйте использовать карта сотрудничества с классовой ответственностью (CRC), чтобы прояснить нужную вам абстракцию.
Вы можете создать свою версию класса String и добавить метод :-)
Фактически, вы можете изменить класс String. Если вы отредактируете файл String.java, расположенный в src.zip, а затем перестроите rt.jar, класс String будет иметь дополнительные методы, добавленные вами. Обратной стороной является то, что этот код будет работать только на вашем компьютере или в том случае, если вы предоставите свой String.class и поместите его в путь к классам до пути по умолчанию.
Как уже говорили все, вы не можете создать подкласс 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;
}
}
Как уже отметили все, вам не разрешено расширять String (из-за final). Однако, если вы чувствуете себя действительно безумно, вы можете изменить саму String, поместить ее в jar и добавить к bootclasspath с -Xbootclasspath / p: myString.jar, чтобы фактически заменить встроенный класс String.
По причинам, которые я не буду вдаваться в подробности, я уже делал это раньше. Возможно, вам будет интересно узнать, что даже если вы можете заменить класс, внутренняя важность String во всех аспектах Java означает, что он используется на протяжении всего запуска JVM, а некоторые изменения просто нарушат работу JVM. Добавление новых методов или конструкторов не представляет проблемы. Добавление новых полей очень рискованно - в частности, добавление объектов или массивов, похоже, ломает вещи, хотя добавление примитивных полей, похоже, работает.
я попробую это. строка должна быть повторяемой. и пока мы находимся в этом: почему Java такая чертовски ужасная? ни один здравомыслящий человек не стал бы указывать remove в интерфейсе только для того, чтобы добавить throws UnsupportedOperationException - if the remove operation is not supported by this Iterator.
Хороший эксперимент, но поскольку безопасно добавлять только новые конструкторы или методы, похоже, нет никаких веских причин использовать этот подход по сравнению с тем, что предложил @ aldo-barreras
Все сказано другими участниками ранее. Вы не можете расширить String напрямую, потому что это окончательный вариант.
Если вы будете использовать 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?
}
Ну, вообще-то все лишены воображения. Мне нужно было написать свою собственную версию метода startWith, потому что мне нужен был тот, который не учитывал регистр.
class MyString{
public String str;
public MyString(String str){
this.str = str;
}
// Your methods.
}
Тогда это довольно просто, вы делаете свою String как таковую:
MyString StringOne = new MyString("Stringy stuff");
а когда вам нужно вызвать метод в библиотеке String, просто сделайте это так:
StringOne.str.equals("");
или что-то подобное, и вот оно ... расширение класса String.
Думаю нестандартно =).
Люди, выполняющие поиск с ключевыми словами «добавить метод к встроенному классу», могут оказаться здесь. Если вы хотите добавить метод к неокончательному классу, например 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, по умолчанию будет окончательным.
Абсолютно самая важная причина того, что String является неизменяемым или окончательным, заключается в том, что он используется механизмом загрузки классов и, таким образом, имеет глубокие и фундаментальные аспекты безопасности.
Если бы String была изменяемой или не окончательной, запрос на загрузку «java.io.Writer» мог быть изменен на загрузку «mil.vogoon.DiskErasingWriter»
ДА!
В зависимости от ваших требований (добавьте другое пространство имен в String и не используйте производный класс) вы можете использовать проект Lombok для этого и использовать функциональность в String следующим образом:
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() для любой строки в любом классе, если вы аннотировали ее и полученный результат для приведенного выше примера.
This is a String!
было бы:
This is a String! 17
IntelliJ выделяет мой метод расширения, как будто это ошибка, а затем он отлично компилируется.
Это не расширение класса, только метод начальной загрузки может заменить класс String. Однако он очень хорошо имитирует добавление методов, перекомпилируя Main для вызова статических методов в Extension. Это идеальный ответ на этот вопрос. Но будьте осторожны, если вы вызовете String.class.getDeclaredMethod, он не будет найден.
Было бы здорово иметь возможность обезьяны патчить Java.