Такое поведение неудивительно, если принять во внимание следующее:
Роль (2) была широко освещена в этой теме. (1), вероятно, является фактором, вызывающим удивление, поскольку это поведение не является «интуитивным» при поступлении с других языков.
(1) описано в учебнике Python по классам . При попытке присвоить значение атрибуту класса только для чтения:
... все переменные, найденные вне самой внутренней области, доступны только для чтения ( попытка написать такую переменная просто создаст новую локальную переменную в самой внутренней области, оставив неизмененную идентичную внешнюю переменную неизменной ).
blockquote>Оглянитесь на исходный пример и рассмотрите приведенные выше пункты:
def foo(a=[]): a.append(5) return a
Здесь
foo
- объект, аa
- атрибутfoo
(доступен вfoo.func_defs[0]
). Посколькуa
является списком,a
является изменяемым и, таким образом, является атрибутом чтения-записиfoo
. Он инициализируется пустым списком, указанным сигнатурой при создании экземпляра функции, и доступен для чтения и записи до тех пор, пока существует функциональный объект.Вызов
foo
без переопределения значения по умолчанию использует значение по умолчанию отfoo.func_defs
. В этом случаеfoo.func_defs[0]
используется дляa
в пределах области кода объекта объекта. Изменения вa
меняютfoo.func_defs[0]
, который является частью объектаfoo
и сохраняется между выполнением кода вfoo
.Теперь сравните это с примером из документации по , эмулируя поведение аргументов по умолчанию других языков , так что значения по умолчанию для функции используются каждый раз, когда функция выполняется:
def foo(a, L=None): if L is None: L = [] L.append(a) return L
Принимая во внимание (1) и (2) , можно понять, почему это выполняет желаемое поведение:
- Когда объект функции
foo
создается,foo.func_defs[0]
установлен наNone
, неизменяемый объект.- Когда функция выполняется с настройками по умолчанию (без функции, заданной для
L
в вызове функции),foo.func_defs[0]
(None
) доступен в локальной области какL
.- После
L = []
присваивание не может преуспеть вfoo.func_defs[0]
, поскольку этот атрибут доступен только для чтения.- Per (1), новая локальная переменная с именем
L
создается в локальной области и используется для остальной части вызова функции.foo.func_defs[0]
, таким образом, остается неизменным для будущих вызововfoo
.
Это означает, что параметр типа должен поддерживать сравнение с другими экземплярами своего собственного типа через интерфейс Comparable.
Пример такого класса приведен в учебнике Oracle Object Ordering . Обратите внимание на аналогичную модель T extends Comparable<T>
в выдержке ниже:
public class Name implements Comparable<Name> {
...
public int compareTo(Name n) { ... }
}
Java. Значение <T extends Comparable<T>>
?
a) Comparable <T>
- общий интерфейс (помните, что это «интерфейс», то есть не «класс»)
b ) extends
означает наследование от класса или интерфейса.
С вышеуказанной точки # a это интерфейс .. (Помните, что это наследование от «интерфейса», то есть не от «класса»)
c) От выше упомянутых обеих точек #a & amp; #b,
здесь «один интерфейс» расширяет «другой интерфейс».
Для этого класса должен быть определенный интерфейс. Например, здесь есть
interface MinMax<T extends Comparable<T>> {
T min();
T max();
}
d) теперь ваш класс, т. е. public class RClass {}
СЛЕДУЕТ
1 # ЭТО «реализовать» этот «общий интерфейс» Comparable<T>
.. !!!
ex: public class RClass<T> implements Comparable<T>
2 # ИЛИ создать интерфейс и перейти к этому «универсальному интерфейсу» Comparable<T>
ex:
interface MinMax<T extends Comparable<T>> {
T min();
T max();
}
class RClass<T extends Comparable<T>> implements MinMax<T> {
.....
.....
}
Здесь обратите особое внимание на то, как параметр типа T объявляется RClass, а затем передается в MinMax
. Поскольку для MinMax
требуется тип, реализующий Comparable
, класс реализации (RClass в этом случае) должен указывать ту же самую границу. Кроме того, после того, как эта оценка была установлена, нет необходимости указывать ее снова в предложении tools.
public **class** RClass<T extends Comparable<T>>
. Это класс, а не интерфейс. Поэтому, пожалуйста, прокомментируйте, что будет означать, если это класс.
– Sathish Kumar k k
9 September 2015 в 13:22
Проще говоря, общий тип T должен быть сопоставим для сравнения. иначе вы не сможете сделать T.compareTo. В пункте 28 «Эффективная Java» предлагается: "always use Comparable<? super T> in preference to Comparable<T>. <T extends Comparable<? super T>>"
Это означает, что вы можете создать экземпляр RClass
с типом, который буквально расширяет Comparable<T>
. Таким образом,
RClass<Integer> a;
приемлемо, так как Integer
расширяет Comparable<Integer>
, а
RClass<Object> b;
не является, так как Object
не является классом, который расширяется, сравнимый по все.
Да, и имейте в виду, что объекты классов, полученные из объектов Comparable
ARE Comparable
. Наследование - это отношение is-a
.
Где-то в этом классе программисту нужно написать что-то вроде
if(t.compareTo(othert) < 0) {
...
}
. Для этого для типа T должен быть метод compareTo, который сравнивает его с другим объектом типа T. Расширение Сопоставимое гарантирует существование такого метода, среди прочего.
==> guhanvj, <T extends Comparable<T>>
означает, что <T>
имеет верхнюю границу объектов Comparable<T>
. Таким образом, <T>
может иметь типы классов Byte, Character, Double, Float, Long, Short, String и Integer, которые все реализуют интерфейс Comparable<T>
для естественного упорядочения.
<T implements Comparable<T>>
не является законным. – flow2k 28 June 2018 в 16:27