Java反射总结

来源:互联网 发布:阿里云 华北 华东 华南 编辑:程序博客网 时间:2024/05/21 22:39

学习了反射,为了更加深入的了解反射的知识,下面我对反射的知识点进行一次小结

一、反射的基石为class

下面我们用一个特别实际的例子来了解一下

l

Person类代表人,它的实例对象就是张三,李四这样一个个具体的人, Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?

Ø       人-->Person

Ø       Java类-->Class

我们在定义一个普通的Person对象的时候是这样来实现的

Person p1 = new Person();

Person p2 = new Person();

但是如果我们想定义一个class对象是不是也可以像这样扶植呢?

Class cls1 = new Class();?这里我给出答案,是不能这样写的,在java里,是不允许这样赋值的的,同样也没有这种赋值的写法

那么我们该如何来实现呢?

我们来通过字节码来实现,如下

Class cls1 = 字节码;

那么什么是字节码呢?每一个字节码都是一个class的对象

如果说这里有三个对象,分别是:Person,Math,Date

那么我们就可以用字节码来实现

Class cls1 = Date.class;//Date.class代表Date类得字节码

Class cls2 = Person.class;//Person.class代表Person类得字节码

 

那么又是如何得到各个字节码对应的实例对象

 

Ø

Ø     类名.class,例如,System.class

Ø    对象.getClass(),例如,new Date().getClass()

Ø    Class.forName("类名"),例如,Class.forName("java.util.Date");//做反射的时候做多使用第三种

 

现在可以说是该了解的都已经了解了,那么我们来通过一个小的程序段来更好的了解反射

package cn.itcast.day1;

import java.lang.reflect.Constructor;

public class ReflectTest {

 
 public static void main(String[] args) throws Exception
 {
  String str1 = "abc";
  Class cls1 = str1.getClass();
  Class cls2 = String.class;
  Class cls3 = Class.forName("java.lang.String");
  System.out.println(cls1 == cls2);
  System.out.println(cls1==cls3);
  
  System.out.println(cls1.isPrimitive());//isPrimitive 判定指定的 Class 对象是否表示一个基本类型。打印结果为:false
  System.out.println(int.class.isPrimitive());//输出结果为:true
  System.out.println(int.class==Integer.class);//输出结果为false
  System.out.println(int.class==Integer.TYPE);//TYPE表示基本类型 int 的 Class 实例,输出结果为:true
  System.out.println(int[].class.isPrimitive());//输出结果为:false
  System.out.println(int[].class.isArray());//isArray判定此 Class 对象是否表示一个数组类。输出结果为:true
  
  Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
  String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
  //String str2 = (String)constructor1.newInstance("abc");Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch
  System.out.println(str2.charAt(2));//输出abc中的第二个字符,输出结果为c
 }

}

 

      数组类型的Class实例对象

Ø       Class.isArray()

      总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…

 


二、反射的概念

 反射就是把Java类中的各种成分映射成相应的java类。

 

例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

三、Constructor类 

1、Constractor代表某个类中的一个构造方法

2、得到某个类所有的构造方法

例子:Constructor[] constructors=

Class.forName("java.lang.String").getConstructors();

3、得到某一个构造方法

例子:Constructor constructor=

Class.forName("java.lang.String").getConstructor(StringBuffer.class);//获得方法时要用到类型

4、创建实例对象

例子:

通常方式:String str = new String(new StringBuffer("abc"));

反射方式:String str =(String)constructor.newInstance(new StringBuffer("abc"));//调用获得的方法时要用到上面相同类型的实例对象

5、Class.newInstance()方法:

例子:String obj = (String)Class.forName("java.lang.String").newInstance();

该方法内部先得到默认的构造方法,然后用构造方法创造实例对象。

6、下面是我们关于一个Constructor的具体实例

package cn.itcast.day1;

import java.lang.reflect.Constructor;

public class ConstructorTest
{

 
 public static void main(String[] args)throws Exception
 {
  String str ="abc";
  Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
  String str1 = (String)constructor1.newInstance(new StringBuffer("abc"));//我们可以在constructor1方法身上,调用好多次这个方法,每调用一次,就是new了一个新的方法
  System.out.println(str1.charAt(2));
 }

}

四、Field类

1、Field代表某个类中的一个成员变量

2、下面我们先来看一个关于Field类得例子

package cn.itcast.day1;

import java.lang.reflect.Field;

