反射
类名为Class的类用来描述众多Java类的类,
Class不能直接new对象。
Class cls1 = Data.class//字节码1
Class cls2 = Person.class//字节码2
先有字节码,然后由字节码生成对象,
得到字节码的3种方式:
1.类名.class
2.对象.getClass()
3.Class.forName("类名");//常用,写程序时不用明确具体的类
有9个预定义Class实例对象:
8个基本类型加一个void.class
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
cls1==cls2==cls3
同一个类的字节码文件相同
基本类中的字节码除了如int.class外,还有
Boolean.TYPE , Character.TYPE ,Byte.TYPE,
Short.TYPE, Integer.TYPE , Long.TYPE,
Float.TYPE ,Double.TYPE , Void.TYPE
int.class !=Integer.class
int.class == Integer.TYPE
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和
关键字 void 也表示为 Class 对象。
数组类型的Class实例对象:
Class.isArray();判断是不是数组类型Class.
只要在源程序中出现的类型,都有各自的Class实例对象,如int[],void..。
反射就是把Java类中的各种成分映射成相应的Java类
Constructor类
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//获得方法时,也就是告诉选择哪一个构造方法
String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));//调用获得的方法时,传递的构造函数
需要强转,因为编译时只有语法检查,不知道constructor类型,
反射会导致程序性能严重下降。
Field类
表示类中的变量的类
ReflectPoint pt1 = new ReflectPoint(3,5);//ReflectPoint中定义了两个变量,y公有,x私有
Field fieldY = pt1.getClass().getField("y");//Field表示字节码中的一个变量(相同类中的特定变量),通过方法访问具体实例对象的值
System.out.pirntln(fieldY.get(pt1));//
Field fieldX = pt1.getClass().getDeclaredField("x");//使私有X变得可见
fieldX.setAccessible(true);//使私有X变得可以访问,暴力反射
System.out.pirntln(fieldY.get(pt1));//
反射的应用
Field[] = fields = obj.getClass().getFields();//obj是形参
for(Field field : fields)
{
//一份字节码,用“==”,因为equal也是用的"=="
if(field.getType() == String.class)
{
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b','a');
field.set(obj, newValue);
}
}
Method类
(方法名字,参数类型)
Method methodCharAt = String.class.getMethod("charAt",int class);
sop(methodCharAt.invoke(str1,1)); //invoke调用(对象,参数)
对象是null,调用的是一个静态方法
sop(methodCharAt.invoke(str1,new Object[]{2}));
写程序调用main方法
class TestArguments
{
public static void main(String[] args)
{
for(String arg : args)
System.out.println(arg);
}
}
直接调用
TestArguments.main(new String[]{"111","222","333"});
反射方式调用
问题:
启动Java程序的main方法参数是一个字符串,通过反射方式调用main方法时为invoke传递参数按照Jdk1.5,整个数组是一个参数;
按照jdk1.4语法,数组中每个元素对应一个参数,而高版本会兼容低版本,处理时会按照1.4版本将参数数组拆分如果直接传递,
new String[]{"xxx"}会出现参数类型不对的错误。
解决方法:
1.将数组外再套一个数组
mainMethod.invoke(null, new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"});
具有相同的元素类型和相同维度的数组具有相同的Class对象
int[] a1 = new int[3];
int[] a2 = new int[4];
int[][] a3 = new int[3][4];
String[] a4 = new String[3];
a1.getClass() == a2.getClass();true
a1.getClass() == a4.getClass();false
a1,getClass() == a3.getClass();false
a1.getName()-----运算结果:[I
a1.getClass().getSuperclass().getName();求其父类名运算结果:java.lang.object
a4.getClass().getSuperclass().getName();求其父类名运算结果:java.lang.object
Object aobj1 = a1;
Object aobj2 = a2;
Object[] aobj3 = a1;//不通过
Object[] aObj4 = a3;
Object[] aObj5 = a4;
int[] a1 = new int[]{1,2,3};
String a4 = new String[3]{"a","b","c"};
System.out.println(a1);//运行结果:[I@哈希码
System.out.println(a4);//运行结果:[Ljava.lang.String;@哈希码
System.out.println(Array.asList(a1));//运行结果:[[I@哈希码]
不是object数组对象按jdk1.5当做object作为一个参数传递
System.out.println(Array.asList(a4));//运行结果:[a,b,c]
object对象按jdk1.4版本将各元素拆分传递给List
数组反射应用(打印object)
<span style="font-size:14px;">private atatic void printObject(Object obj)
{
Class class = obj.getClass();
if(class.isArray())
{
int len = Array.getLength(obj);
for(iint i; i<len;i++)
{
System.out.println(Array.get(obj,1));
}
}
else
{
System.out,println(obj);
}
}
</span>
如何得到数组中元素的类型?
不能直接通过a得到a的类型
int[] a = int[3];
能通过a中的元素获得元素的类型
a[0].getClass().getName();