Вам нужно будет сделать этот сервер. Если вы используете PHP, посмотрите на glob .
Например:
foreach (glob("path/to/css/*.css") as $css) {
echo "\n";
}
Отличие состоит в том, что Some<E extends Some>
означает две вещи:
E
является сырым типом. Вкратце, типы raw имеют всю общую информацию, удаляемую из класса, что, в свою очередь, может создать неожиданное поведение E
, может быть любым классом Some
! Наоборот, использование Some<E extends Some<E>>
означает:
E
напечатан E
должен быть тем же как класс, в котором он объявлен Необработанная часть - проблема, но большая импликация - это границы типов. Этот код демонстрирует разницу, поскольку классы «B» используют (или пытаются использовать) классы «A» как общий тип.
// The raw version
interface Some<E extends Some> {
E get();
}
class SomeA implements Some<SomeA> {
public SomeA get() {
return new SomeA();
}
}
// Compiles OK
class SomeB implements Some<SomeA> {
public SomeA get() {
return new SomeA();
}
}
// The typed version
interface SomeT<E extends SomeT<E>> {
E get();
}
class SomeTA implements Some<SomeTA> {
public SomeTA get() {
return new SomeTA();
}
}
// Compile error
class SomeTB implements SomeT<SomeA> {
public SomeA get() {
return new SomeTA();
}
}
Класс SomeB
компилирует в порядке - тип E привязан только к Some
, поэтому будет выполняться любой класс Some
, но класс SomeTB
выдает ошибку компиляции:
аргумент типа SomeTA не входит в число границы переменной типа E
blockquote>Тип
E
должен быть точно таким же, как содержащий класс.Это важно, если вы ожидаете параметров и возвращаемые типы должны быть такими же, как и сам класс, который обычно вы хотите использовать с типизированными классами.
Тип, ограниченный сырым типом, не является проблемой, поскольку он все еще является
Some
, но могут быть случаи, когда это имеет значение (я не могу думать об этом только сейчас).
Что касается оператора
каждый раз, когда я пытался удалить дополнительный - никаких новых ошибок / предупреждений не было.
blockquote>Это не должно быть дело. Он должен печатать предупреждение, потому что вы используете raw type
Some
, и в результате этого отсутствует безопасность типа, как показано в ответе на newacct .
Пример
Dog
/Cat
немного надуман и несколько испорчен. Вы предложили объявить классpublic class Dog extends Animal<Cat> { } // Note "Cat" !!!
. Но здесь параметр типа в основном означает: «Этот параметр (
Cat
) является типом, который объекты этого класса (Dog
) могут быть по сравнению с ". Таким образом, вы явно заявляете , чтоDog
должен быть сопоставим сCat
. В конце концов, даже разработчикам сложного языка и умных компиляторов приходится программировать код, который имеет смысл.
Действительно, не так много случаев, когда эти самореферентные общие типы необходимо. Один из этих примеров нарисован в этой записи в FAQ: Он объявляет структуру узлов (то есть дерево), где параметр типа может использоваться для отграничения определения структуры дерева / g5] из фактического типа узлов:
public class RecurringTest { public static void main(String[] args) { SpecialNode sa = new SpecialNode(null); SpecialNode sb = new SpecialNode(sa); SpecialNode s = sa.getChildren().get(0); } } abstract class Node<N extends Node<N>> { private final List<N> children = new ArrayList<N>(); private final N parent; protected Node(N parent) { this.parent = parent; if (parent != null) { this.parent.getChildren().add(getThis()); } } abstract N getThis(); public N getParent() { return parent; } public List<N> getChildren() { return children; } } class SpecialNode extends Node<SpecialNode> { public SpecialNode(SpecialNode parent) { super(parent); } SpecialNode getThis() { return this; } }
Но из моего личного опыта я могу сказать, что, когда вы думаете, что вам нужно создать такую типа, вы должны тщательно подумать о преимуществах и недостатках. Последнее в основном относится к уменьшенной читаемости. Если у вас есть выбор между такими методами, как
Node<? extends Node<? extends N, ? extends T>, T> doSomething( Node<? super Node<? extends N>, ? extends T> p, Node<? extends Node<? super N>, ? super T> c) { ... }
, которые являются безопасными по типу, или такими методами, как
Node doSomething(Node parent, Node child) { ... }
, которые не являются безопасными типа (из-за необработанных типов или просто потому, что типы не были обобщены), тогда я предпочел бы последний. Код читается людьми.
Похоже, что в настоящее время Some<E extends Some<E>>
не имеет приключений по сравнению с Some<E extends Some>
Согласно статье , написанной в сочетании с Java Champions и создателем часто задаваемых вопросов Java Generics :
Статья допускает некоторые возможности / предположения:
Я думаю, что Enum было бы достаточно. Однако, как указал мне Филипп Вадлер, поскольку Enum - это общий класс, мы должны использовать его только в сочетании с типом. В будущем Java может стать более строгим, а необработанные типы могут стать незаконными. Поэтому у нас есть выбор записи либо
blockquote>Enum<E extends Enum<E>>
, либоEnum<E extends Enum<?>>
, из которых первый вариант является более точным. Несмотря на то, что компилятор в настоящее время не показывает мне разницы, я могу увидеть предупреждения в будущем, поэтому я следую этой идиоме в своем классе
Очень мало ситуаций, когда необходима привязка как class Some<E extends Some<E>>
. Большую часть времени люди пишут это, в действительности код не используется в коде, а class Some<E>
будет работать так же хорошо.
Однако существуют некоторые ситуации, в которых оценка в class Some<E extends Some<E>>
фактически используется. Например:
abstract class Some<E extends Some<E>> {
abstract E foo();
Some<E> bar() {
return foo();
}
}
Что касается вашего вопроса - как насчет class Some<E extends Some>
? Ну, первая наиболее вопиющая проблема заключается в том, что вы используете сырой тип. Необработанные типы никогда не должны использоваться в новом коде. Но вы не уверены.
Необработанный тип с указанным выше классом (class Some<E extends Some>
) компилирует с предупреждением (которое вы можете игнорировать на свой страх и риск). Тем не менее, тип raw означает, что с ним можно делать небезопасные вещи.
Требуется некоторое усилие, чтобы продемонстрировать, что это небезопасно. Вот один из них:
abstract class Some<E extends Some> {
abstract E foo();
Some<E> bar() {
return foo();
}
}
class SomeFoo extends Some<SomeFoo> {
SomeFoo foo() { return this; }
}
class SomeBar extends Some<SomeFoo> {
SomeFoo foo() { return new SomeFoo(); }
}
class SomeBaz extends Some<SomeBar> {
SomeBar foo() { return new SomeBar(); }
}
// then in some method:
Some<SomeBar> a = new SomeBaz();
Some<SomeBar> b = a.bar();
SomeBar c = b.foo();
Код компилируется с предупреждениями, но без ошибок, и выдает ClassCastException
во время выполнения.