類是用來描述對象的,而反射就能夠理解爲是用來描述類的。java
類中的屬性包括:app
1.Class的靜態方法,forName("全類名")工具
2.類.class關鍵字測試
3.對象引用.getClass()方法 Object中的方法ui
/* 0--默認不寫 1--public 2--private 4--protected 8--static 16--final 32--synchronized 64--volatile 128--transient 256--native 512--interface 1024--abstract */ int = getModifiers(); //獲取類的修飾符(權限+特徵) String = getName(); //獲取類的全類名 String = getSimpleName(); //獲取簡單名(只有類名 ) Class = getSuperClass(); //獲取當前父類的對應Class Class[] = getInterfaces(); //獲取當前父類的接口 Package p = getPackage(); //獲取當前類所在的包 p.getName(); //獲取包的名字 Class[] = getClasses(); //獲取類中的內部類 Object = newInstance(); //獲取當前類的對象(至關於調用了類中的無參數的構造方法)若是類中不存在無參數的構造方法,就會拋出NoSuchMethodException異常 Field = getField("屬性名"); //獲取類中的屬性(公有的 本身類+父類) Field[] = getFields(); //獲取類中的所有屬性(公有的 本身類+父類) Field = getDeclaredField("屬性名") //獲取當前類的屬性(公有 + 私有 本身類) Field = getDeclaredFields() //獲取當前類的所有屬性(公有 + 私有 本身類) 若是想修改私有的屬性則須要設置屬性能夠被操做 setAccessible()
public class TestMain { public static void main(String[] args) { try { Class<?> clazz = Class.forName("com.lili.reflect.People"); Package aPackage = clazz.getPackage(); int modifiers = clazz.getModifiers(); System.out.println(modifiers); Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method.getName()); } System.out.println(aPackage); Class<?>[] interfaces = clazz.getInterfaces(); for (Class c : interfaces) { System.out.println(c.getName()); } ArrayList<String> list = new ArrayList<>(); Class c = ArrayList.class; Class superclass = c.getSuperclass(); while (superclass != null) { System.out.println(superclass.getName()); superclass = superclass.getSuperclass(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
/* 注意只能是繞過private去修改屬性的值,而不能去修改屬性的長度,由於是final修飾的。 String的不可變指的是長度+值的不可變 */ public class ChangeString { public static void main(String[] args) { try { String str = new String("abc"); System.out.println(str); //一、利用反射技術獲取String的Class Class clazz = str.getClass(); //二、獲取屬性 Field f = clazz.getDeclaredField("value"); //三、設置能夠修改屬性的值 f.setAccessible(true); //四、獲取屬性的值 char[] newChar = (char[])f.get(str); //五、修改屬性的值 newChar[0] = 'xu'; newChar[1] = 'Li'; newChar[2] = 'Li'; System.out.println(str); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
能夠獲取共有的方法,包括本身類的以及父類的spa
能夠找到私有的方法,可是要經過setAccessible(true)
方法來執行私有的方法。設計
/** * 測試使用反射獲取類中的方法 */ public class TestMethod { public static void main(String[] args) { try { //一、獲取People類對應的Class Class clazz = People.class; //二、獲取對象 People p = (People) clazz.newInstance(); //三、經過clazz獲取其中的方法,經過方法名以及方法的參數類型來定位方法。 Method m = clazz.getMethod("eat", String.class); //四、調用方法,第一個參數是要執行方法的對象,第二個則是傳進去的參數列表 String n = (String) m.invoke(p, "lili要開始吃飯啦"); System.out.println(n); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
/** * 利用反射執行構造方法 */ public class TestConstructor { public static void main(String[] args) { try { //一、獲取People對應的Class Class<People> clazz = People.class; //二、獲取People中的構造方法,其中省去了構造方法的名稱,由於是與類同名 //無參的就是調用的無參數的構造方法 //有參數的就是傳的構造方法中形參的類型.class Constructor<People> constructor = clazz.getConstructor(String.class); //三、執行構造方法,同理參數就是要傳參數的實參 People people = constructor.newInstance("哈哈哈哈哈"); System.out.println(people); } catch (Exception e) { e.printStackTrace(); } } }
這個小工具能夠代替咱們本身建立對象的功能,經過傳遞一個字符串,來幫咱們建立一個對象,同時還能將對象內的全部屬性賦值。code
其實這就是簡單的模擬了Spring中IOC思想的原理,IOC(Inversion Of Control)控制反轉:將對象的控制權反轉,交給Spring容器去處理;DI(Dependency Injection)依賴注入:Spring容器建立對象的同時幫咱們自動的注入屬性的值。對象
public class MySpring { //設計一個方法,將咱們建立對象的過程交給該方法去執行。 //參數String類型的全類名 //返回值 建立出來的對象 Object類型--->再添加上DI依賴注入 public Object getBean(String classPath) { Object obj = null; //模擬輸入的實參 Scanner scanner = new Scanner(System.in); System.out.println("請給"+ classPath +"的屬性賦值"); try { //一、獲取該路徑下對應的Class Class clazz = Class.forName(classPath); //二、建立一個對象 obj = clazz.newInstance(); //使用set方法對對象的屬性進行賦值,找到每個不一樣對象對應的set方法。 //也就是字符串set+屬性的名字 //三、獲取類中的屬性 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { //獲取屬性的名稱 String fieldName = field.getName(); //改變屬性名中第一個字母的大小寫 String first = fieldName.substring(0, 1).toUpperCase(); //獲取屬性名中除開第一個字母的字段 String last = fieldName.substring(1); //拼接set方法 StringBuilder methodName = new StringBuilder("set"); methodName.append(first); methodName.append(last); //四、獲取屬性的類型 Class fieldType = field.getType(); //五、獲取方法 Method method = clazz.getMethod(methodName.toString(), fieldType); //接收實參 System.out.println("請給"+ fieldName +"屬性賦值"); String value = scanner.nextLine(); /*爲了解決參數類型不一致的問題,能夠將參數的類型都設置未相應的包裝類, 而且將它們都轉換成String的類型,除了Char類型以外須要另外的判斷。 能夠利用其它包裝類帶String類型的構造方法進行處理。 */ Constructor con = fieldType.getConstructor(String.class); //六、執行方法 method.invoke(obj, con.newInstance(value)); } } catch (Exception e) { e.printStackTrace(); } return obj; } }