#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