黑马程序员-学习日记(反射)

  ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、概述

JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。

动态获取类中信息,就是java反射。可以理解为对类的解剖。

如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了此技术。

示例:获取字节码文件对象的3种方式

Person.java

 1 package reflect;
 2
 3 public class Person {
 4     private int age;
 5     private String name;
 6
 7     public Person(int age,String name)
 8     {
 9         super();
10         this.age = age;
11         this.name = name;
12         System.out.println("Person param run..." + this.name + ":" + this.age);
13     }
14     public Person()
15     {
16         super();
17         System.out.println("person run");
18     }
19
20      public void show(){
21          System.out.println(name + "...show run..." + age);
22  }
23
24      private void privateMethod(){
25              System.out.println("method run");
26      }
27
28      public void paramMethod(String str,int num){
29              System.out.println("paramMethod run..." + str + ":" + num);
30      }
31
32      public static void staticMethod(){
33              System.out.println("static method run...");
34      }
35 }

1??、Object类中的getClass()方法。使用该方法必须明确要获取的具体的类,并创建对象。所以比较麻烦。

2??、任何数据类型都具备有一静态属性(.class)来获取其对应的Class对象。虽然相对上一种方式简单,但还是要明确用到类中的静态成员。

3??、只要通过给定的类的字符串名称就能获取该类字节码文件。

ReflectDemo.java

 1 package reflect;
 2 //import reflect.Person;
 3
 4 public class ReflectDemo {
 5
 6     public static void main(String[] args) throws ClassNotFoundException {
 7
 8         getClassObject_3();
 9
10
11     }
12
13     public static void getClassObject_1()
14     {
15         Person p = new Person();
16         Class cls = p.getClass();
17
18         Person p1 = new Person();
19         Class cls1 = p1.getClass();
20
21         System.out.println(cls==cls1);
22     }
23
24     public static void getClassObject_2()
25     {
26         Class clazz = Person.class;
27         Class clazz1 = Person.class;
28
29         System.out.println(clazz == clazz1);
30     }
31
32     public static void getClassObject_3() throws ClassNotFoundException
33     {
34         String className = "reflect.Person";
35         Class clazz = Class.forName(className);
36         System.out.print(clazz);
37     }
38 }

如果指定 的类中没有空参数构造函数。或者要创建的类对象需要通过指定的构造函数进行初始化。此时就不能用到newInstance方法了。

得到这个类的所有构造函数:

Constructor[] constr = Class.forName("reflect.Person").getConstructors();

获取某一个构造函数:

Constructor constr = Person.class.getConstructor(String.class,int.class);

创建实例对象:

Person p = (Person)constr.newInstance(30,"小王");

要注意的是创建实例时newInstance方法中的参数列表必须与获取Constructor的方法getConstructor方法中的参数列表一致。

示例:获取Class中的构造函数

 1 package reflect;
 2
 3
 4 import java.lang.reflect.Constructor;
 5 import java.lang.reflect.InvocationTargetException;
 6
 7 public class ReflectDemo {
 8
 9     public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
10
11         createNewObject_1();
12         createNewObject_2();
13
14     }
15
16     public static void createNewObject_1() throws ClassNotFoundException, InstantiationException, IllegalAccessException
17     {
18         String classname = "reflect.Person";
19         Class cls = Class.forName(classname);
20         Object obj = cls.newInstance();
21     }
22
23     public static void createNewObject_2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
24     {
25         /*
26          * 使用getConstructor(parameterTypes)方法来获取指定名称对应类所        体现的对象的构造函数
27          */
28         String classname = "reflect.Person";
29         //找到该名称类文件、加载进内存,并产生Class对象
30         Class cls = Class.forName(classname);
31         //获取到指定的构造函数对象
32         Constructor contr = cls.getConstructor(int.class,String.class);
33         //通过该构造函数对象的newInstance方法进行对象的初始化
34         Object obj = contr.newInstance(29,"小王");
35     }
36 }

示例:获取类的字段

 1 package reflect;
 2 //import reflect.Person;
 3 import java.lang.reflect.Field;
 4 import java.lang.reflect.Constructor;
 5 import java.lang.reflect.Field;
 6 import java.lang.reflect.InvocationTargetException;
 7
 8 public class ReflectDemo {
 9
10     public static void main(String[] args) throws Exception {
11
12         getFieldDemo();
13     }
14     public static void getFieldDemo() throws Exception
15     {
16         Class cls = Class.forName("reflect.Person");
17         //getDeclaredField可以都获取到公共字段或私有字段
18         Field field = cls.getDeclaredField("age");
19         //对私有字段的访问取消权限检查。
20         field.setAccessible(true);
21
22         Object obj = cls.newInstance();
23         field.set(obj, 31);
24         Object o = field.get(obj);
25         System.out.println(field);
26     }
27 }

