黑马程序员------Java反射学习总结(一)

-------------------------Java培训、Android培训,期待与您交流!-----------------------------

一、反射的概念

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

  2)一句话来讲,反射就是将Java类中的各个成分映射成相应的Java类。

  3)即在Java中,描述事物的各种类同样也是一种事物,也可以用面向对象的方法来描述,即也有一个类来描述众多的Java类。

  4)反射也称为对类的解剖。例如一个类有成员变量、构造方法、成员方法,包等信息,通过反射,就可以拿到这个类的各种信息。

二:Class类

  1)所有的类文件(.class文件)都有共同属性,所以可以向上抽取,把这些共性内容封装成一个类,这个类就叫Class(描述字节码文件的对象)。

  2)Class类描述的信息:类的名字,类的访问属性,类所属于的包名,字段名称列表,方法名称列表等。每一个字节码就是class的实例对象。如:Class clazz = String.class.

  3)Class类是Java中反射的基石。

1、获取Class对象的三种方式:

  1)通过所有数据类型都有的静态属性.class来获取

    类名.class  例如:String.class

  2)通过对象的getClass()方法获取

    对象.getClass()  例如:new String("123").getClass();

  3)通过Class类的静态方法forName()和要获得Class对象的类名来获取

    Class.forName(包名.类名);  例如:Class.forName("java.lang.String");

  代码示例: 

 1 public class ClassTest{
 2   public static void main(String...args)throws Exception{
 3     String str = "黑马程序员";
 4     Class cls1 =String.class;
 5     Class cls2 = str.getClass();
 6     Class cls3 = Class.forName("java.lang.String");
 7     System.out.println(cls1 == cls2);//true
 8     System.out.println(cls2 == cls3);//true
 9   }
10 }

  注:同一个类的字节码文件是唯一的,所以无论怎样获取,都是同一份字节码文件,即同一个Class实例对象

2、Java中预定义的九个Class对象:

  1)  包括八种基本类型(byte、short、int、long、float、double、char、boolean)的字节码对象和一种返回值为void类型的void.class。

  2)  Integer.TYPE是Integer类的一个常量,它代表此包装类型包装的基本类型的字节码,所以和int.class是相等的。基本数据类型的字节码都可以用与之对应的包装类中的TYPE常量表示。

  注意:具有相同数据类型和维数的数组在Java中被映射为同一个Class对象。

3、Class类中的常用方法:

   1)  static Class forName(String className)  返回与给定字符串名的类或接口的相关联的Class对象。

2)  Class getClass()  返回的是Object运行时的类,即返回Class对象即字节码对象

3)  Constructor getConstructor()   返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。

4)  Field getField(String name)   返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。

5)  Field[] getFields()   返回包含某些Field对象的数组,表示所代表类中的成员字段。

6)  Method getMethod(String name,Class… parameterTypes)  返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。

7)  Method[] getMehtods()  返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。

8)  String getName()  以String形式返回此Class对象所表示的实体名称。

9)  String getSuperclass()  返回此Class所表示的类的超类的名称

10) boolean isArray()  判定此Class对象是否表示一个数组

11) boolean isPrimitive()  判断指定的Class对象是否是一个基本类型。

12) T newInstance()  创建此Class对象所表示的类的一个新实例。注意:此方法会使用该的空参数构造函数进行初始化实例对象。 

三:Constructor类

1、概述:Constructor类的实例对象代表类的一个构造方法。

2、获取构造方法:

1)得到这个类的所有构造方法:如得到String类的所有构造方法

Constructor[] cons = Class.forName(“java.lang.String”).getConstructors();

2)获取某一个构造方法:

Constructor con=String.class.getConstructor(StringBuffer.class);

3、创建实例对象:

1)通常方式:String str = new String("123");

2)反射方式:String str = (String)con.newInstance("123");

注:

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

2、newInstance():构造出一个实例对象,每调用一次就构造一个对象。

3、利用Constructor类来创建类实例的好处是可以指定构造函数,而Class类只能利用无参构造函数创建类实例对象。

代码示例:

 1 package com.itheima.day01;
 2 import java.lang.reflect.Constructor;
 3 public class ReflectTest {
 4     public static void main(String[] args) throws Exception {
 5         //获取String类的Class对象
 6         Class clszz = Class.forName("java.lang.String");
 7         //获取String类Class对象的构造方法
 8         Constructor constructor =  clszz.getConstructor(StringBuffer.class);
 9         //通过此构造方法获取String类的实例对象
10         String str = (String) constructor.newInstance(new StringBuffer("黑马程序员"));
11     }
12 } 

四、Field类

1、Field类代表反射某个类中的成员变量。

