反射的概述:
JAVA反射機制是在運行時將任何一個類的內部信息暴露出來,例如這個類的所有屬性和方法;並且對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
反射是java中一種強大的工具,能夠使我們很方便的創建靈活的代碼,這些代碼可以再運行時裝配,無需在組件之間進行源代碼鏈接。但是反射使用不當會成本很高!
使用方法:
java.lang.Class:是反射的源頭
通過運行時類的對象,調用其getClass方法,返回其運行時類
正常的順序時通過類構建對象,反射是通過對象找到其所對應的類,進而調用這個類
創建的Persion類:包含註解、集成、接口、私有屬性、私有方法等。
package D19;
/**
* @Author: wj
* @Date: 2018/11/25 8:35
* @Version 1.0
*/
@MyAnnotation(value = "annotation")
public class Persion extends Creature<String> implements Comparable,MyInterface{
public String name;
private int age;
public Persion(String name, int age) {
this.name = name;
this.age = age;
}
public Persion() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@MyAnnotation(value = "123")
public void show(){
System.out.println("我是一個人");
}
private void display(String nation){
System.out.println("我的國籍是:" +nation);
}
public static void info(){
System.out.println("中國人");
}
@Override
public String toString() {
return "Persion{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public int compareTo(Object o) {
return 0;
}
}
1.
一.獲取Class的四種方法:
1. 調用運行時類本身
Class clazz1 = Persion.Class;
System.out.print(clazz1.getName());
2. 通過運行時類的對象創建
Persion persion = new Persion();
Class clazz2 = persion.getClass();
System.out.print(clazz2.getName());
3.通過運行時類的全類名路徑
Class clazz3 = Class.forName("D19.Persion");
System.out.print(clazz3.getName());
4.通過類加載器
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz4 = classLoader.loadClass("D13.Persion");
System.out.print("clazz4.getName()");
二.Class 的運用
1.獲取運行時類的屬性:
屬性的權限有別,有public、private、protected,不同權限的屬性獲取方法不同
下面提供兩種方法:
//獲取運行時類的屬性
@Test
public void test1(){
Class clazz = Persion.class;
//getFields 只能獲取到運行時類及其父類中權限爲public的
Field[] fields = clazz.getFields();
//getDeclaredFields只能獲取到運行時類本身聲明的所有屬性,包括private
Field[] fields2 = clazz.getDeclaredFields();
for(int i =0 ; i<fields2.length;i++){
System.out.println(fields2[i].getName());
}
}
2.各個屬性的特徵,包括權限修飾符、類型、變量名都可通過Class獲取
//屬性有 權限修飾符 類型 變量名
//獲取屬性各個部分的內容
@Test
public void test2(){
//getDeclaredFields只能獲取到運行時類本身聲明的所有屬性
Class clazz = Persion.class;
Field[] fields2 = clazz.getDeclaredFields();
for(Field f:fields2){
//1.獲取每個屬性的權限修飾符
int i = f.getModifiers();
String str1 = Modifier.toString(i);
System.out.println(str1);
//2.獲取每個屬性的變量類型
Class type = f.getType();
System.out.println(type.getName());
//3.獲取每個屬性的變量名
System.out.print(f.getName());
System.out.println();
}
}
3.獲取運行時類中的各種方法,同屬性一樣,不同權限的方法獲取形式不同
與屬性類似,獲取方法也分爲兩種
@Test
public void test3(){
Class clazz = Persion.class;
//1.獲取運行時類及其父類包括Object中所有的聲明爲Public的方法
Method[] methods = clazz.getMethods();
for(Method m :methods){
System.out.println(m);
}
//2.獲取運行時類自身的方法不包括父類的,其中也包含權限爲private的
methods = clazz.getDeclaredMethods();
for(Method m :methods){
System.out.println(m);
}
}
4.方法其他特徵的獲取,包括註解、權限修飾符、返回值類型、方法名、形參列表、拋出的異常等
以下通過Method[] methods = clazz.getMethods();獲取
//註解,權限修飾符,返回值類型,方法名,形參列表,拋出的異常
@Test
public void test4(){
Class clazz =Persion.class;
Method[] methods = clazz.getDeclaredMethods();
for(Method m :methods){
//1.獲取註解
Annotation[] ann = m.getAnnotations();
System.out.print(ann);
//2.權限修飾符
System.out.print(Modifier.toString(m.getModifiers()));
//3.返回值類型
Class returnType = m.getReturnType();
System.out.print(returnType.getName()+" ");
//4.方法名
System.out.print(m.getName()+" ");
//5.形參列表
System.out.print("(");
Class[] params = m.getParameterTypes();
for(Class p:params){
System.out.print(p.getName());
}
System.out.print(")");
//6.異常類型
Class[] exceptions = m.getExceptionTypes();
if(exceptions.length!=0){
System.out.println("throws ");
}
for(Class e:exceptions){
System.out.print(e.getName());
}
System.out.println();
}
}
5.類的泛型獲取(JDBC常用)
//獲取父類泛型(JDBC用到)
@Test
public void test5() throws ClassNotFoundException {
Class clazz = Class.forName("D19.Persion");
//獲取帶泛型的父類
Type type = clazz.getGenericSuperclass();
ParameterizedType param = (ParameterizedType) type;
Type[] args = param.getActualTypeArguments();
System.out.println(((Class)args[0]).getName());
}
6.獲取實現接口
//獲取實現的接口
@Test
public void test6(){
Class clazz = Persion.class;
Class[] interfaces = clazz.getInterfaces();
for(Class i:interfaces){
System.out.println(i.getName());
}
}
7.通過Class創建對象,併爲屬性賦值,以及調用各類方法
1)通過無參構造器創建
//使用反射創建對象,調用其中的方法(運行時類)
@Test
public void testReflection() throws Exception{
Class<Persion> clazz = Persion.class;
//1.創建clazz對應的運行時類(Persion)的對象
Persion p = clazz.newInstance();//必須有無參的構造方法
System.out.println(p);
//2.調用屬性
Field field1 = clazz.getField("name");//public屬性
//私有屬性調用
Field field2 =clazz.getDeclaredField("age");
field2.setAccessible(true);//關鍵
field1.set(p,"L");
field2.set(p,22);
System.out.println(p);
//3.使用反射調用類的方法
Method method1 = clazz.getMethod("show");//public方法
method1.invoke(p);
//帶參數的以及私有的(private)方法
Method method2 = clazz.getDeclaredMethod("display", String.class);
method2.setAccessible(true);//關鍵
//爲參數賦值(注意invoke可變參數)
method2.invoke(p,"China");
//帶返回值的
Method method3 = clazz.getMethod("toString");
Object returnVal = method3.invoke(p);
System.out.println(returnVal);
//靜態方法
Method method4 = clazz.getMethod("info");
method4.invoke(p);
//也可以不用太對象
method4.invoke(Persion.class);
}
2)調用指定構造器
//調用指定構造器
@Test
public void test8() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
String className = "D19.Persion";
Class clazz = Class.forName(className);
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Persion p = (Persion) cons.newInstance("bxklx",20);
System.out.println(p);
}
8.通過ClassLoder讀取配置文件
配置文件:
user=root;
password=123
讀取方法:
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream is = classLoader.getResourceAsStream("Jdbc.properties");
Properties properties = new Properties();
properties.load(is);
String user = properties.getProperty("user");
System.out.println(user);
結果:
以上就是我學習JAVA反射時用到的方法,對於反射用到的地方特別多,尤其是閱讀框架源碼時候,此外在通過Sql查詢數據庫獲得對象時,也可通過反射構建實體對象,並未對象賦值。