Отключение зависимости времени компиляции, проверяющей при компиляции классов Java

Насколько я знаю, это не поддерживается с полнотекстовым поиском MySQL, но можно достигнуть эффекта, так или иначе повторяя что слово несколько раз в поле ключевого слова. Вместо того, чтобы иметь ключевые слова "панель нечто", имейте "панель нечто панели нечто панели нечто", тот путь и нечто и панель одинаково важны в столбце ключевых слов, и так как они несколько раз появляются, они становятся более относящимися к mysql.

Мы используем это на нашем сайте, и он работает.

12
задан knorv 8 October 2009 в 13:11
поделиться

8 ответов

Можете ли вы привести какой-либо пример, для которого было бы технически невозможно сгенерировать допустимый файл класса Java без выполнения проверки зависимостей времени компиляции?

Рассмотрим этот код:

public class GotDeps {
  public static void main(String[] args) {
    int i = 1;
    Dep.foo(i);
  }
}

Если целевой метод имеет подпись public static void foo (int n) , то будут сгенерированы следующие инструкции:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   istore_1
   2:   iload_1
   3:   invokestatic    #16; //Method Dep.foo:(I)V
   6:   return

Если целевой метод имеет подпись public static void foo (long n) , тогда int будет повышен до long до вызова метода:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_1
   1:   istore_1
   2:   iload_1
   3:   i2l
   4:   invokestatic    #16; //Method Dep.foo:(J)V
   7:   return

В этом случае было бы невозможно сгенерировать инструкции вызова или как заполнить Структура CONSTANT_Methodref_info , указанная в пуле констант классов числом 16. Подробнее см. формат файла класса в спецификации VM.

19
ответ дан 2 December 2019 в 05:15
поделиться

Я не понимаю, как вы могли бы разрешить это, не нарушая тип java проверка. Как бы вы использовали объект, на который указывает ссылка, в своем методе? В качестве дополнения к вашему примеру:

class test {
   void foo (pkg.not.in.classpath.FooBar foobar) { 
       foobar.foobarMethod(); //what does the compiler do here?
  } 
}

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

 void foo(Object suspectedFoobar)
     {
       try{
        Method m = suspectedFoobar.getClass().getMethod("foobarMethod");
        m.invoke(suspectedFoobar);
       }
       ...
     }

Однако я не вижу смысла делать это. Не могли бы вы предоставить дополнительную информацию о проблеме, которую пытаетесь решить?

2
ответ дан 2 December 2019 в 05:15
поделиться

Я не думаю, что существует такой способ - компилятор должен знать о классе аргумента, чтобы создать соответствующий байт-код. Если он не может найти класс Foobar, он не может скомпилировать класс Test .

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

Итак, ваша предпосылка - что компилятор не должен находить класс для компиляции в этом случае - неверна.

Изменить - ваш комментарий кажется спросить: «Не может ли компилятор просто упустить этот факт и сгенерировать байт-код, который в любом случае будет подходящим?»

Ответ - нет - не может. Согласно спецификации языка Java , сигнатуры методов должны принимать типы, которые в другом месте определены , чтобы их можно было разрешить во время компиляции.

Это означает, что, хотя это было бы механически довольно просто чтобы создать компилятор, который будет делать то, что вы просите, он нарушил бы JLS и, следовательно, технически не был бы компилятором Java. Кроме того, обход безопасности во время компиляции не кажется мне большим аргументом в пользу продажи ...: -)

5
ответ дан 2 December 2019 в 05:15
поделиться

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

Что можно сделать (и сделано, скажем, для драйверов JDBC), так это отложить проверку зависимостей с помощью отражения. Вы можете получить класс из Class.forName без того, чтобы компилятор знал класс во время компиляции. В общем, однако, это означает, что код записывается в интерфейс, и во время выполнения загружается класс, реализующий интерфейс.

1
ответ дан 2 December 2019 в 05:15
поделиться

Компиляция класса без просмотра сигнатур типов классов, от которых он зависит, было бы нарушением JLS. Ни один совместимый компилятор Java не позволил бы вам сделать это.

Однако ... можно сделать нечто подобное. В частности, если у нас есть класс A и класс B, который зависит от A, можно сделать следующее:

  1. Скомпилировать A.java
  2. Скомпилировать B.java против A.class.
  3. Отредактировать A. java, чтобы изменить его несовместимым образом.
  4. Скомпилируйте A.java, заменив старый A.class.
  5. Запустите приложение Java, используя B.class и новый (несовместимый) A.class.

