& lt; E расширяет Enum & lt; E & gt; в Java [дубликат]

Вам нужно установить значение upload_max_filesize и post_max_size в вашем php.ini:

; Maximum allowed size for uploaded files.
upload_max_filesize = 40M

; Must be greater than or equal to upload_max_filesize
post_max_size = 40M

. После изменения файлов (ов) php.ini вам необходимо перезапустить HTTP-сервер для использования новой конфигурации.

Если вы не можете изменить свой php.ini, вам не повезло. Вы не можете изменить эти значения во время выполнения; Загрузка файлов большего размера, чем значение, указанное в php.ini, будет сбой, так как время выполнения достигнет вашего вызова ini_set.

См. Описание основных директив php.ini .

133
задан CajunLuke 30 August 2012 в 20:07
поделиться

7 ответов

Это означает, что аргумент type для перечисления должен выводиться из перечисления, которое имеет один и тот же аргумент типа. Как это может произойти? Сделав аргумент типа новым типом. Поэтому, если у меня есть перечисление с именем StatusCode, оно будет эквивалентно:

public class StatusCode extends Enum<StatusCode>

Теперь, если вы проверите ограничения, у нас есть Enum<StatusCode> - так E=StatusCode. Давайте проверим: расширяет ли E Enum<StatusCode>? Да! Мы все в порядке.

Вы вполне можете спросить себя, в чем суть этого :) Ну, это означает, что API для Enum может ссылаться на себя - например, имея возможность сказать, что Enum<E> реализует Comparable<E>. Базовый класс способен выполнять сравнения (в случае перечислений), но он может убедиться, что он сравнивает только правильный тип перечислений друг с другом. (EDIT: ну, почти - см. Редактирование внизу.)

Я использовал что-то подобное в моем C # -порте ProtocolBuffers. Существуют «сообщения» (неизменяемые) и «строители» (изменяемые, используемые для создания сообщения), и они являются парами типов. В число задействованных интерфейсов входят:

public interface IBuilder<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

public interface IMessage<TMessage, TBuilder>
  where TMessage : IMessage<TMessage, TBuilder> 
  where TBuilder : IBuilder<TMessage, TBuilder>

Это означает, что из сообщения вы можете получить соответствующий строитель (например, взять копию сообщения и изменить некоторые биты), а из строителя вы можете получить соответствующий когда вы закончите его строительство. Это хорошая работа, которую пользователи API не нуждаются в этом, хотя это ужасно сложно, и потребовалось несколько итераций, чтобы добраться туда, где они есть.

EDIT: Обратите внимание, что это не останавливается вы создаете нечетные типы, которые используют аргумент типа, который сам по себе хорошо, но который не является одним и тем же типом. Цель состоит в том, чтобы приносить пользу в случае right , а не защищать вас от неправильного случая .

Так что если Enum не были обработаны " особенно в Java, вы могли бы (как отмечено в комментариях) создать следующие типы:

public class First extends Enum<First> {}
public class Second extends Enum<First> {}

Second будет реализовывать Comparable<First>, а не Comparable<Second> ... но First сам будет хорошо.

97
ответ дан Jon Skeet 25 August 2018 в 04:16
поделиться

Это можно проиллюстрировать простым примером и техникой, которая может быть использована для реализации цепных вызовов методов для подклассов. В примере ниже setName возвращается значение Node, поэтому цепочка City не будет работать:

class Node {
    String name;

    Node setName(String name) {
        this.name = name;
        return this;
    }
}

class City extends Node {
    int square;

    City setSquare(int square) {
        this.square = square;
        return this;
    }
}

public static void main(String[] args) {
    City city = new City()
        .setName("LA")
        .setSquare(100);    // won't compile, setName() returns Node
}

. Таким образом, мы могли бы ссылаться на подкласс в общем объявлении, City теперь возвращает правильный тип:

abstract class Node<SELF extends Node<SELF>>{
    String name;

    SELF setName(String name) {
        this.name = name;
        return self();
    }

    protected abstract SELF self();
}

