<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## [接口和類型](https://lingcoder.gitee.io/onjava8/#/book/19-Type-Information?id=%e6%8e%a5%e5%8f%a3%e5%92%8c%e7%b1%bb%e5%9e%8b) `interface`關鍵字的一個重要目標就是允許程序員隔離組件,進而降低耦合度。使用接口可以實現這一目標,但是通過類型信息,這種耦合性還是會傳播出去——接口并不是對解耦的一種無懈可擊的保障。比如我們先寫一個接口: ~~~ // typeinfo/interfacea/A.java package typeinfo.interfacea; public interface A { void f(); } ~~~ 然后實現這個接口,你可以看到其代碼是怎么從實際類型開始順藤摸瓜的: ~~~ // typeinfo/InterfaceViolation.java // Sneaking around an interface import typeinfo.interfacea.*; class B implements A { public void f() { } public void g() { } } public class InterfaceViolation { public static void main(String[] args) { A a = new B(); a.f(); // a.g(); // Compile error System.out.println(a.getClass().getName()); if (a instanceof B) { B b = (B) a; b.g(); } } } ~~~ 輸出結果: ~~~ B ~~~ 通過使用 RTTI,我們發現`a`是用`B`實現的。通過將其轉型為`B`,我們可以調用不在`A`中的方法。 這樣的操作完全是合情合理的,但是你也許并不想讓客戶端開發者這么做,因為這給了他們一個機會,使得他們的代碼與你的代碼的耦合度超過了你的預期。也就是說,你可能認為`interface`關鍵字正在保護你,但其實并沒有。另外,在本例中使用`B`來實現`A`這種情況是有公開案例可查的\[^3\]。 一種解決方案是直接聲明,如果開發者決定使用實際的類而不是接口,他們需要自己對自己負責。這在很多情況下都是可行的,但“可能”還不夠,你或許希望能有一些更嚴格的控制方式。 最簡單的方式是讓實現類只具有包訪問權限,這樣在包外部的客戶端就看不到它了: ~~~ // typeinfo/packageaccess/HiddenC.java package typeinfo.packageaccess; import typeinfo.interfacea.*; class C implements A { @Override public void f() { System.out.println("public C.f()"); } public void g() { System.out.println("public C.g()"); } void u() { System.out.println("package C.u()"); } protected void v() { System.out.println("protected C.v()"); } private void w() { System.out.println("private C.w()"); } } public class HiddenC { public static A makeA() { return new C(); } } ~~~ 在這個包中唯一`public`的部分就是`HiddenC`,在被調用時將產生`A`接口類型的對象。這里有趣之處在于:即使你從`makeA()`返回的是`C`類型,你在包的外部仍舊不能使用`A`之外的任何方法,因為你不能在包的外部命名`C`。 現在如果你試著將其向下轉型為`C`,則將被禁止,因為在包的外部沒有任何`C`類型可用: ~~~ // typeinfo/HiddenImplementation.java // Sneaking around package hiding import typeinfo.interfacea.*; import typeinfo.packageaccess.*; import java.lang.reflect.*; public class HiddenImplementation { public static void main(String[] args) throws Exception { A a = HiddenC.makeA(); a.f(); System.out.println(a.getClass().getName()); // Compile error: cannot find symbol 'C': /* if(a instanceof C) { C c = (C)a; c.g(); } */ // Oops! Reflection still allows us to call g(): callHiddenMethod(a, "g"); // And even less accessible methods! callHiddenMethod(a, "u"); callHiddenMethod(a, "v"); callHiddenMethod(a, "w"); } static void callHiddenMethod(Object a, String methodName) throws Exception { Method g = a.getClass().getDeclaredMethod(methodName); g.setAccessible(true); g.invoke(a); } } ~~~ 輸出結果: ~~~ public C.f() typeinfo.packageaccess.C public C.g() package C.u() protected C.v() private C.w() ~~~ 正如你所看到的,通過使用反射,仍然可以調用所有方法,甚至是`private`方法!如果知道方法名,你就可以在其`Method`對象上調用`setAccessible(true)`,就像在`callHiddenMethod()`中看到的那樣。 你可能覺得,可以通過只發布編譯后的代碼來阻止這種情況,但其實這并不能解決問題。因為只需要運行`javap`(一個隨 JDK 發布的反編譯器)即可突破這一限制。下面是一個使用`javap`的命令行: ~~~ javap -private C ~~~ `-private`標志表示所有的成員都應該顯示,甚至包括私有成員。下面是輸出: ~~~ class typeinfo.packageaccess.C extends java.lang.Object implements typeinfo.interfacea.A { typeinfo.packageaccess.C(); public void f(); public void g(); void u(); protected void v(); private void w(); } ~~~ 因此,任何人都可以獲取你最私有的方法的名字和簽名,然后調用它們。 那如果把接口實現為一個私有內部類,又會怎么樣呢?下面展示了這種情況: ~~~ // typeinfo/InnerImplementation.java // Private inner classes can't hide from reflection import typeinfo.interfacea.*; class InnerA { private static class C implements A { public void f() { System.out.println("public C.f()"); } public void g() { System.out.println("public C.g()"); } void u() { System.out.println("package C.u()"); } protected void v() { System.out.println("protected C.v()"); } private void w() { System.out.println("private C.w()"); } } public static A makeA() { return new C(); } } public class InnerImplementation { public static void main(String[] args) throws Exception { A a = InnerA.makeA(); a.f(); System.out.println(a.getClass().getName()); // Reflection still gets into the private class: HiddenImplementation.callHiddenMethod(a, "g"); HiddenImplementation.callHiddenMethod(a, "u"); HiddenImplementation.callHiddenMethod(a, "v"); HiddenImplementation.callHiddenMethod(a, "w"); } } ~~~ 輸出結果: ~~~ public C.f() InnerA$C public C.g() package C.u() protected C.v() private C.w() ~~~ 這里對反射仍然沒有任何東西可以隱藏。那么如果是匿名類呢? ~~~ // typeinfo/AnonymousImplementation.java // Anonymous inner classes can't hide from reflection import typeinfo.interfacea.*; class AnonymousA { public static A makeA() { return new A() { public void f() { System.out.println("public C.f()"); } public void g() { System.out.println("public C.g()"); } void u() { System.out.println("package C.u()"); } protected void v() { System.out.println("protected C.v()"); } private void w() { System.out.println("private C.w()"); } }; } } public class AnonymousImplementation { public static void main(String[] args) throws Exception { A a = AnonymousA.makeA(); a.f(); System.out.println(a.getClass().getName()); // Reflection still gets into the anonymous class: HiddenImplementation.callHiddenMethod(a, "g"); HiddenImplementation.callHiddenMethod(a, "u"); HiddenImplementation.callHiddenMethod(a, "v"); HiddenImplementation.callHiddenMethod(a, "w"); } } ~~~ 輸出結果: ~~~ public C.f() AnonymousA$1 public C.g() package C.u() protected C.v() private C.w() ~~~ 看起來任何方式都沒法阻止反射調用那些非公共訪問權限的方法。對于字段來說也是這樣,即便是`private`字段: ~~~ // typeinfo/ModifyingPrivateFields.java import java.lang.reflect.*; class WithPrivateFinalField { private int i = 1; private final String s = "I'm totally safe"; private String s2 = "Am I safe?"; @Override public String toString() { return "i = " + i + ", " + s + ", " + s2; } } public class ModifyingPrivateFields { public static void main(String[] args) throws Exception { WithPrivateFinalField pf = new WithPrivateFinalField(); System.out.println(pf); Field f = pf.getClass().getDeclaredField("i"); f.setAccessible(true); System.out.println( "f.getInt(pf): " + f.getInt(pf)); f.setInt(pf, 47); System.out.println(pf); f = pf.getClass().getDeclaredField("s"); f.setAccessible(true); System.out.println("f.get(pf): " + f.get(pf)); f.set(pf, "No, you're not!"); System.out.println(pf); f = pf.getClass().getDeclaredField("s2"); f.setAccessible(true); System.out.println("f.get(pf): " + f.get(pf)); f.set(pf, "No, you're not!"); System.out.println(pf); } } ~~~ 輸出結果: ~~~ i = 1, I'm totally safe, Am I safe? f.getInt(pf): 1 i = 47, I'm totally safe, Am I safe? f.get(pf): I'm totally safe i = 47, I'm totally safe, Am I safe? f.get(pf): Am I safe? i = 47, I'm totally safe, No, you're not! ~~~ 但實際上`final`字段在被修改時是安全的。運行時系統會在不拋出異常的情況下接受任何修改的嘗試,但是實際上不會發生任何修改。 通常,所有這些違反訪問權限的操作并不是什么十惡不赦的。如果有人使用這樣的技術去調用標志為`private`或包訪問權限的方法(很明顯這些訪問權限表示這些人不應該調用它們),那么對他們來說,如果你修改了這些方法的某些地方,他們不應該抱怨。另一方面,總是在類中留下后門,也許會幫助你解決某些特定類型的問題(這些問題往往除此之外,別無它法)。總之,不可否認,反射給我們帶來了很多好處。 程序員往往對編程語言提供的訪問控制過于自信,甚至認為 Java 在安全性上比其它提供了(明顯)更寬松的訪問控制的語言要優越\[^4\]。然而,正如你所看到的,事實并不是這樣。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看