Более общая функция для сортировки элементов с помощью jQuery:
$.fn.sortChildren = function (sortingFunction: any) {
return this.each(function () {
const children = $(this).children().get();
children.sort(sortingFunction);
$(this).append(children);
});
};
Использование:
$(".clist").sortChildren((a, b) => a.dataset.sid > b.dataset.sid ? 1 : -1);
Предполагая, что никакой SecurityManager
не мешает вам сделать это, вы можете использовать setAccessible
, чтобы обойти private
и сбросить модификатор, чтобы избавиться от final
, и фактически изменить private static final
поле.
Вот пример:
import java.lang.reflect.*;
public class EverythingIsTrue {
static void setFinalStatic(Field field, Object newValue) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
public static void main(String args[]) throws Exception {
setFinalStatic(Boolean.class.getField("FALSE"), true);
System.out.format("Everything is %s", false); // "Everything is true"
}
}
Предполагая, что не возникнет SecurityException
, приведенный выше код выводит "Все верно"
.
На самом деле здесь сделано следующее:
boolean
true
и false
в main
автобоксируются в ссылочные типы Boolean
"констант" Boolean.TRUE
и Boolean. FALSE
public static final Boolean.FALSE
для ссылки на Boolean
, на который ссылается Boolean.TRUE
false
автобоксируется в Boolean. FALSE
, он ссылается на тот же Boolean
, на который ссылается Boolean.TRUE
"false"
, теперь стало "true"
static final File. separatorChar
для модульного тестированияInteger
, изменить String
и т.д.Всякий раз, когда вы делаете что-то подобное, следует быть предельно осторожным. Это может не сработать, потому что может присутствовать SecurityManager
, но даже если это не так, в зависимости от модели использования, это может сработать или не сработать.
JLS 17.5.3 Последующая модификация конечных полей
В некоторых случаях, например при десериализации, системе потребуется изменить
конечные
поля объекта после создания.final
поля могут быть изменены с помощью отражения и других средств, зависящих от реализации. Единственная модель, в которой это имеет разумную семантику - это модель, в которой объект строится, а затем обновляютсяfinal
поля объекта. Объект не должен быть виден другим потокам, а поляfinal
не должны быть прочитаны, пока все обновления полейfinal
объекта не будут завершены. Замораживаниеfinal
поля происходит как в конце конструктора, в котором устанавливаетсяfinal
поле, так и сразу после каждого измененияfinal
поля через отражение или другой специальный механизм.Даже в этом случае возникает ряд сложностей. Если поле
final
инициализируется константой времени компиляции в объявлении поля, то изменения поляfinal
могут не наблюдаться, поскольку использование этого поляfinal
заменяется во время компиляции константой времени компиляции.Другая проблема заключается в том, что спецификация допускает агрессивную оптимизацию полей
final
. Внутри потока допустимо переупорядочивать чтенияfinal
поля с теми модификациями final поля, которые не происходят в конструкторе.
private static final boolean
, поскольку он инлайнится как константа времени компиляции и, таким образом, "новое" значение может быть не наблюдаемымПо сути,
field.getModifiers() & ~Modifier.FINAL
выключает бит, соответствующий Modifier.FINAL
из field.getModifiers()
. &
- это побитовое и, а ~
- побитовое дополнение.
Все еще не можете решить эту задачу, впали в депрессию, как это сделал я? Ваш код выглядит вот так?
public class A {
private final String myVar = "Some Value";
}
Читая комментарии к этому ответу, особенно комментарии @Pshemo, я вспомнил, что Constant Expressions обрабатываются по-другому, поэтому будет невозможно изменить их. Следовательно, вам нужно будет изменить свой код так:
public class A {
private final String myVar;
private A() {
myVar = "Some Value";
}
}
если вы не являетесь владельцем класса... Я вас понимаю!
Подробнее о причинах такого поведения читайте здесь?
Даже несмотря на то, чтобы быть final
поле может быть изменено за пределами статического инициализатора, и (по крайней мере, JVM HotSpot) выполнит превосходный байт-код.
проблема состоит в том, что компилятор Java не позволяет это, но это может быть легко обойдено с помощью objectweb.asm
. Вот совершенно допустимый classfile, который передает проверку байт-кода и успешно загруженный и инициализированный под JVM HotSpot OpenJDK12:
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Cl", null, "java/lang/Object", null);
{
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "fld", "I", null, null);
fv.visitEnd();
}
{
// public void setFinalField1() { //... }
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "setFinalField1", "()V", null, null);
mv.visitMaxs(2, 1);
mv.visitInsn(Opcodes.ICONST_5);
mv.visitFieldInsn(Opcodes.PUTSTATIC, "Cl", "fld", "I");
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
{
// public void setFinalField2() { //... }
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "setFinalField2", "()V", null, null);
mv.visitMaxs(2, 1);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitFieldInsn(Opcodes.PUTSTATIC, "Cl", "fld", "I");
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
cw.visitEnd();
В Java, класс выглядит примерно говорящим следующим образом:
public class Cl{
private static final int fld;
public static void setFinalField1(){
fld = 5;
}
public static void setFinalField2(){
fld = 2;
}
}
, который не может быть скомпилирован с javac
, но может быть загружен и выполнен JVM.
JVM HotSpot имеет специальный режим таких классов в том смысле, что он предотвращает такие "константы" от участия в сворачивании констант. Эта проверка сделана на байт-код, переписав фазу инициализации класса :
// Check if any final field of the class given as parameter is modified
// outside of initializer methods of the class. Fields that are modified
// are marked with a flag. For marked fields, the compilers do not perform
// constant folding (as the field can be changed after initialization).
//
// The check is performed after verification and only if verification has
// succeeded. Therefore, the class is guaranteed to be well-formed.
InstanceKlass* klass = method->method_holder();
u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1);
constantPoolHandle cp(method->constants());
Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index));
if (klass->name() == ref_class_name) {
Symbol* field_name = cp->name_ref_at(bc_index);
Symbol* field_sig = cp->signature_ref_at(bc_index);
fieldDescriptor fd;
if (klass->find_field(field_name, field_sig, &fd) != NULL) {
if (fd.access_flags().is_final()) {
if (fd.access_flags().is_static()) {
if (!method->is_static_initializer()) {
fd.set_has_initialized_final_update(true);
}
} else {
if (!method->is_object_initializer()) {
fd.set_has_initialized_final_update(true);
}
}
}
}
}
}
единственное ограничение, которое проверяет JVM HotSpot, - то, что final
поле не должно быть изменено за пределами класса, в котором final
объявляется поле.
Если значение, присвоенное статическому конечному логическому полю , известно во время компиляции, это константа . Поля примитивных или
Тип String
может быть константами времени компиляции. Константа будет встроена в любой код, который ссылается на это поле. Поскольку поле фактически не читается во время выполнения, его изменение не повлияет.
В спецификации языка Java сказано следующее:
Если поле является постоянной переменной (§4.12.4), затем удалив ключевое слово final или изменение его значения не будет нарушить совместимость с уже существующими двоичные файлы, заставляя их не запускаться, но они не увидят нового значения для использования поля, если они перекомпилированы. Это верно, даже если само использование не является временем компиляции постоянное выражение (§15.28)
Вот пример:
class Flag {
static final boolean FLAG = true;
}
class Checker {
public static void main(String... argv) {
System.out.println(Flag.FLAG);
}
}
Если вы декомпилируете Checker
, вы увидите, что вместо ссылки на Flag.FLAG
, код просто помещает значение 1 ( истина
) в стек (инструкция №3).
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_1
4: invokevirtual #3; //Method java/io/PrintStream.println:(Z)V
7: return
Весь смысл конечного
поля в том, что оно не может быть переназначено после установки. JVM использует эту гарантию для поддержания согласованности в различных местах (например, внутренние классы ссылаются на внешние переменные). Так что нет. Возможность сделать это сломала бы JVM!
Решение состоит в том, чтобы не объявлять ее конечной
в первую очередь.