sqlite字段是否存在_学习廖雪峰的JAVA教程---反射(访问字段)
對任意的一個Object實例,只要我們獲取了它的Class,就可以獲取它的一切信息。
我們先看看如何通過Class實例獲取字段信息。Class類提供了以下幾個方法來獲取字段:
- Field getField(name):根據字段名獲取某個public的field(包括父類)
- Field getDeclaredField(name):根據字段名獲取當前類的某個field(不包括父類)
- Field[] getFields():獲取所有public的field(包括父類)
- Field[] getDeclaredFields():獲取當前類的所有field(不包括父類)
我們來看一下示例代碼:
// reflectionpublic class Main { public static void main(String[] args) throws Exception { Class stdClass = Student.class; // 獲取public字段"score": System.out.println(stdClass.getField("score")); // 獲取繼承的public字段"name": System.out.println(stdClass.getField("name")); // 獲取private字段"grade": System.out.println(stdClass.getDeclaredField("grade")); }}class Student extends Person { public int score; private int grade;}class Person { public String name;}上述代碼首先獲取Student的Class實例,然后,分別獲取public字段、繼承的public字段以及private字段,打印出的Field類似:
public int Student.scorepublic java.lang.String Person.nameprivate int Student.grade一個Field對象包含了一個字段的所有信息:
- getName():返回字段名稱,例如,"name";
- getType():返回字段類型,也是一個Class實例,例如,String.class;
- getModifiers():返回字段的修飾符,它是一個int,不同的bit表示不同的含義。
以String類的value字段為例,它的定義是:
public final class String { private final byte[] value;}我們用反射獲取該字段的信息,代碼如下:
Field f = String.class.getDeclaredField("value"); //返回一個Field對象(包含字段名稱、字段類型、字段修飾符)f.getName(); // "value"f.getType(); // class [B 表示byte[]類型int m = f.getModifiers();Modifier.isFinal(m); // trueModifier.isPublic(m); // falseModifier.isProtected(m); // falseModifier.isPrivate(m); // trueModifier.isStatic(m); // false獲取字段值
利用反射拿到字段的一個Field實例只是第一步,我們還可以拿到一個實例對應的該字段的值。
例如,對于一個Person實例,我們可以先拿到name字段對應的Field,再獲取這個實例的name字段的值:
// reflectionimport java.lang.reflect.Field;public class Main { public static void main(String[] args) throws Exception { Object p = new Person("Xiao Ming"); Class c = p.getClass(); Field f = c.getDeclaredField("name"); Object value = f.get(p); System.out.println(value); // "Xiao Ming" }}class Person { private String name; public Person(String name) { this.name = name; }}上述代碼先獲取Class實例,再獲取Field實例,然后,用Field.get(Object)獲取指定實例的指定字段的值。
運行代碼,如果不出意外,會得到一個IllegalAccessException,這是因為name被定義為一個private字段,正常情況下,Main類無法訪問Person類的private字段。要修復錯誤,可以將private改為public,或者,在調用Object value = f.get(p);前,先寫一句:
f.setAccessible(true);調用Field.setAccessible(true)的意思是,別管這個字段是不是public,一律允許訪問。
可以試著加上上述語句,再運行代碼,就可以打印出private字段的值。
有童鞋會問:如果使用反射可以獲取private字段的值,那么類的封裝還有什么意義?
答案是正常情況下,我們總是通過p.name來訪問Person的name字段,編譯器會根據public、protected和private決定是否允許訪問字段,這樣就達到了數據封裝的目的。
而反射是一種非常規的用法,使用反射,首先代碼非常繁瑣,其次,它更多地是給工具或者底層框架來使用,目的是在不知道目標實例任何信息的情況下,獲取特定字段的值。
此外,setAccessible(true)可能會失敗。如果JVM運行期存在SecurityManager,那么它會根據規則進行檢查,有可能阻止setAccessible(true)。例如,某個SecurityManager可能不允許對java和javax開頭的package的類調用setAccessible(true),這樣可以保證JVM核心庫的安全。
設置字段值
通過Field實例既然可以獲取到指定實例的字段值,自然也可以設置字段的值。
設置字段值是通過Field.set(Object, Object)實現的,其中第一個Object參數是指定的實例,第二個Object參數是待修改的值。示例代碼如下:
// reflectionimport java.lang.reflect.Field;public class Main { public static void main(String[] args) throws Exception { Person p = new Person("Xiao Ming"); System.out.println(p.getName()); // "Xiao Ming" Class c = p.getClass(); Field f = c.getDeclaredField("name"); f.setAccessible(true); f.set(p, "Xiao Hong"); System.out.println(p.getName()); // "Xiao Hong" }}class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return this.name; }}運行上述代碼,打印的name字段從Xiao Ming變成了Xiao Hong,說明通過反射可以直接修改字段的值。
同樣的,修改非public字段,需要首先調用setAccessible(true)。
小結
Java的反射API提供的Field類封裝了字段的所有信息:
通過Class實例的方法可以獲取Field實例:getField(),getFields(),getDeclaredField(),getDeclaredFields();
通過Field實例可以獲取字段信息:getName(),getType(),getModifiers();
通過Field實例可以讀取或設置某個對象的字段,如果存在訪問限制,要首先調用setAccessible(true)來訪問非public字段。
通過反射讀寫字段是一種非常規方法,它會破壞對象的封裝。
【關鍵:
】
總結
以上是生活随笔為你收集整理的sqlite字段是否存在_学习廖雪峰的JAVA教程---反射(访问字段)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps ico插件_Photoshop 2
- 下一篇: .tex类型文件怎么阅读_Python用