黑马程序员------------------JAVA基础-------反射机制

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

1.1 Class类

什么是Class类?

java用类用于描述一类事物的共性,该事物有什么属性。

但是属性的具体的值是由对象确定的。那么java中的类也是一类事物,它都有成员变量,方法,构造器,这类事物就是用Class类描述的。

Class的实例是什么呢?是java类?其实java类从硬盘中加载进内存时,就会形成一个字节码文件,之后再用这个字节码去复制对象,所以这个字节码里有这个类的所有的信息。

Class类的实例就是这个字节码。


Class类的三种实例化方法:

1. 由类对象创建;

2 由类创建;

3由Class类的静态方法创建;

	Class cls1 = String.class;
	Class cls2 = Class.forName("java.lang.String");
	Class cls3 = new String().getClass();
注意:每个类的字节码在java虚拟机里都是唯一的,调用时java虚拟机会查看这个字节码是否已经加载,如果已经加载它就返回已经存在的字节码,如没有加载它才会用java的类加载器加载字节码缓存在虚拟机,然后把它返回。

Class有9 个预定义对象:8个基本数据类型和一个void的类型。

public static void main(String[] args) throws Exception{
		Class cls1 = String.class;
		Class cls2 = Class.forName("java.lang.String");
		Class cls3 = new String().getClass();
		System.out.println(cls1 == cls2);
		
		System.out.println(cls3 == cls2);	
		
		System.out.println(int.class == Integer.class);
		
		System.out.println(int[].class.isArray());
		
		System.out.println(cls1.isPrimitive());
		
		System.out.println(int.class.isPrimitive());
		
		Class cl = void.class;
输出结果:
true
true
false
true
false
true

Class类中方法摘要:

|--static Class<?>          forName(String className )    使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。

|--<A extends Annotation>  A         getAnnotation(Class<A> annotationClass)     如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。注释也是一个类!
|--Annotation[]      getAnnotations()             返回此元素上存在的所有注释。

|--Class<?>[]          getClasses()                 返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。 

|--ClassLoader getClassLoader()                                       返回该类的类加载器。

|--Constructor<T> Constructor<?>[] getConstructors() 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

|-- Constructor<?>[]     getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

|-- Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。

|-- Constructor<?>[] getDeclaredConstructors() 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。

|-- Method getMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

|-- Method[] getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口

|-- String getName() 以 String 的形式返回此 Class 对象所表示的实体。

|-- Class<? super T> getSuperclass() 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。

|-- boolean isArray() 判定此 Class 对象是否表示一个数组类。

|-- boolean isPrimitive() 判定指定的 Class 对象是否表示一个基本类型。

|--T newInstance() 创建此 Class 对象所表示的类的一个新实例。

1.2 反射 

反射是吧java类中个各个成分映射成相应的java类。

一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。
一个java类的组成成分:

成员变量---->Field,

方法--------->Method,

构造器------->Constructor.

等信息都被包装秤一个类。

2 Constructor类:

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


//String str = new String(StringBuffer("axdsf"));用反射实现创建一个这样的实例对象;
		Constructor constructor = String.class.getConstructor(StringBuffer.class);
		String str = (String)constructor.newInstance(new StringBuffer("axdsf"));
		System.out.println(str.charAt(2));
<span style="white-space:pre">		</span>输出:d



Constructor类中的方法摘要:

|--T   newInstance(Object... initargs)     使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

|-- String getName() 以字符串形式返回此构造方法的名称。 

|-- Class<?>[] getParameterTypes() 按照声明顺序返回一组 Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型。 

|-- T newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

3 Field 类: 代表某个类中的成员变量


public class ReflectPoint {
	private int x;
	public int y;
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 = "access";
	
	public ReflectPoint(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	@Override
	public String toString(){
		return str1 + ":" + str2 +":"+ str3;
	}
	
}

ReflectPoint pt = new ReflectPoint(3,5);
		Field fieldY = pt.getClass().getField("y");
		//此时的fieldY是类上的变量而不是对象上的,所以要关联对象;
		System.out.println(fieldY.get(pt));
		
		Field fieldX = pt.getClass().getDeclaredField("x");
		fieldX.setAccessible(true);
		//此时的fieldY是类上的变量而不是对象上的,所以要关联对象;
//		System.out.println(fieldX.get(pt));
//这样有些复杂 所以在Class类有一个newInstance()方法使用无参构造器构造实例; <span style="white-space: pre;">	<strong>	</strong></span>

输出结果:

5
3
Field类中的方法摘要:

|--Object get(Object obj) 返回指定对象上此 Field 表示的字段的值。 

|--setAccessible public void setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的布尔值。这是Field从其父类AccessibleObject继承过来的方法。

|--void set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

|-- Class<?> getType() 返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

如果要把ReflectPoint类中的String变量中的‘a’ 改为‘b’:

<span style="white-space:pre">	</span>public static void main(String[] args) throws Exception{
<span style="white-space:pre">		</span>changeStringValue(pt);
		System.out.println(pt);
<span style="white-space:pre">	</span><pre name="code" class="java">输出结果:bbll:bbsketbbll:bccess

} private static void changeStringValue(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.replaceAll("a", "b");//field 是类上的变量field.set(obj, newValue); //需要关联到对象,用set把新值设置到对象上}}}

 



4 Method类 代表某一个类的成员方法:

普通的方法调用时用对象或者类比如:

str.charAt(1); //普通调用方法;
用反射的方法:
Method method = Class.forName("java.lang.String").getMethod("charAt", int.class);  //参数为方法名(String类型),参数的类型(Class类型);
	System.out.println(method.invoke(str, 1));                            //调用的对象(str),以及实际传入的参数(1);
//	method.invoke(null, 2);//静态方法调用 不需要对象,所以是null;

Method类的方法摘要:

|-- Object invoke(Object obj, Object... args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。 

在jdk1.4中方法为  Object  invoke(Object obj, Object[]  args) 

|-- String getName() 以 String 形式返回此 Method 对象表示的方法名称 “

|-- int getModifiers() 以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。

一个小练习:用反射执行传入的类的main方法(类名作为参数传入)。

平时知道类名我们可以直接调用TestArguments.main(new String[]{"11","22","33","44"});

class  TestArguments{
	public static void main(String[] args){
		for(String arg : args)
			System.out.println(arg);
	}
}

但此时类名是一个传入的参数,我们并不知道,所以用反射的方法就很方便。

<span style="white-space:pre">		</span>String startingClassName = args[0];
		Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
//		mainMethod.invoke(null,new String[]{"11","22","33","44"}); //IllegalArgument
//		mainMethod.invoke(null, new Object[]{new String[]{"11","22","33","44"}});  //可以用
		mainMethod.invoke(null, (Object)new String[]{"11","22","33"});
输出:
11
22
33
调用时把TestArgument类名作为参数传入下面代码的主函数。此时运用第一个invoke会出现IllegalArgument异常,这是因为java把String[]数组拆包了,不是作为一个数组整体传入,我们有两种解决方法:
1 新建一个Object[]数组,里面的元素时String[]数组;
2 强制String[]数组转换为Object。

<strong>5 数组的反射</strong>:
<pre name="code" class="java">//数组的反射
	
int[] a1 = new int[]{1,2,3};
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[]{"as","ssss","sadada"};
System.out.println(a1.getClass() == a2.getClass());
/* System.out.println(a1.getClass() == a3.getClass());
System.out.println(a2.getClass() == a4.getClass());
System.out.println();*/
System.out.println(a1.getClass().getSimpleName());
System.out.println(a3.getClass().getName());
System.out.println(a4.getClass().getSimpleName());
System.out.println(a1.getClass().getSuperclass().getSimpleName());

System.out.println(a1);
System.out.println(a4);
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));

 
<span style="white-space:pre">		</span>Object aobj1 = a1;  //数组是object的之类
<span style="white-space:pre">		</span>Object aobj2 = a4;
//<span style="white-space:pre">		</span>Object[] aobj3 = a1;  //int  不是object    
<span style="white-space:pre">		</span>Object[] aobj4 = a4;
<span style="white-space:pre">		</span>Object[] aobj5 = a3;
<span style="white-space:pre">		</span>printObject(a4);
<pre name="code" class="java">private static void printObject (Object obj){
		Class clas = obj.getClass();
		if(clas.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);
	}

输出
 
true
int[]
[[I
String[]
Object
[I@70dea4e
[Ljava.lang.String;@5c647e05
[[I@70dea4e]
[as, ssss, sadada]
as
ssss
sadada
<span style="white-space:pre">		</span>

数组:具有相同数据类型和维数的数组类型是相同的





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值