示例:获取类中的方法

 1 package reflect;
 2 import java.lang.reflect.Field;
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.InvocationTargetException;
 6
 7 public class ReflectDemo {
 8
 9     public static void main(String[] args) throws Exception {
10
11         getMethodDemo_1();
12         System.out.println("---------------------------");
13         getMethodDemo_2();
14         System.out.println("---------------------------");
15         getMethodDemo_3();
16     }
17
18     public static void getMethodDemo_1() throws ClassNotFoundException
19     {
20         Class cls = Class.forName("reflect.Person");
21         Method[] methods = cls.getMethods();
22         methods = cls.getDeclaredMethods();
23         for (Method mthd:methods)
24         {
25             System.out.println(mthd);
26         }
27     }
28     public static void getMethodDemo_2() throws Exception
29     {
30         Class cls = Class.forName("reflect.Person");
31         Method mt = cls.getMethod("show", null);
32         Object obj = cls.newInstance();
33         Constructor contr = cls.getConstructor(int.class,String.class);
34         obj = contr.newInstance(21,"小米");
35         mt.invoke(obj, null);
36     }
37     public static void getMethodDemo_3() throws Exception
38     {
39         Class cls = Class.forName("reflect.Person");
40         Method mt = cls.getMethod("paramMethod", String.class,int.class);
41         Object obj = cls.newInstance();
42
43         Constructor constr = cls.getConstructor();
44         obj = constr.newInstance();
45         mt.invoke(obj, "小李",23);
46     }
47 }

应用场景:

一个应用程序已经完成编写,无需额外的代码加入了。而后期遇出现了需要加入新的功能的情况。就如同计算机一样,使用后期用户会置换更好的键盘、硬盘等,所以计算机事先预留了usb接口,只要符合此接口规则的设备,计算机就可以通过加载驱动来完成使用。

一个方便的作法是,对外提供一个配置文件,让后期出现的子类直接将类名写入配置文件中即可。该应用程序直接读取配置文件的内容,并查找与给定名称相同的类文件。

 1 package reflect;
 2
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.sql.PseudoColumnUsage;
 6 import java.util.Properties;
 7
 8 public class ReflectTest {
 9      public static void main(String[] args)  throws Exception
10      {
11          Computer cp = new Computer();
12          cp.run();
13
14          //关联配置文件
15          FileInputStream fis = new FileInputStream(new File("USB.properties"));
16          //将配置文件信息缓存到集合中
17          Properties props = new Properties();
18          props.load(fis);
19          for (int i = 1; i < props.size(); i++) {
20             String className = props.getProperty("USB"+i);
21             Class cls = Class.forName(className);
22             USB usb = (USB)cls.newInstance();
23             cp.viaUSB(usb);
24         }
25          fis.close();
26      }
27 }
28
29 interface USB{
30     void plug();
31     void unplug();
32 }
33
34 class Computer{
35     public void run() {
36         System.out.println("Computer is running");
37     }
38     public void viaUSB(USB usb){
39         if(usb!=null){
40             usb.plug();
41             usb.unplug();
42         }
43     }
44 }
45
46 class Keyboard implements USB{
47     @Override
48     public void plug() {
49         // TODO Auto-generated method stub
50         System.out.println("Keyboard plugged in!");
51     }
52
53     @Override
54     public void unplug() {
55         // TODO Auto-generated method stub
56         System.out.println("Keyboard unplugged!");
57     }
58 }
59
60 class Monitor implements USB{
61
62     @Override
63     public void plug() {
64         // TODO Auto-generated method stub
65         System.out.println("Monitor plugged in!");
66     }
67
68     @Override
69     public void unplug() {
70         // TODO Auto-generated method stub
71         System.out.println("Monitor unplugged!");
72     }
73
74 }

---恢复内容结束---

时间: 2024-12-13 22:08:55

黑马程序员-学习日记(反射)的相关文章