2、方法

  1)  Field getField(String s);//只能获取公有和父类中公有

  2)  Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有

  3)  setAccessible(ture);//如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。

  4)  set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。

  5)  Object get(Object obj);//返回指定对象上Field表示的字段的值。

示例:

 1 package cn.itheima;
 2   public class Person {
 3     private String name;
 4     public int age;
 5
 6     Person(){}
 7
 8     Person(String name,int age){
 9       this.name = name;
10       this.age = age;
11     }
12
13     public String toString(){
14       return name+"::"+age;
15     }
16   }
17
18 //获取Person对象的成员变量
19 public static void getPersonField() throws Exception{
20 //如果想要给该变量赋值,必须先要有对象。
21     Class clazz=Class.forName("cn.itheima.Person");
22     Person p=(Person)clazz.newInstance();
23
24     //获取所有的成员变量
25     Field[] fs=clazz.getFields();
26     for(Field f:fs){
27         System.out.println(f);
28     }
29
30     //获取指定的成员变量
31     Field fage=clazz.getField("age");
32     Field fname=clazz.getDeclaredField("name");
33
34     //显示改变后的值
35     fage.set(p, 20);
36     System.out.println(fage.get(p));
37
38     //暴力访问私有变量
39     fname.setAccessible(true);
40     fname.set(p, "zhangsan");
41     System.out.println(fname.get(p));
42 }

  注意:暴力反射的方式,也就是使用setAccessible(true)使private类型的成员变量也可以被获取值。

五:Method类

1、概念:

  Method类代表某个类中的一个成员方法。

2、专家模式:谁调用这个数据,就是谁在调用它的专家。

如人画圆:

调用者:是圆调用画的动作,对象是圆,因为圆知道如何执行画的动作,通过圆心和半径等之类的细节实现。

指挥者:是人在指挥圆做画的动作,只是给圆发出了画自己的信号,让圆去执行。

总结:变量使用方法,是方法本身知道如何实现执行的过程,也就是“方法对象”调用方法,才执行了方法的每个细节的。

   一种程序设计思想,即设计类时,应把此类有关改变自身成员变量的动作设计为自己的成员方法,而不是外置到另一个类中。

3、方法

Method[] getMethods();//只获取公共和父类中的方法。

Method[] getDeclaredMethods();//获取本类中包含私有。

Method   getMethod("方法名",参数.class(如果是空参可以写null));

Object invoke(Object obj ,参数);//调用方法  注:如果方法是静态,invoke方法中的对象参数可以为null。

  例如:

    获取某个类中的某个方法:String str = "abcd";

     Method methodCharAt =Class.forName("java.lang.String").getMethod("charAt",int.class);

    调用这个方法:

    1)通常方式:

      str.charAt(2);

    2)反射方式

      methodCharAt.invoke(str,2);

   注:如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法

4、JDK1.4和JDK1.5的invoke方法的区别:

  JDK1.4:public Object invoke(Object obj,Object[] args)

  JDK1.5:public Object invoke(Object obj,Object... args)

  即按JDK1.4的语法,需要将一个数组作为参数传递给invoke方法时,这时它会把一个数组作为一个元素。

  这时如果我们要取出其中的元素,需要将数组中的元素通过数组一个个的取出。

  所以,调用charAt方法的代码也可以用JDK 1.4改写为 charAt.invoke("str", new Object[]{1})形式。

 代码示例:

 1 package com.itheima.day1;
 2 import java.lang.reflect.Method;
 3 public class ReflectTests {
 4     public static void main(String[] args) throws Exception {
 5         String str = "黑马程序员";
 6         Method method = str.getClass().getMethod("charAt", int.class);
 7         // 1.4写法。
 8         System.out.println(method.invoke(str, new Object[] { 1 }));
 9         // 1.5写法。
10         System.out.println(method.invoke(str, 0));
11     }
12 }

5、对接受数组参数的成员方法进行反射

  需求:用反射的方法运行某个类的mian函数

  代码:

 1  package com.itheima.day1;
 2   import java.lang.reflect.Method;
 3    public class MassTests {
 4          Class clszz = Class.forName("com.itheima.day1.TestArguments");
 5
 6           Method main = clszz.getMethod("main", String[].class);
 7
 8           main.invoke(null, new String[]{"aaa", "bbb", "ccc"});
 9        }
10   }
11  class TestArguments{
12   public static void main(String[] args){
13     for(String s: args){
14       System.out.println(s);
15     }
16   }
17 }

  这段代码会发生异常:非法参数异常:Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments

分析原因:

  1)启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?

  2)按JDK1.5的语法,整个数组是一个参数,而按JDK1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,Javac会到底按照哪种语法进行处理呢?

  3)JDK1.5肯定要兼容JDK1.4的语法,会按JDK1.4的语法进行处理,即把数组打散成若干个单独的参数。

  4)所以,在给main方法传递参数时,不能使用代码main.invoke(null,"aaa","bbb","ccc"),Javac只把它当作JDK1.4的语法进行理解,而不把它当作JDK1.5的语法解释,因此会出现参数类型不对的问题。

解决方法:

  1)main.invoke(null,new Object[]{new String[]{"aaa","bbb","ccc"}});

  2)main.invoke(null,(Object)new String[]{"aaa","bbb","ccc"});编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了。

六、数组的反射

1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。数组字节码的名字:有[和数组对应类型的缩写,如int[]数组的名称为:[I

2、Object[]与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”}; Object x =“abc”能强制转换成String x =“abc”。

3、如何得到某个数组中的某个元素的类型,

例:

int a = new int[3];Object[] obj=new Object[]{”ABC”,1};

无法得到某个数组的具体类型,只能得到其中某个元素的类型,

如:

Obj[0].getClass().getName()得到的是java.lang.String。

4、Array工具类用于完成对数组的反射操作。

Array.getLength(Object obj);//获取数组的长度

Array.get(Object obj,int x);//获取数组中的元素

5、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

示例:

 1 package cn.itheima.Demo;
 2
 3 import java.lang.reflect.Array;
 4 import java.util.Arrays;
 5
 6 public class ArrayReflect {
 7     public static void main(String[] args) {
 8         int [] a1 = new int[]{1,2,3};
 9         int [] a2 = new int[4];
10         int[][] a3 = new int[2][3];
11         String [] a4 = new String[]{"a","b","c"};
12         System.out.println(a1.getClass().equals(a2.getClass()));//true
13     System.out.println(a1.getClass().equals(a3.getClass()));//false
14       System.out.println(a1.getClass().equals(a4.getClass()));//false
15       System.out.println(a1.getClass().getName());//[I
16       System.out.println(a4.getClass().getName());//[Ljava.lang.String;
17       System.out.println(a1.getClass().getSuperclass());//class java.lang.Object
18       System.out.println(a4.getClass().getSuperclass());//class java.lang.Object
19
20         Object obj1=a1;
21         Object obj2=a3;
22         Object obj3=a4;
23
24 //        Object[] obj11=a1;//编译失败,因为a1中的元素是int类型,基本数据类型不是Object
25         Object[] obj13=a3;
26         Object[] obj14=a4;//编译成功,因为String数组中的元素属于Object
27
28         System.out.println(a1);//[[email protected]
29         System.out.println(a4);//[Ljava.lang.String;@6c10a234
30         System.out.println(Arrays.asList(a1));//[[email protected]
31         System.out.println(Arrays.asList(a4));//[a, b, c]32 }
33   

6、Arrays.asList()方法处理int[]和String[]时的差异。

  代码示例:

 1 public classReflectTest {
 2   public static void main(String[] args) throwsException {
 3     int[] arr =new int[] { 1, 2, 3 };
 4     String[] str =newString[] {"aaa", "bbb", "ccc" };
 5
 6     // 直接使用System.out.println无法打印出数组的内容
 7     System.out.println(arr); // 结果:[[email protected]
 8     System.out.println(str); // 结果:[Ljava.lang.String;@22adc446
 9
10     // 通过Arrays.asList方法打印出集合的内容
11     System.out.println(Arrays.asList(arr)); // 结果:[[[email protected]]
12     System.out.println(Arrays.asLsit(str)); // 结果:[a,b,c]
13
14     /*
15      * 原因是因为JDK1.4中为Arrays.asList(Object[] a),JDK1.5中为Arrays.asList(T... a)。
16      * arr是int[]类型,JDK1.4中的asList方法处理不了,JDK1.5可以处理。但是JDK1.5将 int数组整体作为一个参数进行处理。
17      * 因此最终结果就是将 int[]进行了封装,结果类型也就成了[[I。
18      */
19   }
20 }

 练习:利用反射原理写一个打印任意数值的方法。如果是数组,则遍历打印。

  代码:

 1 package com.itheima.day1;
 2 import java.lang.reflect.Array;
 3 public class ReflectTest4 {
 4
 5     public static void main(String[] args) {
 6         // TODO Auto-generated method stub
 7         int[] a1 = new int[]{1,2,3,4,5};
 8         printObject(a1);
 9         String str = "adc";
10         printObject(str);
11     }
12      //打印任意数值
13     private static void printObject(Object obj) {
14         Class clazz=obj.getClass();
15        //如果传入的是数组,则遍历
16         if(clazz.isArray()){
17            int len =Array.getLength(obj);//Array工具类获取数组长度方法
18             for(int x=0;x<len;x++){
19                 System.out.println(Array.get(obj, x));//Array工具获取数组元素
20             }
21         }
22         else
23             System.out.println(obj);
24     }
25 }

  

时间: 2024-09-30 09:35:16

黑马程序员------Java反射学习总结(一)的相关文章

黑马程序员------Java反射学习总结(二)

----------------------------Java培训.Android培训.期待与您交流! ------------------------------- ArrayList_HashSet的比较及Hashcode分析 看以下三段代码: 1.定义一个点类(Point) 1 package com.itheima.day1; 2 3 public class ReflectPoint { 4 private int x; 5 public int y; 6 7 public Refl

黑马程序员--java基础学习笔记5

黑马程序员--java基础学习笔记6 一.笔记内容概述: 数组-第二种定义格式.数组-常见操作-遍历-最值-选择排序-冒泡排序-排序位置置换代码提取.数组-排序的性能问题.数组-常见功能-查找-折半查找.进制转换-查表法-整合. 二.常用内容介绍: 1.数组初始化的三种方式: int[] arr = new int[3]; int[] arr = new int[]{1,2,3}; int[] arr = {1,2,3}; 2.查表法: 如果数据中出现了对应关系,而且对应关系的一方是有序的数字编

黑马程序员——JAVA面向对象学习总结

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- www.itheima.com 首先,面向对象是一种思想. 有一种面向过程的思想,面向对象就是基于面向过程的. 举个例子:把大象放进冰箱中. 面向过程: 用我们程序模拟 (java是纯面向对象语言) class Demo{ public static void main(String[] args){ /* 这几个动作相当于功能 既然是功能就用方法封装 */ //先打开冰箱门 open();

黑马程序员-Java 反射

--Java培训.Android培训.iOS培训..Net培训.期待与您交流!-- 一.概述 Java 反射机制是在运行状态中,对于程序中的任意一个类,通过反射机制都能够知道这个类的所有属性和方法,包括共有.包含.默认和私有.对于任意的一个对象,通过反射机制都可以去调用它的每一个方法,这种机制就称为Java的反射机制.一般的操作都在java.lang.reflect包中,常用到的类有Constructor,Field和Method三种.既然是对Java类的反射,当然也有个比不可少的类Class,

黑马程序员--Java基础学习笔记【单例设计模式、网络编程、反射】

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 设计模式分类: 创建模式:是对类的实例化过程的抽象化,又分为类创建模式和对象创建模式 类创建模式:工厂方法模式 对象-:简单工厂(静态工厂方法)模式.抽象工厂模式.单例模式.建造模式- 结构模式:描述如何将类或者对象结合在一起形成更大的结构 适配器模式.缺省模式.合成模式.装饰模式(包装模式).门面模式- 行为模式:对不同的对象之间划分责任和算法的抽象化 不变模式.策略模式.迭代子模式.命令模

黑马程序员---Java反射机制学习

由现在这个时间补上反射机制的学习笔记,本想报20期的JavaEE班,无奈真担心自己过不去,所以这段时间,一直的复习现在改报21期的吧!! 准备知识:一 1.Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method:    其中class代表的时类对象,    Constructor-类的构造器对象,    Field-类的属性对象,    Method-类的方法对象. 2.在Java中,每个class都有一个相应的Class对象.也就是说,当我们编写一

黑马程序员——JAVA数组学习总结

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- www.itheima.com 学习数组,学会如何声明,如何遍历,如何获取最值,还有交换,排序方法就差不多了,因为后期都是使用集合的更多. 一维数组1)   int[] a;   //声明,没有初始化 2)   int[] a=new int[5];   //初始化为默认值,int型为0 3)   int[] a={1,2,3,4,5};   //初始化为给定值 4)   int[] a=ne

黑马程序员---java反射机制的实现原理

------- android培训.java培训.期待与您交流! ---------- 反射机制就是java语言在运行时拥有一项自观的能力. 通过这种能力可以彻底的了解自身的情况为下一步的动作做准备. 下面具体介绍一下java的反射机制.这里你将颠覆原来对java的理解. Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method: 其中class代表的时类对象, Constructor-类的构造器对象, Field-类的属性对象, Method-类的方

黑马程序员--java反射

一句话总结反射:反射就是将java类中的各种成分映射成相应的java类 int.class与Integet.TYPE一样,都是返回int的Class实例 Class类里的 isPrimitive()方法是判断这个Class对象是否是基本类型(只有在9中情况下返回true,int.class...等8中基本数据类型和void.class) 通过Class类实例,可以将类中的构造方法(Constructor),成员变量(Field),成员方法(Method),包(Package),注释(Annota