Как предотвратить автоматическое преобразование объекта в строку

#java #compiler-errors #type-conversion #java-6

#java #ошибки компилятора #преобразование типов #java-6

Вопрос:

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

 public class FileEntry {
    private String name;
    public FileEntry (String name) {
        this.name = name;
    }
}

void foo(String arg){};
foo("string"   new FileEntry("")); // How to get a compile error here
  

Как я могу заставить java выдавать ошибку компиляции вместо автоматического преобразования объекта в строку?

Комментарии:

1. «Я использую этот класс в методе со строковым аргументом» — подожди, ват? Что значит, когда вы передаете результат вызова метода? Какой тип возвращаемого значения у этого метода?

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

3. Похоже, вам нужно немного переосмыслить свой дизайн. При каких обстоятельствах вам это понадобится?

4. Я не верю в то, что, как мне кажется, я понимаю. Можете ли вы показать фактический код, в котором происходит «преобразование в строку»?

5. @delnan — да, я этого не понимаю. Наверняка передача FileEntry методу, который принимает строку, приведет к ошибке компиляции?

Ответ №1:

Если у вас есть

 void foo(String bar)
{

}
  

и вы вызываете

 foo(new FileEntry());
  

произойдет ошибка компилятора. Смотрите здесь

toString() будет вызван, только если вы сделаете что-то вроде

 foo("this is foo"   new FileEntry());
  

Комментарии:

1. Спасибо за все ответы. Вы правы. Проблема возникает при преобразовании строки. Однако было бы неплохо, если бы существовал способ определить это время компиляции. Отредактирует мой вопрос

Ответ №2:

это невозможно сделать во время компиляции. во время выполнения вы можете создать исключение из переопределенного метода toString

Ответ №3:

Вызов toString() — это не то же самое, что приведение — вы должны осознавать разницу.

Вы могли бы переопределить toString() , чтобы не только генерировать исключение, но и быть устаревшим:

 @Deprecated @Override
public String toString() {
    throw new IllegalStateException("toString mustn't be called on this class");
}
  

Это только поможет во время компиляции, если тип выражения во время компиляции FileEntry . Это также будет просто предупреждением в большинстве конфигураций.

Это также потенциально может сбить с толку отладчики, которые пытаются вызвать toString() автоматически и т.д.

Ответ №4:

Я не могу придумать другого способа, кроме переопределения toString() и создания исключения внутри.

Ответ №5:

Если я использую этот класс в методе со строковым аргументом, компилятор java автоматически преобразует это в строковый объект с помощью toString()

Нет, этого не произойдет. Что он будет делать, так это вызывать перегруженный метод, который принимает Object параметр, если такой метод существует — а такие методы часто вызываются toString() для параметра.

Вы ничего не можете сделать, чтобы предотвратить использование перегруженных методов — в конце концов, они были помещены туда специально.

Ответ №6:

Как указывали другие, "str" obj не включает приведение типа.

Это также не требует перегрузки или вызова String.concat(String) . (Действительно, str1.concat(str2) дает результат, отличный от того, str1 str2 когда str2 есть null !)

Технически говоря, это называется «преобразованием строки»; см. JLS 5.1.11. Преобразование эквивалентно вызову String.valueOf(Object) или статического toString(primitive) метода соответствующего класса-примитивной оболочки.

Ответ №7:

Как упоминалось в комментариях, я не понимаю, что именно происходит. Но FileEntry@6e470ce1, вероятно, является результатом метода toString FileEntry. Вы можете перезаписать это, чтобы возвращать все, что хотите, при условии, что это строка.

Ответ №8:

Я не уверен, почему бы вам просто не реализовать toString() метод в FileEntry . Если вам действительно нужна ошибка компиляции, вы можете создать базовый абстрактный класс типа:

 public abstract class ForceImplementToString {
  @Override
  public abstract String toString();
}
  

Затем создайте свой класс следующим образом, это создаст ошибку компиляции, из-за которой вам придется реализовать toString() метод:

 public class FileEntry extends ForceImplementToString {
    private String name;
    public FileEntry (String name) {
        this.name = name;
    }
}
  

Ответ №9:

Object Класс имеет toString() , который наследуется каждым классом в Java (поскольку сам класс является производным от Object ). Это toString() будет вызвано (если только оно не переопределено, и в этом случае будет вызван переопределенный этот конкретный объект toString() ).

Вы ничего не можете сделать, чтобы предотвратить это.

С другой стороны, как выглядит ваш метод? Если у вас есть public myMethod(String arg) и вы вызываете myMethod(new FileEntry()) , я почти уверен, что это приводит к ошибке времени компиляции.

Конечно, если у вас есть перегруженный метод, который имеет Object arg в качестве параметра, то будет вызван именно этот метод. Внутри этот метод, вероятно, вызывается toString() on arg . Кроме того, использование объекта, который не является строкой в контексте строки (например, если вы объединяете его со строкой), приводит к неявному вызову этого объекта toString() (который может быть переопределенным или использоваться по умолчанию from из Object ).).

Чтобы получить более красивый результат от toString() , вы должны переопределить toString() в FileEntry классе, чтобы он печатал что-то, что имеет больше смысла.

Ответ №10:

Я не думаю, что ваша предпосылка верна. Java не преобразует объекты в строки автоматически. Этот код:

 public class Foo {
    public static void main(String[] args) {
        Foo foo = new Foo();
        String got = "Concatenated: ".concat(foo);
        System.out.println(got);
    }
    public String toString() {
        return "Foo object";
    }
}
  

выдает этот вывод из моего компилятора Java 1.6.0_23:

 Foo.java:4: concat(java.lang.String) in java.lang.String cannot be applied to (Foo)  
            String got = "Concatenated: ".concat(foo);
                                         ^
1 error
  

Ответ №11:

Вы всегда можете загрузить исходный код для java и удалить toString() из Object.

Комментарии:

1. Тогда это больше не было бы java