张孝祥J2SE加强自学笔记(17-24)

17、透彻分析反射的基础类Class类:
Person p1 = new Person();
Class cls1 = java.util.Date.class //字节码1
Class cls2 = Person.class //字节码2
Class cls3 = p1.getClass()


当.java的源程序文件编译完成后,会编译成.class的字节码文件 当某个字节码文件要执行的时候首先会被load到内存
然后用这些字节码文件创建相应的对象。
面试题:Class.forName()的作用:
答:他的作用就是返回类的字节码,而返回的方式有两种,一种是这个类曾经加载过已经加载到JVM当中来了,那么可以直接得到 例如:p1.getClass()
或者Person.class就可以拿到字节码,另外一种方式是还没有加载过,要通过类加载器将它加载上来然后把它缓存起来例如:Class.forName(java.lang.String);
相同类型的类的字节码只有一份如:下面str1 = "abc"的例子就能说明这一点!!
代码举例:
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");
//true
System.out.println(cls1 == cls2);
//true 得到的都是String类的字节码
System.out.println(cls1 == cls3);

//String.class是不是原始类型:false String 是一个类它不是原始类型
System.out.println(cls1.isPrimitive());
//Integer是int的包装类,所以false
System.out.println(int.class == Integer.class);
//Integer.TYPE返回的字节码指的是他所包装的那个类int的字节码,true
System.out.println(int.class == Integer.TYPE);
//整型数组他是数组类型他不是原始类型,所以最后一句是true,下面一句是false
System.out.println(int[].class.isPrimitive());
System.out.println(int[].class.isArray());

}
总结:得到各个字节码对应的实例对象(Class类型)
(1)类名.class 例如:System.class
(2)对象.getClass() 例如:new Date().getClass()
(3)Class.forName("类名"),例如:Class.forName("java.lang.String");

九个预定义的Class实例对象:八种基本类型的.class + void.class void也是一种类型

18、理解反射的概念:的反射就是把Java类中的各个成分映射成相应的Java类

19、构造方法的反射应用:
代码举例:
//String.class拿到的那份字节码文件然后再得到他的一个参数为StringBuffer的那个构造方法
Constructor construct = String.class.getConstructor(StringBuffer.class);
//根据得到的这个构造方法,构造一个对象
String abc = (String) construct.newInstance(new StringBuffer("abc"));
System.out.println(abc);
注意:反射的应用会导致程序的性能下降,因为他在内部处理的时候要缓存对象。

20、成员变量的反射:
举例代码:
//定义实体类
public class ReflectionPoint {
private int x;
public int y;

public ReflectionPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
//测试代码
ReflectionPoint rp = new ReflectionPoint(3,5);
//通过反射拿到RelectionPoint这个类的y成员变量
Field pointY = rp.getClass().getField("y");
//此时通过反射拿到的这个属性是属于整个类的,不属于某个对象,所以如果直接打印是打印不出具体的值的
//如果想得到具体的值必须用get(Object obj)方法来说明取得的是那一个对象的值
System.out.println(pointY.get(rp));

//通过反射拿到RelectionPoint这个类的x成员变量
//Field pointX = rp.getClass().getField("x");
//如果用上面这句话来拿到x成员变量的话会出错,因为x是private的所以在外部是看不到这个方法的(NoSuchMethodExcepion),
//所以用getDecleardField()方法
//意为拿到类中声明过的变量,只要你在类中声明了不管是否是私有的,我都能拿到这个值
Field pointX = rp.getClass().getDeclaredField("x");
//设置x这个变量的访问权限为“可以访问”,虽然在上一句代码中我们已经拿到了x变量,但它是私有的还不能访问
//所以在更改了他的访问权限之后才能够打印他的值。
pointX.setAccessible(true);
System.out.println(pointX.get(rp));

21、成员变量反射的综合案例: 将一个类中的String类型的成员变量的值中包含字符b的都替换成字符a
示例代码:
//定义实体类
public class ReflectionPoint {

private int x;

public int y;

public String str1 = "ball";

public String str2 = "basketball";

public String str3 = "itcast";

public ReflectionPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}

@Override
public String toString() {

return "str1:" + str1 + "str2:" + str2 + "str3:" + str3;
}
}
//测试代码:
public static void main(String[] args) {
ReflectionPoint rp = new ReflectionPoint(3,5);
changeStringValue(rp);
System.out.println(rp);
}

private static void changeStringValue(ReflectionPoint rp) throws Exception {
Field[] fields = rp.getClass().getFields();
for(Field field : fields) {
//此处比较的时候比较的是字节码:因为字节码只有一份所以用==比较合适,而不适合
//用equals虽然也能够得出正确的结果
if(field.getType() == String.class) {
String oldValue = (String)field.get(rp);
String newValue = oldValue.replace('b', 'a');
field.set(rp, newValue);
}
}
}

22、成员方法的反射:调用String类的charAt方法
示例代码:
String str1 = "abc";
Method method = String.class.getMethod("charAt", int.class);
System.out.println(method.invoke(str1, 1));
//自动拆箱和装箱会将new Object[]{1}封装成一个Integer类型的对象
System.out.println(method.invoke(str1, new Object[] {1}));

23、对接受数组参数的成员方法进行反射:
代码示例:
问题:通过反射的方式来调用TestArgments类的main方法时如何为invoke方法传递参数呢?按照jdk1.5的语法
整个数组是一个参数,当把一个字符串数组作为参数传递给invoke方法,javac会到底按照哪种语法进行处理呢
jdk1.5肯定要兼容jdk1.4的语法,会按照1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以在给main
方法传递参数的时候,不能使用代码main.invoke(null, new String[]{"xxx"}),javac只把他当做jdk1.4的语法进行
理解,而不把他当做jdk1.5的语法进行理解,因此会出现参数类型不对的问题。
解决办法:
(1)main.invoke(null, (Object)new String[]{"xxx"});
(2)main.invoke(null, new Object[]{new String[]{"xxx"}));
编译器会做特殊的处理,编译时不会把参数当做数组来看待,也就不会把数组打散成若干个参数了.


public class ReflectionTest {
public static void main(String[] args) throws Exception{
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
mainMethod.invoke(null, (Object)new String[]{"123", "222","33"});

}

class TestArguments{
public static void main(String[] args){
for(String arg : args){
System.out.println(arg);
}
}
}
24、数组与Object的关系及其反射类型:
示例代码:
int[] a1 = new int[]{1,2,3};
int[] a2 = new int[5];
int[][] a3 = new int[2][3];
String[] a4 = new String[]{"a","b","c"};
//true.因为同样都是数组类型且维数一样,他们的字节码肯定一样.
System.out.println(a1.getClass() == a2.getClass());
//false.虽然都是数组类型,但是数组的维数不一样,在1.5的编译器中甚至不能变异通过,说是
//不兼容的操作数类型
System.out.println(a2.getClass() == a3.getClass());
System.out.println(a1.getClass().getName());
//false.数据的类型不一样,那么他们字节码的name当然不一样
System.out.println(a1.getClass().getName() == a4.getClass().getName());

Object aObj1 = a1;
Object aObj2 = a4;
Object[] aObje3 = a3;
//Object[] aObje4 = a1;
Object[] aObje5 = a4;
总结:
(1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象
(2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
(3)基本类型的一维数组可以被当做Object类型来使用,不能当做Object[]来使用,因为int
属于基本类型.非基本类型的一维数组既可以当做Object类型使用有可以当做Object[]来使用
(4)Arrays.asList()方法处理int[]和String[]时的差异:
//在jdk1.4中asList方法的定义:public static List asList(Object[] a);
//在jdk1.5中asList方法的定义:public static List<T> asList(T ... a);
//当我们传递a1的时候,因为a1是一个int[]不能转化为Object[],所以不能满足jdk1.4中方法参数的
//定义标准,转而交给jdk1.5所定义的方法来处理,在jdk1.5的定义中参数是一个可变的参数列表,会把
//a1看成是一个对象,所以转化为List之后打印出来就是[[I@de6ced],而传递a4的时候因为a4是String[],他符合jdk1.4方法
//中定义的参数类型Object[],因为jdk1.5要兼容1.4所以会首先按照jdk1.4所定义的方法来执行转换成List后
//打印结果为:[a, b, c]
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));//[a, b, c]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值