class City extends Node<City> {
    int square;

    City setSquare(int square) {
        this.square = square;
        return self();
    }

    @Override
    protected City self() {
        return this;
    }

    public static void main(String[] args) {
       City city = new City()
            .setName("LA")
            .setSquare(100);                 // ok!
    }
}
3
ответ дан Andrey Chaschev 25 August 2018 в 04:16
поделиться

Если вы посмотрите на исходный код Enum, он имеет следующее:

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {

    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    } 
}

Прежде всего, что означает E extends Enum<E>? Это означает, что параметр типа является чем-то, что простирается от Enum и не параметризуется с необработанным типом (он сам параметризуется).

Это актуально, если у вас есть перечисление

public enum MyEnum {
    THING1,
    THING2;
}

, который, если я правильно знаю, переведен на

public final class MyEnum extends Enum<MyEnum> {
    public static final MyEnum THING1 = new MyEnum();
    public static final MyEnum THING2 = new MyEnum();
}

Таким образом, это означает, что MyEnum получает следующие методы:

public final int compareTo(MyEnum o) {
    Enum<?> other = (Enum<?>)o;
    Enum<MyEnum> self = this;
    if (self.getClass() != other.getClass() && // optimization
        self.getDeclaringClass() != other.getDeclaringClass())
        throw new ClassCastException();
    return self.ordinal - other.ordinal;
}

И что еще более важно,

    @SuppressWarnings("unchecked")
    public final Class<MyEnum> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<MyEnum>)clazz : (Class<MyEnum>)zuper;
    }

Это делает getDeclaringClass() отличным от соответствующего объекта Class<T>.

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

0
ответ дан Community 25 August 2018 в 04:16
поделиться

Вы не единственный, кто задается вопросом, что это значит; см. Хаотический Java-блог .

«Если класс расширяет этот класс, он должен передать параметр E. Оценки параметра E для класса, который расширяет этот класс с тем же параметром E».

2
ответ дан kpirkkal 25 August 2018 в 04:16
поделиться

Ниже приведен модифицированный вариант объяснения из книги Java Generics and Collections : у нас есть Enum объявленный

enum Season { WINTER, SPRING, SUMMER, FALL }

, который будет расширен до class

final class Season extends ...

, где ... должен быть как-то параметризованным базовым классом для Enums. Давайте выясним, что это должно быть. Ну, одним из требований для Season является то, что он должен реализовывать Comparable<Season>. Итак, нам понадобится

Season extends ... implements Comparable<Season>

. Что вы могли бы использовать для ..., который позволил бы этому работать? Учитывая, что он должен быть параметризацией Enum, единственным выбором является Enum<Season>, так что вы можете иметь:

Season extends Enum<Season>
Enum<Season> implements Comparable<Season>

Таким образом, Enum параметризуется в таких типах, как Season. Реферат из Season и вы получите, что параметр Enum - это любой тип, который удовлетворяет

 E extends Enum<E>

Морис Нафталин (соавтор, Java Generics and Collections)

25
ответ дан Maurice Naftalin 25 August 2018 в 04:16
поделиться

В случае Enum это бесполезно. Все будет работать одинаково, если оно было объявлено как

class Enum<E>
0
ответ дан newacct 25 August 2018 в 04:16
поделиться

Этот пост полностью разъяснил мне эту проблему «рекурсивных родовых типов». Я хотел бы добавить еще один случай, когда эта конкретная структура необходима.

Предположим, что у вас есть общие узлы в общем графике:

public abstract class Node<T extends Node<T>>
{
    public void addNeighbor(T);

    public void addNeighbors(Collection<? extends T> nodes);

    public Collection<T> getNeighbor();
}

Тогда вы можете иметь графики специализированных типов:

public class City extends Node<City>
{
    public void addNeighbor(City){...}

    public void addNeighbors(Collection<? extends City> nodes){...}

    public Collection<City> getNeighbor(){...}
}
2
ответ дан nozebacle 25 August 2018 в 04:16
поделиться
Другие вопросы по тегам:

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