Java反射機(jī)制介紹與Class類的基本能使用(工廠模式)

1.Java反射機(jī)制

1.1 反射機(jī)制是什么

在運(yùn)行狀態(tài)中,對于任意一個(gè)類都能夠知道這個(gè)類所有的屬性和方法;并且對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能為Java語言的反射機(jī)制。

1.2 反射的應(yīng)用場合

程序在運(yùn)行時(shí)可能接受到外部傳入的對象,該對象的編譯時(shí)類型為Object,但是程序有需要改對象的運(yùn)行時(shí)類型的方法。
為了解決這些問題,程序需要在運(yùn)行時(shí)發(fā)現(xiàn)對象和類的真實(shí)信息。
如果編譯時(shí)根本無法預(yù)知該對象和類屬于哪些類,比如這些類都是以字符串形式存放在配置文件中的時(shí)候,程序只能依靠運(yùn)行時(shí)信息來發(fā)現(xiàn)該對象和類的真實(shí)信息,此時(shí)必須使用反射了。

1.3 反射的常用類

  1. Class類(模板類):java.lang.Class 反射的核心類,可以獲取類的屬性、方法等信息;
  2. Field類:java.lang.reflec包中的類,表示類的成員變量,可以用來獲取和設(shè)置類之中的屬性值;
  3. Method類:Java.lang.reflec包中的類,表示類的方法,它可以用來獲取類中的方法信息或者執(zhí)行方法;
  4. Constructor類:Java.lang.reflec包中的類,表示類的構(gòu)造方法。

1.4 反射使用步驟

獲取想要操作的類的Class對象,他是反射的核心,通過Class對象我們可以任意調(diào)用類的方法;
調(diào)用Class類中的方法,即就是反射的使用階段;
使用反射API來操作這些信息。

  • 類的對象:基于某個(gè)類new出來的對象,也稱為實(shí)例對象。
  • 類對象:類加載的產(chǎn)物,封裝了一個(gè)類的所有信息
    ————類名、父類、接口、屬性、方法、構(gòu)造方法

2. Class類

位置:java.lang.Class

  • 類對象,類的實(shí)例代表一個(gè)運(yùn)行 類 java應(yīng)用程序的類和接口。
public final class Class<T>
    extends Object
    implements Serializable, GenericDeclaration, Type, AnnotatedElement

2.1 常用方法和示例

常用方法:

String getName()
返回由 類對象表示的實(shí)體(類,接口,數(shù)組類,原始類型或空白)的名稱,作為 String 。

static Class<?> forName(String className)
獲取類對象名

Package getPackage()
獲取類對象的包名

Class<? super T> getSuperclass()
獲取父類的類對象名

Class<?>[] getInterfaces()
獲取接口的類對象名

Constructor<?>[] getConstructors()
獲取構(gòu)造方法

Class<?>[] getParameterTypes()
獲取方法(構(gòu)造/成員)的參數(shù)類型列表

Field[] getFields()
獲取屬性(自身+父類的所有public公開屬性)

Field[] getDeclaredFields()
獲取屬性(自身所有的屬性)

Method[] getMethods()
獲取方法(自身+父類單繼承疊加的所有public公開方法)

Method[] getDeclaredMethods()
獲取方法(自身所有的方法)

T newInstance()
創(chuàng)建由此類對象表示的類的新實(shí)例(此類對象必須有無參構(gòu)造)。

方法使用示例:

public class TestClassMethods {
      public static void main(String[] args) throws Exception {
            // 獲取類對象
            Class<?> c = Class.forName("com.day.methods.Student");
            System.out.println(c.getName()); //  com.day.methods.Student
            
            // 獲得指定類對象的包名
            Package pack = c.getPackage();
            System.out.println(pack.getName()); // com.day.methods
            
            // 獲得父類的類對象
            Class<?> superClass = c.getSuperclass();
            System.out.println(superClass.getName()); //  com.day.methods.Person
            
            // 獲得接口的類對象
            Class<?>[] interfaces = c.getInterfaces();
            for (Class<?> inter : interfaces) {
                  // java.io.Serializable java.lang.Runnable  java.lang.Comparable
                  System.out.print(inter.getName() + " ");
            }
            
            // 獲取屬性(自身+父類的public公開屬性)
            Field[] fields = c.getFields();
            for (Field field : fields) {
                  System.out.print(field.getName() + " "); // name age  name money
            }
            // 獲取屬性(自身所有的屬性)
            Field[] fields2 = c.getDeclaredFields();
            for (Field field : fields2) {
                  System.out.print(field.getName() + " "); // name age  score
            }
            System.out.println("\n---------------------");
            
            // 獲取方法(自身+父類單繼承疊加的所有public公開方法)
            Method[] methods = c.getMethods();
            for (Method method : methods) {
                  // run compareTo exam play sleep eat wait wait wait  equals toString hashCode getClass notify notifyAll
                  System.out.print(method.getName() + " ");
            }
            System.out.println("\n---------------------");
            
            // 獲取方法(自身所有的方法)
            Method[] methods2 = c.getDeclaredMethods();
            for (Method method : methods2) {
                  // run:void compareTo:int play:void exam:void
                  System.out.println(method.getName() + ":" +  method.getReturnType());
            }
            System.out.println("*************************");
            
            // 獲取構(gòu)造方法
            Constructor<?>[] cs = c.getConstructors();
            for (Constructor<?> cc : cs) {
                  // com.day.methods.Student:java.lang.String int
                  // com.day.methods.Student:java.lang.String
                  // com.day.methods.Student: (無參構(gòu)造)
                  System.out.print(cc.getName() + ":");
                  Class<?>[] param = cc.getParameterTypes();
                  for (Class<?> p : param) {
                        System.out.print(p.getName() + " ");
                  }
                  System.out.println();
            }
            System.out.println();
            
            // new一個(gè)實(shí)例對象(必須要有無參構(gòu)造)
            Object o = c.newInstance();
            Student stu = (Student)o;
            System.out.println(stu); //  com.day.methods.Student@3d4eac69
      }
}
class Person {
      public String name;
      public double money;
      public Person() {}
      public void eat() {}
      public void sleep() {}
}
@SuppressWarnings({ "serial", "rawtypes" })
class Student extends Person implements Serializable, Runnable,  Comparable{
      public String name;
      public int age;
      double score;
      