黑马程序员-学习日记(面向对象)

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 1.面向对象  理解面向对象  面向对象是相对面向过程而言,面向对象和面向过程都是一种思想. 面向过程: 强调的是功能行为.代表语言:C语言. 例子:把大象装进冰箱 1.打开冰箱门.2.放入大象.3.关上冰箱门."打开"."存储"."关上"都是功能行为,在代码中的直观体现就是函数或者方法,这就是一种面向过程的以功能行为为主体的思想体现. 面向对

黑马程序员-学习日记(接口和多态)

1.继承 1-1 继承的概念 1-1-1 继承的概述 通过 extends 关键字让类与类之间产生继承关系. 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可. 多个类可以称为子类,单独这个类称为父类或者超类. 注意: ①子类可以直接访问父类中的非私有的属性和行为. ②子类无法继承父类中私有的内容.③父类怎么来的?共性不断向上抽取而来的. ExtendDemo.java class Person{ String name; int

黑马程序员-学习日记(多线程的初步认识)

 ------Java EE培训.Android培训.iOS培训.期待与您交流! ------- 进程:正在执行的应用程序.一个应用程序运行时内存分配的空间.线程:进程中一个程序执行的控制单元,一条执行路径.负责程序的执行顺序.多线程:在java虚拟机启动的时候会有一个java.exe的执行程序,即一个进程.该进程中至少有一个线程负责java程序的运行.而且这个线程运行的代码存在于main方法中. class Demo extends Thread { public void run() { f

黑马程序员-学习日记(多线程安全问题和死锁认识)

------Java培训.Android培训.iOS培训.期待与您交流! ------- 安全问题产生的原因: 当多条代码语句在操作同一个共享数据时,一个线程对多条语句只执行了一部分,还没有执行完, 另一个线程参与进来执行.导致共享数据的错误. class Mlpc implements Runnable { private int ticket = 50; public void run() { while(true) { if(ticket>0) { try { Thread.sleep(2

黑马程序员-学习日记(单例设计模式的两种类型)

单例设计模式:解决一个类在内存中只有一个对象 多个程序使用统一配置信息对象时,需要保证该对对象的唯一性. 保证对象唯一性的实现步骤: 1.将构造函数私有化:为了避免其他程序过多建立该对象,禁止其他程序调用该对象. 2.在类中创建一个本类对象:为了让其他程序可以访问该类对象 3.提供一个方法可以获取到该对象的方法:方便其他程序访问自定义的本类对象.(类方法的访问方式只有两种,建立对象或定义为静态方法)

黑马程序员-学习日记(多线程)

进程:正在执行的应用程序.一个应用程序运行时内存分配的空间.线程:进程中一个程序执行的控制单元,一条执行路径.负责程序的执行顺序. 多线程存在的意义: 程序运行中至少有两个线程在运行,一个是主函数的主线程,另一个是垃圾回收的线程. 线程创建方式一: 继承Thread类.要覆盖其run方法,调用线程的start方法. 作用:1.启动线程 2.运行run方法.目的是将自定义的代码存储在run方法中,让线程运行 cpu每次只执行一个程序,只是在快速的不同线程间切换,表现了多线程的随机性 class M

黑马程序员-学习日记(集合类之TreeSet)

为什么会用到集合类? 面向对象语言对事物的体现都是以对象的方式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式. 数组虽然也可以存储对象,但长度固定.集合长度可变.数组中可以存储基本数据类型,集合只能存储对象. 集合类自身的特点 只用于存储对象,长度可变,能够存储不同类型的对象. 容器分了很多种,因此Java工程师对其进行了划分.这个划分成的体系就被成为集合框架. import java.util.*; class mapDemo { public static

黑马程序员-学习日记(多线程间的通信)

 ------Java EE培训.Android培训.iOS培训.期待与您交流! ------- 示例: //将资源封装成对象 class Resour { String name; String gender; } //将线程执行的任务封装成对象 class Input implements Runnable { private Resour r; Input(Resour r) { this.r = r; } public void run() { int x =0; while(true)

黑马程序员-学习日记(多线程的安全)

安全产生的原因: 当多条语句在操作同一个共享数据时,一个线程对多条语句只执行了一部分,还没有执行完, 另一个线程参与进来执行.导致共享数据的错误. class Mlpc implements Runnable { private int ticket = 50; public void run() { while(true) { if(ticket>0) { try { Thread.sleep(20); //让线程进入冻结状态 } catch (Exception e) { } System.