public class RefectPointTest {

 
 public static void main(String[] args)throws Exception
 {
  RefectPoint rf = new RefectPoint(3,5);
  Field fieldY = rf.getClass().getField("y");
  //fieldY的值是多少?5?错!fieldY不是对象身上的变量,而是类上的,要用它去取某个对象上对应的值
  
  System.out.println(fieldY.get(rf));
  
  Field fieldX = rf.getClass().getDeclaredField("x");//返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。name 参数是一个 String,它指定所需字段的简称。注意,此方法不反映数组类的 length 字段
  fieldX.setAccessible(true);//暴力反射
  System.out.println(fieldX.get(rf));
  changStringValue(rf);
  System.out.println(rf);
 }
 
 private static void changStringValue(Object obj)throws Exception
 {
  Field[] fields = obj.getClass().getFields();
  for(Field field:fields)
  {
   //field.getType().equals(String.class);
   if (field.getType()==(String.class))//比较同一份字节码要用等号
   {
    String OldValue = (String)field.get(obj);
    String NewValue = OldValue.replace('b', 'a');
    field.set(obj, NewValue);
   }
  }
 }

}
五、Method类

1、Method类代表某个类中的一个成员变量

2、得到类中的某一个方法:

例子:Method charAt=

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

3、调用方法

通常方法:System.out.println(str.charAt(1));

反射方法:System.out.println(charAt.invoke(str,1));

如果传递给Method方法的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!

4、下面是一个Method类的例子

package cn.itcast.day1;

import java.lang.reflect.Method;

public class MethodTest {

 
 public static void main(String[] args) throws Exception
 {
  String str1 = "abc";
  Method methodCharAt = String.class.getMethod("charAt", int.class);
  System.out.println(methodCharAt.invoke(str1, 1));
  
  System.out.println(methodCharAt.invoke(str1, new Object[]{2}));
 }

}
六、用反射方式执行类中的某个main方法

关于这个问题我们直接用一个案例来理解

package cn.itcast.day1;

import java.lang.reflect.Method;

public class MainTest {

 
 public static void main(String[] args)throws Exception
 {
  //TestArguments.main(new String[]{"111"});//这就是在程序里面用静态代码的方式直接调用他的main方法
  //以下是用反射的方式是实现
  String startingClassName = args[0];
  Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
  //张老师提供的方法
  //mainMethod.invoke(startingClassName, new Object[]{new String[]{"111","222","333"}});
  //李老师提供的方法是:
  mainMethod.invoke(startingClassName, (Object)new String[]{"111","222","333"});
 }
 
}
class TestArguments
{
 public static void main(String[] args)
 {
  for(String arg:args)
  {
   System.out.println(arg);
  }
 }
}

七、数组的反射

一、这些是应该注意的细节

1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。

2、代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class。

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

好了,既然我们已经把细节了解的差不多了,那么我们就要用一个实例来把这些细节体现出来

package cn.itcast.day1;

import java.lang.reflect.Array;
import java.util.Arrays;

public class RefectArray {

 
 public static void main(String[] args)
 {
  int[] a1 =new int[]{1,2,3};
  int[] a2 = new int[4];
  int[][] a3 = new int[3][4];
  String [] a4 = new String[]{"abc","def","gi"};
  System.out.println(a1.getClass() == a2.getClass());
  System.out.println(a1.getClass() == a3.getClass());
  System.out.println(a1.getClass() == a4.getClass());
  System.out.println(a1.getClass().getName());
  System.out.println(a1.getClass().getSuperclass().getName());
  System.out.println(a4.getClass().getSuperclass().getName());
  
  Object aObj1 = a1;
  Object aObj2 = a2;
  //Object[] aObj3 = a1;//基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用
  Object[] aObj4 = a3;
  Object[] aObj5 = a4;
  
  System.out.println(a1);
     System.out.println(a4);
    
     System.out.println(Arrays.asList(a1));
     System.out.println(Arrays.asList(a4));
    
     Object obj = null;
     printObject(a4);
     printObject("xyz");
     printObject(a1);
 }

 private static void printObject(Object obj)
 {
  Class clazz = obj.getClass();
  if(clazz.isArray())
  {
   int len = Array.getLength(obj);
   for(int i = 0; i<len;i++)
   {
    System.out.println(Array.get(obj, i));
   }
   
  }
  else
  {
   System.out.println(obj);
  }
 }

}
好了,这些就是关于反射的一些知识点!!

0 0