Thay đổi private static cuối cùng lĩnh vực bằng cách sử dụng Java phản ánh


0 Phiếu
Đã hỏi 19/3/2016 bởi Jbebhan (310 điểm)
Tôi có một class với một private static final lĩnh vực đó, thật không may, tôi cần phải thay đổi tại thời gian chạy. Tôi sử dụng phản ánh nhận được lỗi này: java.lang.IllegalAccessException: Can not set static final boolean field có cách nào để thay đổi giá trị?
Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK");
hack.setAccessible(true);
hack.set(null, true);

3 Câu trả lời

0 Phiếu
Đã trả lời 25/3/2016 bởi The_6400 (1,470 điểm)
 
Câu trả lời hay nhất
Giả sử SecurityManager không ngăn cản bạn làm điều này, bạn có thể sử dụng setAccessible để có được xung quanh private và đặt lại công cụ sửa đổi để thoát khỏi của final, và thực sự sửa đổi một lĩnh vực private static final. Dưới đây là một ví dụ: giả sử
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"
   }
}
không SecurityException được ném, trên code in "Everything is true". Những gì thực sự được thực hiện ở đây là như sau:
  • nguyên thủy boolean giá trị truefalse trong main là autoboxed để tham khảo type Boolean "hằng" Boolean.TRUEBoolean.FALSE
  • phản chiếu được sử dụng để thay đổi public static final Boolean.FALSE để tham khảo Boolean được gọi bằng Boolean.TRUE
  • kết quả là, sau đó bất cứ khi nào một false là autoboxed để Boolean.FALSE, nó đề cập đến Boolean tương tự như một được gọi đến bởi Boolean.TRUE
  • tất cả mọi thứ đã là "false" bây giờ là "true"

câu hỏi liên quan


hãy cẩn thận

cực kỳ chăm sóc cần được thực hiện bất cứ khi nào bạn làm điều gì đó như thế này. Nó có thể không làm việc vì một SecurityManager có thể có mặt, nhưng ngay cả khi nó không, tùy thuộc vào cách sử dụng mẫu, nó có thể hoặc không thể làm việc.
JLS 17.5.3 Subsequent sửa đổi cuối cùng lĩnh vực trong một số trường hợp, chẳng hạn như deserialization, system sẽ cần phải thay đổi các lĩnh vực final một object sau khi xây dựng. final lĩnh vực có thể được thay đổi thông qua sự phản ánh và phương tiện khác phụ thuộc vào thực hiện. Các mô hình duy nhất, trong đó có hợp lý ngữ nghĩa là một trong đó một object được xây dựng và sau đó các lĩnh vực final object được Cập Nhật. object không phải được thực hiện có thể nhìn thấy chủ đề khác, cũng không nên các lĩnh vực final được đọc, cho đến khi tất cả các bản Cập Nhật cho các lĩnh vực final object được hoàn thành. Đóng băng trong một lĩnh vực final xảy ra cả ở phần cuối của constructor trong lĩnh vực final được thiết lập, và ngay lập tức sau mỗi thay đổi của một lĩnh vực final thông qua phản ánh hoặc cơ chế đặc biệt. Thậm chí sau đó, có nhiều biến chứng. Nếu một lĩnh vực final được khởi tạo với một hằng số biên dịch trong lĩnh vực tuyên bố, thay đổi để final lĩnh vực có thể không được quan sát thấy, kể từ khi sử dụng các lĩnh vực final đó được thay thế tại compile thời gian với hằng số thời gian biên dịch. Một vấn đề khác là đặc điểm kỹ thuật cho phép optimization tích cực của các lĩnh vực final. Trong một chủ đề, nó được cho phép để sắp xếp lại lần đọc một trường final với những sửa đổi của một trường cuối cùng mà không diễn ra tại các nhà xây dựng.

xem cũng

  • JLS 15.28 liên tục biểu hiện
    • nó không chắc rằng kỹ thuật này hoạt động với một private static final boolean nguyên thủy, bởi vì nó inlineable như là một hằng số biên dịch và do đó value "mới" có thể không là quan sát

phụ lục: ngày

bitwise thao tác Về cơ bản,
field.getModifiers() & ~Modifier.FINAL
tắt chút tương ứng với Modifier.FINAL từ field.getModifiers(). & là bitwise- và, và ~ là sự bổ sung bitwise.

xem thêm

0 Phiếu
Đã trả lời 20/3/2016 bởi storag (1,680 điểm)
The whole point of a final field is that it cannot be reassigned once set. The JVM uses this guarentee to maintain consistency in various places (eg inner classes referencing outer variables). So no. Being able to do so would break the JVM! The solution is not to declare it final in the first place.
Đã bình luận 20/3/2016 bởi Actual (260 điểm)
Như vậy là một ý tưởng tồi. Tôi sẽ cố gắng để có được source và recompile (hoặc thậm chí ngược/recompile) để thay thế.
Đã bình luận 21/3/2016 bởi Zbz_6877_th (200 điểm)
System.out là một public static cuối cùng lĩnh vực, nhưng nó có thể được thay đổi quá.
Đã bình luận 22/3/2016 bởi Jur1891Empty (130 điểm)
'System.out/in/err' là "đặc biệt" mô hình bộ nhớ Java đã làm cho đề cập đến đặc biệt của họ. Chúng không phải là ví dụ mà cần được theo sau.
0 Phiếu
Đã trả lời 25/3/2016 bởi Kreps (240 điểm)
Nếu value được gán cho một lĩnh vực static final boolean được biết đến tại thời điểm biên dịch, nó là một hằng số . value của nó sẽ được inlined trong bất kỳ code tham chiếu giá trị. Kể từ khi nó không thực sự đọc lúc chạy, thay đổi nó sau đó sẽ không có hiệu lực. Java ngôn ngữ đặc tả nói điều này:
nếu một lĩnh vực là một biến liên tục (§4.12.4), sau đó xóa cuối cùng từ khóa hoặc thay đổi value của nó sẽ không phá vỡ tính tương thích với những chương trình sẵn bởi khiến họ không chạy, nhưng họ sẽ không nhìn thấy bất kỳ giá trị mới cho việc sử dụng của trường trừ khi họ được biên . đây là true ngay cả khi việc sử dụng chính nó không phải là một thời gian biên dịch liên tục expression
(§15.28) ở đây là một ví dụ:
class Flag {
  static final boolean FLAG = true;
}
class Checker {
  public static void main(String... argv) {
    System.out.println(Flag.FLAG);
  }
}
nếu bạn dịch ngược Checker, bạn sẽ thấy rằng thay vì tham khảo Flag.FLAG, code chỉ đơn giản là đẩy một value 1 (true) lên stack (hướng dẫn #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
Đã bình luận 26/3/2016 bởi To_8366 (700 điểm)
Vâng tôi ws điểm để tìm kiếm một hack trong các giữa để có ứng dụng của tôi làm việc cho đến khi lib chịu trách nhiệm thực hiện thay đổi phát hành tiếp theo vì vậy tôi không cần phải hack nữa...

ToughDev Q&A là gì?

Trang web hỏi đáp cho các bạn đam mê lập trình, phát triển phần mềm và các vấn đề kỹ thuật khác. Với sự giúp đỡ của bạn, chúng tôi hy vọng sẽ xây dựng thành công một thư viện đầy đủ các câu hỏi và trả lời về tất cả các vấn đề có liên quan đến lập trình!







...