今天學到Java基礎中的反反射。依照我學習後的個人理解呢,反射就是一套取得類別、屬性、方法等的工具吧。 (其實,感覺學完反射後,有點像喝涼水,解渴但確實我也沒體會出它有什麼味道,我可能沒有學到精髓吧。自己都能感覺少點什麼。這是我Java基礎學習的最後一個部分了,我想再複習一遍,然後再學習其他的。 )
在學習反射之前,我先回憶了一下可變參數。
public static void main(String[] args) { test();//调用方法1test("JAVA");//调用方法2test("JAVA","工程师");//调用方法3test(new String[]{"水果","电器"});//调用方法4 } static void test(String ... array){ //直接打印:System.out.println(array);for(String str:array){ //利用增强for遍历 System.out.println(str); } }
之所以回憶可變參數呢,是因為它與反射的應用有點像。如果將一個方法定義為可變參數,在呼叫的時候傳參的限制就少了一大截。在反射當中呢,我們利用一些方法,得到類別的實例對象,那麼類別裡面的方法、屬性等,就盡收眼底。在前面的學習中知道了,方法、屬性等都有靜態的和非靜態的,私有的和非私有的之分,那麼我們在調用的時候,想取哪一塊,或者說只想取得哪一塊,是不是也可以想個辦法實現呢?這時候,反射就出現了,現今我對它的理解就只有這些了。繼續努力吧。
一、反射的概念
JAVA反射機制是在運行狀態中(注意不是編譯的時候),對於任意一個類別,都能夠知道這個類別的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態獲取的資訊以及動態調用對象的方法的功能稱為java語言的反射機制。
Java反射機制主要提供了以下功能:
-- 在執行階段判斷任意一個物件所屬的類別;
-- 在執行時建構任一個類別的物件;
-- 在執行時判斷任一類別所具有的成員變數與方法;
-- 在執行時呼叫任意一個物件的方法;
- - 產生動態代理。
JDK中,與反射相關的類別,主要有以下幾個
//java.lang套件下
Class 類別
Class 類別的實例表示正在執行的Java 應用程式中的類別和介面。枚舉是一種類,註解是一種介面。每個數組屬於被映射為 Class 物件的一個類,所有具有相同元素類型和維數的數組都共用該 Class 物件。基本的 Java 類型(boolean、byte、char、short、int、long、float 和 double) 和關鍵字 void 也表示為 Class 物件。
關於Class類別JDK裡面的解釋:
public finalclass Class<T> implements java.io.Serializable, java.lang.reflect.GenericDeclaration, java.lang.reflect.Type, java.lang.reflect.AnnotatedElement {private static final int ANNOTATION= 0x00002000;private static final int ENUM = 0x00004000;private static final int SYNTHETIC = 0x00001000;private static native void registerNatives();static { registerNatives(); }/* * Constructor. Only the Java Virtual Machine creates Class * objects. */private Class() {}
Class類別JDK裡的一些方法(個人覺得讀起來很舒服,自己想記錄)
public String toString() {return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))+ getName(); }//应该是三元表达式
public static Class<?> forName(String className)throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)throws ClassNotFoundException { Class<?> caller = null; SecurityManager sm = System.getSecurityManager();if (sm != null) {// Reflective call to get caller class is only needed if a security manager// is present. Avoid the overhead of making this call otherwise.caller = Reflection.getCallerClass();if (loader == null) { ClassLoader ccl = ClassLoader.getClassLoader(caller);if (ccl != null) { sm.checkPermission( SecurityConstants.GET_CLASSLOADER_PERMISSION); } } }return forName0(name, initialize, loader, caller); }
private static native Class<?> forName0(String name, boolean initialize, ClassLoader loader, Class<?> caller)throws ClassNotFoundException;
public T newInstance()throws InstantiationException, IllegalAccessException {if (System.getSecurityManager() != null) { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); }// NOTE: the following code may not be strictly correct under// the current Java memory model.// Constructor lookupif (cachedConstructor == null) {if (this == Class.class) {throw new IllegalAccessException("Can not call newInstance() on the Class for java.lang.Class"); }try { Class<?>[] empty = {};final Constructor<T> c = getConstructor0(empty, Member.DECLARED);// Disable accessibility checks on the constructor// since we have to do the security check here anyway// (the stack depth is wrong for the Constructor's// security check to work) java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {public Void run() { c.setAccessible(true);return null; } }); cachedConstructor = c; } catch (NoSuchMethodException e) {throw new InstantiationException(getName()); } } Constructor<T> tmpConstructor = cachedConstructor;// Security check (same as in java.lang.reflect.Constructor)int modifiers = tmpConstructor.getModifiers();if (!Reflection.quickCheckMemberAccess(this, modifiers)) { Class<?> caller = Reflection.getCallerClass();if (newInstanceCallerCache != caller) { Reflection.ensureMemberAccess(caller, this, null, modifiers); newInstanceCallerCache = caller; } }// Run constructortry {return tmpConstructor.newInstance((Object[])null); } catch (InvocationTargetException e) { Unsafe.getUnsafe().throwException(e.getTargetException());// Not reachedreturn null; } }
public String getName() { String name = this.name;if (name == null)this.name = name = getName0();return name; }
// cache the name to reduce the number of calls into the VMprivate transient String name;private native String getName0();
還有很多,暫不記錄了。 。 。 。 。
//java.lang.reflect 包下 Constructor 代表构造函数 Method 代表方法 Field 代表字段 Array 与数组相关
二、Class類別的說明
常用的得到Class类的方法 // Class c=new Class(); 不可以,因为它被私有化了1) Class c=Student.class; //用类名.class 就可以得到Class类的实例2) Student stu=new Student(); Class c=stu.getClass(); //用对象名.getClass();3) Class c=Class.forName("com.mysql.jdbc.Driver");
//例一 通过调用无参的构造函数,创建类对象public class Test {public static void main(String[] args) throws InstantiationException, IllegalAccessException { Class clazz=Dog.class; Dog dog=(Dog)clazz.newInstance(); dog.shout(); } } class Dog{void shout(){ System.out.println("汪汪"); } }
透過例一,我並沒有看出來利用反射的好處,呃~~
//例二 上例的改写Class clazz=Class.forName("com.weiboo.Dog"); //注意,必须是类的全部Dog dog=(Dog)clazz.newInstance(); dog.shout();
//例三 (运行本类,Dog 和 Cat 类,必须有一个无参的构造函数)public class Test {public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Dog dog=(Dog)createObj(Dog.class); dog.shout(); Cat cat=(Cat)createObj(Cat.class); cat.speak(); } static Object createObj(Class clazz) throws InstantiationException, IllegalAccessException{return clazz.newInstance(); //调用的是newInstance() 方法创建的类对象,它调用的是类中无参的构造方法} } class Dog{void shout(){ System.out.println("汪汪"); } } class Cat{void speak(){ System.out.println("喵~~~"); } }
三、反射中的其他的類別的說明
1) Constructor
代表類別中的建構子 Class 類別提供了下列四個方法
public Constructor>[] getConstructors() //傳回類別中所有的public建構器集合,預設建構器的下標為0
public Constructor
public Constructor>[] getDeclaredConstructors() //傳回類別中所有的建構器,包含私有的
public Constructor
import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;//例子 得到某个类中指定的某个构造函数所对应的 Constructor对象class Test2 {public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { Class<Cat> clazz = Cat.class; Constructor<Cat> c = clazz.getConstructor(int.class, String.class); Cat cat = (Cat) c.newInstance(20, "加飞猫"); cat.speak(); }class Cat {private String name;private int age;public Cat(int age, String name) {this.age = age;this.name = name; }public Cat(String content) { System.out.println("这是构造函数得到的参数" + content); }void speak() { System.out.println("喵~~~"); System.out.println("我的名字是" + this.name + "我的年龄是" + this.age); } } }
/例子 访问类中的私有构造函数 Class clazz=Cat.class; Constructor c=clazz.getDeclaredConstructor(); c.setAccessible(true); //让私有成员可以对外访问Cat cat=(Cat) c.newInstance(); //对于私有的来说,能不能行?cat.speak();
2) Method 代表類別中的方法
Class 類別提供了以下四個方法
public Method[] getMethods() //取得所有的共有方法的集合,包擴充繼承的
#public Method getMethod(String name,Class>... parameterTypes) // 取得指定公有方法參數1:方法名稱參數2:參數型別集
public Method[] getDeclaredMethods() //取得所有的方法(包擴充私有的),除了繼承來的
public Method getDeclaredMethod(String name,Class>... parameterTypes) //取得任意指定方法,除來了繼承來的
//调用类中的私有方法main 函数 Class clazz=Cat.class;//调用一个不带参数的方法Method m=clazz.getDeclaredMethod("speak"); m.setAccessible(true); Cat c=new Cat(); m.invoke(c); //让方法执行 //调用一个带参数的方法Method m=clazz.getDeclaredMethod("eat", int.class,String.class); m.setAccessible(true); Cat c=new Cat(); m.invoke(c, 20,"鱼"); class Cat{private String name;private int age; Cat(){ }public Cat(int age,String name){this.age=age;this. name=name; } public Cat(String content){ System.out.println("这是构造函数得到的参数"+content); } private void speak(){ System.out.println("喵~~~"); System.out.println("我的名字是"+this.name+"我的年龄是"+this.age); } private void eat(int time,String something){ System.out.println("我在"+time +"分钟内吃了一个"+something); } }
例子 查看一个类中的所有的方法名public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { Class clazz=Cat.class; /*Method [] methodList=clazz.getMethods() ; //查看所有的公有方法,包扩继承的 for(Method m:methodList){ System.out.println(m.getName()); }*/Method [] methodList=clazz.getDeclaredMethods(); //查看所有的方法,包扩私有的,但不包扩继承的for(Method m:methodList){ System.out.println(m.getName()); } }
3) Field 代表字段
public Field getDeclaredField(String name) // 获取任意指定名字的成员
public Field[] getDeclaredFields() // 获取所有的成员变量,除了继承来的
public Field getField(String name) // 获取任意public成员变量,包含继承来的
public Field[] getFields() // 获取所有的public成员变量
//例子 访问字段public class Test {public static void main(String[] args) throws Exception { Class clazz=Cat.class; /* Field field= clazz.getField("home"); Cat c=new Cat(); Object obj=field.get(c); System.out.println(obj); // 家*/ Cat cat=new Cat(); Field [] fieldList= clazz.getDeclaredFields();for(Field f:fieldList){ //访问所有字段f.setAccessible(true); System.out.println(f.get(cat)); } } } class Cat{private String name="黑猫";private int age=2;public String home="家"; }
四、反射的应用
用一个例子来说明一下,比较两个同类对象中的所有字段,不同的并把它输出来。
import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class Test {public static void main(String[] args) throws Exception { Student stu1 = new Student(24, "李磊", "工程大学", "女"); Student stu2 = new Student(20, "王一", "师大", "男"); Map<String, String> map = compare(stu1, stu2);for (Map.Entry<String, String> item : map.entrySet()) { System.out.println(item.getKey() + ":" + item.getValue()); } }static Map<String, String> compare(Student stu1, Student stu2) { Map<String, String> resultMap = new HashMap<String, String>(); Field[] fieldLis = stu1.getClass().getDeclaredFields(); // 得到stu1所有的字段对象try {for (Field f : fieldLis) { f.setAccessible(true); // 别忘了,让私有成员可以对外访问Object v1 = f.get(stu1); Object v2 = f.get(stu2);if (!(v1.equals(v2))) { resultMap.put(f.getName(), "stu1的值是" + v1 + " stu2的值是" + v2); } } } catch (Exception ex) { ex.printStackTrace(); }return resultMap; } }class Student {private String name;private String school;private String sex;public Student(int age, String name, String school, String sex) {this.age = age;this.name = name;this.school = school;this.sex = sex; }private int age;public int getAge() {return age; }public void setAge(int age) {this.age = age; }public String getName() {return name; }public void setName(String name) {this.name = name; }public String getSchool() {return school; }public void setSchool(String school) {this.school = school; }public String getSex() {return sex; }public void setSex(String sex) {this.sex = sex; } }
以上是Java基礎入門之反射的詳細內容。更多資訊請關注PHP中文網其他相關文章!