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
}
}
l 数组类型的Class实例对象
Ø Class.isArray()
l 总之,只要是在源程序中出现的类型,都有各自的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);
}
}
}
好了,这些就是关于反射的一些知识点!!