      public Student() {super();}
      public Student(String name) {}
      public Student(String name, int age) {}
      
      public void exam() {}
      public void play() {}
      @Override
      public void run() {}
      @Override
      public int compareTo(Object o) { return 0; }
}

2.2 獲取Class對象的 3 種方法

① 通過類的對象,獲取Class對象
② 通過類名獲取一個(gè)Class對象
通過Class的靜態(tài)方法forName()獲取類對象 【最具普適性】

public class TestGetClassObject {
      public static void main(String[] args) throws  ClassNotFoundException {
            // 1.通過類的對象,獲取Class對象
            Person p = new Person(); // 類的對象
            Class<? extends Person> c = p.getClass();
            System.out.println(c.getName());
            
            // 2.通過類名獲取一個(gè)Class對象
            Class<Person> c2 = Person.class;
            System.out.println(c2.getName());
            
            // 3.通過Class的靜態(tài)方法獲取類對象 【最具普適性】
            Class<?> c3 = Class.forName("com.day.reflect.Person");
            System.out.println(c3.getName());
      }
      // 更通用的獲取類對象的方法
      public static Class<?> getClassObject(String className) {
            Class<?> c = null;
            try {
                  c = Class.forName(className);
            } catch (ClassNotFoundException e) {
                  e.printStackTrace();
            }
            return c;
      }
}
class Person {
}

2.3 反射創(chuàng)建對象的 2 種方法

① 反射通過類對象創(chuàng)建類的對象
方法傳參返回對象【普適性】

public class TestNewInstance {
      public static void main(String[] args) throws Exception {
            // 手工new對象
            Teacher t = new Teacher();
            t.name = "JJ";
            System.out.println(t.name);
            
            // 1.反射通過類對象創(chuàng)建類的對象
            Class<?> c = Class.forName("com.day.methods.Teacher");
            Teacher t2 = (Teacher)c.newInstance();
            t2.name = "Jerry";
            System.out.println(t2.name);
            
            // 2.方法傳參返回對象【普適性】
            Teacher t3 =  (Teacher)createObject("com.day.methods.Teacher");
            System.out.println(t3);
      }
      
      public static Object createObject(String className) {
            try {
                  Class<?> c = Class.forName(className);
                  return c.newInstance();
            } catch (Exception e) {
                  e.printStackTrace();
            }
            return null;
      }
}
class Teacher {
      String name;
      public Teacher() { }
}

3. 工廠設(shè)計(jì)模式(示例)

  • 開發(fā)中有一個(gè)非常重要的原則“開閉原則”,對拓展開放、對修改關(guān)閉;
  • 工廠模式主要負(fù)責(zé)對象創(chuàng)建的問題;
  • 通過反射進(jìn)行工廠模式的設(shè)計(jì),完成動態(tài)的對象創(chuàng)建。
public class TestNewInstanceForFile {
      public static void main(String[] args) throws Exception {
            // 創(chuàng)建出入流對象
            FileReader fr = new FileReader("files\\application.txt");
            BufferedReader br = new BufferedReader(fr);
            // 讀出文件中的類的全限定名
            String className = br.readLine();
            
            // 創(chuàng)建Object對象返回后進(jìn)行強(qiáng)轉(zhuǎn)為對應(yīng)類型,進(jìn)而使用
            Teacher t3 = (Teacher)createObject(className);
            System.out.println(t3);
            
            br.close();
      }
      
      /**
       * 工廠:創(chuàng)建對象工廠
       * @param className String類型的類的全限定名
       * @return Object Object類型的對象
       */
      public static Object createObject(String className) {
            try {
                  Class<?> c = Class.forName(className);
                  return c.newInstance();
            } catch (Exception e) {
                  e.printStackTrace();
            }
            return null;
      }
}
/*
* files\\application.txt 內(nèi)容:
* com.methods.Teacher
*/
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容