Если вы сделайте это, приложение завершится ошибкой IncompatibleClassChangeError , когда загрузчик классов заметит несовместимость подписи.

На самом деле, это иллюстрирует, почему компиляция с игнорированием зависимостей была бы плохой идеей. Если вы запускаете приложение с несовместимыми файлами байт-кода, будет сообщено (только) о первом обнаруженном несоответствии. Так что, если у вас много несоответствий, вам нужно будет запустить приложение много раз, чтобы «обнаружить» их все. В самом деле, если есть какая-либо динамическая загрузка классов (например, с использованием Class.forName () ) в приложении или любой из его зависимостей, то некоторые из этих проблем могут не проявиться сразу.

Таким образом, игнорирование зависимостей во время компиляции приведет к замедлению разработки Java и менее надежным Java-приложениям.

если есть какая-либо динамическая загрузка классов (например, с использованием Class.forName () ) в приложении или любой из его зависимостей, то некоторые из этих проблем могут не проявиться сразу.

Таким образом, игнорирование зависимостей во время компиляции приведет к замедлению разработки Java и менее надежным Java-приложениям.

если есть какая-либо динамическая загрузка классов (например, с использованием Class.forName () ) в приложении или любой из его зависимостей, то некоторые из этих проблем могут не проявиться сразу.

Таким образом, игнорирование зависимостей во время компиляции приведет к замедлению разработки Java и менее надежным Java-приложениям.

2
ответ дан 2 December 2019 в 05:15
поделиться

Извлечь интерфейс

pkg.in.classpath.IFooBar

заставить FooBar реализовать IFooBar и

class Test { void foo(pkg.in.classpath.IFooBar foobar) {} }

Ваш класс Test будет скомпилирован. Просто подключите правильную реализацию, например FooBar , во время выполнения, используя фабрики и конфигурацию. Найдите несколько контейнеров IOC .

0
ответ дан 2 December 2019 в 05:15
поделиться

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

В грамматике Java нет ничего для использования pkg.not.in.classpath.FooBar , чтобы отличить это:

 package pkg.not.in.classpath;
 public class FooBar { }

от этого:

 package pkg.not.in.classpath;
 class FooBar { }

Итак, есть только ваше слово, что это законно чтобы использовать там FooBar.

Также существует двусмысленность между классами в области видимости пакета и внутренними классами в источнике:

class pkg {
    static class not {
        static class in {
            static class classpath {
                static class FooBar {}
            }
        }
    }
}

Внутренний класс также называется pkg.not.in.classpath.FooBar в источнике, но будет называться pkg $ not $ в $ classpath $ FooBar , а не pkg / not / in / classpath / FooBar в файле класса. Не существует способа, которым javac может сказать, что вы имеете в виду, не ища его в пути к классам.

0
ответ дан 2 December 2019 в 05:15
поделиться

Я создал два класса: Caller и Callee

public class Caller {
    public void doSomething( Callee callee) {
        callee.doSomething();
    }

    public void doSame(Callee callee) {
        callee.doSomething();
    }

    public void doSomethingElse(Callee callee) {
        callee.doSomethingElse();
    }
}

public class Callee {
    public void doSomething() {
    }
    public void doSomethingElse() {
    }
}

Я скомпилировал эти классы, а затем разобрал их с помощью javap -c Callee> Callee.bc и javap -c Caller> Caller.bc . Это привело к следующему:

Compiled from "Caller.java"
public class Caller extends java.lang.Object{
public Caller();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public void doSomething(Callee);
Code:
0: aload_1
1: invokevirtual #2; //Method Callee.doSomething:()V
4: return

public void doSame(Callee);
Code:
0: aload_1
1: invokevirtual #2; //Method Callee.doSomething:()V
4: return

public void doSomethingElse(Callee);
Code:
0: aload_1
1: invokevirtual #3; //Method Callee.doSomethingElse:()V
4: return

}

Compiled from "Callee.java"
public class Callee extends java.lang.Object{
public Callee();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public void doSomething();
Code:
0: return

public void doSomethingElse();
Code:
0: return

}

Компилятор сгенерировал сигнатуру метода и безопасный для типов invokevirtual вызов для вызовов метода «вызываемого» - он знает, какой класс и какой метод здесь вызывается. Если бы этот класс был недоступен, как бы компилятор сгенерировал подпись метода или ʻinvokevirtual '?

Существует JSR ( JSR 292 ) для добавления кода операции invokedynamic, который поддерживает динамический вызов, однако в настоящее время это не поддерживается JVM.

0
ответ дан 2 December 2019 в 05:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: