`
jiao13953900900
  • 浏览: 32461 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

黑马程序员-反射机制

    博客分类:
  • java
阅读更多

---------------------- android培训java培训、期待与您交流! ----------------------

 

  

 

黑马程序员-反射机制

 

 

反射

Java程序中的各个java类属于同一类事物,描述这里类的java类就叫做Class。

Class类代表Java类,它的各个示例对象分别在对应各个类在内存中的字节码。

什么是字节码?

一个类被加载器加载到内存中占有一片存储空间,这个空间里面的内容就说字节码;

不同类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个空间可以分别用故意个个对象来表示,且这些对象具有相同的类型Class类。

如何得到字节码对应的示例对象(Class类型)?

有三种方式:

1.类名.class 

如:Person.class;

2.对象.getclass();

如:得到创建该对象的字节码:new Demo().getClass(); 

3.Class.forName():

如: Class.forName("Java.util.date");返回字节码。

forName()方法先在内存中判断有没有字节码,有就返回,没有就用类加载器加载一个,然后在返回。

 

java中一共有九个预定义的Class示例对象:

boolean byte char short int long float double 和 void.

使用Class.isprimitive可以判断指定的class对象是不是基本类型。

int.class==Integer.TYPE比较结果为 true 。因为Integer返回的是int数值的字节码。

数组类型的class示例对象,class.isArray();

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

反射是什么呢?

反射 就是把java类中的各种成分映射到相应的java类,如,一个java类中用一个Class类的对象来表示,一个类中的组成部分,成员变量,方法,构造方法。包等信息,也用一个个的java类来表示

java类的class类提供了一些方法来获取其中的变量方法,构造方法,修饰符,包等信息,这些信息用相应类的示例对象来表示,Fild  Method  Contructor  Package。

 

Constructor类 代表某个类中的构造方法

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

Constructor[] constructors=Class.forName("Java.lang.String").getConstructors();

得到某一个构造方法,获取参数类型为StringBuffer类型的构造方法。

Constructor constructor=Class.forName("Java.lang.String").getConstructor(StringBuffer.Class);

创建实例对象

通常方法:

String str=new String(new StringBuffer("abc"));

反射方法:

String str1=(String) Constructor.newInstance(new StringBuffer("abc"));

再调用获得的构造方法时,要用到上面相同的实例对象,

Class.newInstance()方法

String obj=() Class.forName("Java.lang.String").newInstance();

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

该方法内部用到了缓存机制,来保存默认构造方法的示例对象。

 

 

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

ReflectPoint pt1=new ReflectPoint(3,5);

//在构造方法中传入3.5

Field fieldY=pt1.getClass().getField("y");

//把要去的变量以字符串的方式传入

//fieldY取出来的不是对象身上的变量,而是类上的,要用它去取某个对象对应的值。

sop(field.get(pt1));

//使用对象的.get(pt1);方法取对象的值。

如果要去的对象变量的值是私有的,那么该怎么办呢,不用担心,java为我们提供了获取私有变量的方法:getDeclaredDield().和setAccessible().

//获取X的值,可以取出私有变量

Field fieldX=pt1.getClass().getDeclaredDield("x");

//获取私有变量的值,有称为暴力反射

fieldX.setAccessible(true);

//打印X值

sop(fieldX.get(pt1));

字段反射

如果要把一个类中的所有String类型的成员变量中的b替换为a怎么实现呢?

public static void changeStringValue(Object obj) Throws Exception

{//将所有的成员变量存入数组

Field[] fields=obj.getClass().getFields();

//对数组进行遍历

for(Field field: fields)

{//使用==比较两个类型的字节码

if(field.getTYPE()==String.class)

{

//取出对象的值

String oldValue=() field.get(obj);

//把旧的值用薪的代替,replace用于替换某一个字符

String newValue=oldValue.replace('b','a');

//将对象的值设置为newValue

field.set(obj.newValue);

}

}

}

在对两个字节码进行比较是否相同时,使用==进行比较,因为有肯能是同一个字节码

 

 

 

 

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

//getMethod参数为一个字符串和一个int.class.

Method methodCharAt=String.class.getMethod("charAt",int.class);

//传入一个字符串对象和要取的位置

sop(methodCharAt.invoke(str1,1);

调用方法:

1.通常方法:

sop(str.charAt());

2.反射方法:

sop(charAt.invoke(str,1);

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

JDK 1.5与JDK 1.4 invoke方法的区别:

JDK 1.5:使用的是可变参数

public Object invoke(Object obj,Object... args);

JDK 1.4:public Object invoke(Object obj,Object[] args);

在这之前没有可变参数,按 1.4的语法需要将一个数组作为可变参数传递给invoke方法时,数组中的每一个元素分别对应被调用方法的一个参数,所以,调用charAt方法的代码也可以用 1.4改写为charAt。invoke("str",new Object[]{1});

 

 

反射的方式执行某个类中的main方法。

用静态方法:类名.main(new String[]{})//也可以传入参数

用反射的方法:

//将要启动的类的参数

String stringClassName=args[0];

//根据名字和参数类型获取main

Method mainMethod=Class.forName(stringClassName).getMethod("main",String[].class)

mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});

//让他解包一次后还是我们需要的参数或者向下面那么写

mainMethod.invoke(null,(Object)new String[]{"111","222","333"});

//使用强转的方式是参数正确传递

为什么需要使用反射的方式调用main方法呢??

当要调用的main的所在类名字不能确定,或有多个main方法,不能确定调用哪一个main的时候,可以使用反射的方式,使用参数列表来进行选择要调用的main()

在启动Java程序的时候,main方法的参数上一个字符串数组,String[] args,当通过反射的方式调用这个main方法时,如何为invoke方法传递参数呢,按JDK 1.5,整个数组是一个参数,而按JDK 1.4,的语法,数组腮红的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,Java会按照哪种方式进行处理呢??因为1.5要向下兼容1.4的内容,所以会按1.4的语法基尼系那个处理,即把数组打散为若干个单独的参数,所以我们要以1.4的处理方式进行处理。

 

/*反射
 * java程序中的各个java类同属于一类事物,描述这一类事物的java类就是Class
 * Class代表java类,它的各个实例对象分别对相应各个类在内存中的字节码
 * 
 * 
 * */


package fs1;

import java.lang.reflect.*;
import java.util.*;

import java.*;
class Person{
	private String name;
	private int age;
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	
	
}
public class fanshe {

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		String s1="abc";
		sop(Person.class);
		Person p=new Person("lisi",23);
		//sop(Person.getClass());
		System.out.println(123);
		
			//sop(Class.forName("Java.lang.String"));
		Class c1=String.class;
		Class c2=s1.getClass();
		Class c3=Class.forName("java.lang.String");
		sop(c1==c2);
		sop(c1==c3);
		sop(c3==c2);
		
		sop(new String("abc").getClass().getFields());
		List l1=new ArrayList();
		Constructor[] cons=Class.forName("java.lang.String").getConstructors();
		//获取构造方法。可以通过构造方法构造实例对象,得到方法的时候需要参数列型
		Constructor cons1=String.class.getConstructor(StringBuffer.class);
		//用获取的构造方法创建实例对象,调用活动的方法时,也需要有类型
		String  str2=(String) cons1.newInstance(new StringBuffer("abc"));
		sop(str2.charAt(2));
		ReflectPoint pt1=new ReflectPoint(3,5);
		//该方法只有私有的草可以获得
		Field fieldY=pt1.getClass().getField("y");
	
		sop(fieldY.get(pt1));
		Field fieldX=pt1.getClass().getDeclaredField("x");
		fieldX.setAccessible(true);
		sop(fieldX.get(pt1));
		changeStringValue(pt1);
		sop(pt1);
		//Method类,代表某一个类中的成员方法
		Method methodCharAt=String.class.getMethod("charAt", int.class);
		sop(methodCharAt.invoke(s1, 1));
		//获取main方法
		String startingClassName=args[0];
		Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class);
		//使用一下两种方式调用main方法
		//把整个数组打包为一个数组,因为为了兼容1.4要对数组进行依次解包
		mainMethod.invoke(null, new Object[]{new String[]{"11","22","33"}});
		//生命该数组是一个对象
		//mainMethod.invoke(null, (Object)new String[]{"11","22","33"});
		int[] a1=new int[]{1,2,3};
		int[] a2=new int[4];
		int[][] a3=new int[2][3];
		String[] a4=new String[]{"a","b","c"};
		//对象要得到字节码组要使用方法,不能直接用。class获取
		sop(a1.getClass()==a2.getClass());
		sop(a1.getClass()==a3.getClass());
		sop(a1.getClass()==a4.getClass());
		sop(a1.getClass().getName());
		sop(a1.getClass().getSuperclass().getName());
		Object Obj1=a1;
		Object Obj2=a4;
		//基本数据类型的数组是无法装入Object数组中的
		//Object[] Obj3=a1;
		Object[] Obj4=a3;
		Object[] Obj5=a4;
		sop(a1);
		sop(a4);
		//int类型的数组不能传入Object【】中,
		sop(Arrays.asList(a1));
		sop(Arrays.asList(a4));
		Object obj=null;
		printObject(a1);
		printObject("abc");
		
		
	}
	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++){
				sop(Array.get(obj, 1));
			}
		}else{
			sop(obj);
		}
		
	}
	private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
		Field[] fields=obj.getClass().getFields();
		for(Field field: fields){
			//使用==比较两个字节码,因为两个字节码有可能是同一个
			if(field.getType()==String.class){
				String oldValue=(String) field.get(obj);
				String newValue=oldValue.replace('b', 'a');
				field.set(obj, newValue);
			}
		}
		
	}
	public static void sop(Object obj){
		System.out.println(obj);
	}

}
class Test{
	public static void main(String[] args){
		System.out.println(123);
		}
	}

 

 

 

 

 

 

---------------------- android培训java培训、期待与您交流! ----------------------

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics