黑马程序员____基础加强____反射(框架的基石)

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

一,Java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class类。反射的基石:Class类。


二,对比提问:众多的人用一个什么类表示?众多的java类用一个什么类表示?比如以后要学习到的三大框架都要用到反射的技术

     1,人 ----->   Person 

     2java-->   Class


三,对比提问:Person类代表人这一个类,它的实例对象就是张三,李四这样的一个个具体的人,Class类代表java类,它的各个实例对象又分别对应什么呢?

     1,对应各个类在内存中的字节码【张老师说,*.class文件只有被类加载器加载到内存之后才称之为字节码】,例如,Person类的字节码,ArrayList类的字节码,等等。

     2,一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?


四,以后学习框架要用到反射的知识。


五,一个类所属的类的名字:Class(注意,这里是大写的),一个定义类的关键字:class


六,java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的,不同的实例有不同的属性值。java程序中的各个java类,它们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?这个类的名字就是Class,要注意与小写class关键字的区别哦。Class类描述了哪些方面的信息呢?类的名字、类的访问属性、类所属于哪个包、字段的名称列表、方法名称列表、以及它的父类等等。学习反射,首先就要明白Class这个类。


七,如何得到各个字节码对应的实例对象(Class类型)

    1,类名.class,例如:System.class。这是固定的写法,没有为什么。

 2,对象.getClass(),例如:new Date().getClass()。这是得到创建该对象的Class实例【即指向类Date的字节码的引用】。

 3,Class.forName("类名"),例如,Class.forName("java.util.Date")。这里要写完整的,导入包是没用的。这个静态方法,如果JVM里没有所要类名的类,则会用类加载器加载到jvm里缓存起来,在进行Class实例的获取;如果存在,则就不加载,直接获取。反射的时候主要用这种。这也是一个面试题!如果已经加载过,就不加载了!如果没有加载,则就加载。因此,可以说是查询(要加载的类的字节码已经存在)或加载(要加载的字节码不存在于JVM中)。在写程序的时候一般用这种,因为在写程序的时候还不知道类的名字。


八,九个预定义的Class实例对象:

     1,基本的8 Java 类型(booleanbytecharshortintlongfloat  double)和关键字 void 也表示为 Class 对象。 

     2,int.class==Integer.TYPETYPE代表包装类型所对应的基本类型的字节码(Class实例)

     3Class的实例.isPrimitive方法的帮助。该方法,如果其Class类型是基本数据类型的则反回truevoid类型的也反回true,否则返回false

     4public boolean isPrimitive()判定指定的 Class 对象是否表示一个基本类型。 有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double。 这些对象仅能通过下列声明为 public static final 的变量访问,也是使此方法返回 true 的仅有的几个 Class 对象。 返回:当且仅当该类表示一个基本类型时,才返回 true从以下版本开始: JDK1.1 另请参见:Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE


九,public boolean isArray()判定此 Class 对象是否表示一个数组类。 返回:如果此对象表示一个数组类,则返回 true;否则返回false。从以下版本开始: JDK1.1 


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


十一,示例代码:

package itheima.zhao;
public class ReflectTest {

	public static void main(String[] args) throws Exception {
		String str = "abc";
		Class c1 = String.class;
		Class c2 = str.getClass();
		Class c3 = Class.forName("java.lang.String");// 会抛出异常。
		System.out.println(c1 == c2);// true
		System.out.println(c1 == c3);// true
		System.out.println(c1.isPrimitive());// false
		System.out.println(void.class.isPrimitive());// true
		System.out.println(int.class.isPrimitive());// true
		System.out.println(int.class == Integer.class);// false
		System.out.println(char.class == Character.TYPE);// true
		System.out.println(int[].class.isPrimitive());// false
		System.out.println(int[].class.isArray());// true
	}
}


十二,反射就是把java类中的各种成份映射成相应的java。例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个java类来表示,就象汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class 类显然要提供一系列的方法来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是:Field  ,  Method ,Constructor ,Package等等。


十三,java的反射就是把java类的成份解析成相应的类。


十四,一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。


十五,class---->Class对象---->比如:Field对象--->某个成员变量。


十六,比如,一个类中所有方法属于Method类,而一个个具体的方法则就是一个Method类的一个个实例。


十七,利用反射获取构造函数:

      1public Constructor<?>[] getConstructors()

                                 throws SecurityException返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。如果该类没有公共构造方法,或者该类是一个数组类,或者该类反映一个基本类型或 void,则返回一个长度为 0 的数组。 注意,此方法返回 Constructor<T> 对象的数组(即取自此类构造方法的数组)时,此方法的返回类型是 Constructor<?>[],不是 预期的 Constructor<T>[]。此少量信息的返回类型是必需的,因为从此方法返回之后,该数组可能被修改以保存不同类的 Constructor 对象,而这将违反 Constructor<T>[] 的类型保证。 返回:表示此类公共构造方法的 Constructor 对象数组 抛出: SecurityException - 如果存在安全管理器 s,并满足下列任一条件: 调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝访问该类中的构造方法 调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包 从以下版本开始: JDK1.1 

     2 public Constructor<T> getConstructor(Class<?>... parameterTypes)//可变参数的方法。因此说参数是数组。

                              throws NoSuchMethodException,

                                     SecurityException返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声明顺序标识构造方法的形参类型。 如果此 Class 对象表示非静态上下文中声明的内部类,则形参类型作为第一个参数包括显示封闭的实例。 要反映的构造方法是此 Class 对象所表示的类的公共构造方法,其形参类型与 parameterTypes 所指定的参数类型相匹配。 参数:parameterTypes - 参数数组 返回:与指定的 parameterTypes 相匹配的公共构造方法的 Constructor 对象 

抛出: 

NoSuchMethodException - 如果找不到匹配的方法。 

SecurityException - 如果存在安全管理器 s,并满足下列任一条件: 

调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝访问构造方法 

调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包 

从以下版本开始: 

JDK1.1 

       3,这个是Constructor类里的方法:public T newInstance(Object... initargs)

              throws InstantiationException,

                     IllegalAccessException,

                     IllegalArgumentException,

                     InvocationTargetException

      使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。个别参数会自动解包,以匹配基本形参,必要时,基本参数和引用参数都要进行方法调用转换。



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

     1,得到某个类所有的构造方法:(数组的中括号最好放在类型的后面,这样一看就知道是某类型的数组)

               例子:Constructor[]   constructors=Class.forName("java.lang.String").getConstructors();得到的所有的构造方法会装在constructor[]数组里面。

     2,得到某一个构造方法:

      例子:Constructor  constructor =Class.forName("java.lang.String").getConstructor(StringBuffer.class);

        //获得具体的构造方法时要用到类型。这个方法会抛出异常。

public   Constructor<T>    getConstructor(Class<?>... parameterTypes)//JDK1.4及以前的版本是这里不是用可变参数来表示,而是用数组来表示的!

                              throws NoSuchMethodException,

                                     SecurityException

返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声明顺序标识构造方法的形参类型。 如果此 Class 对象表示非静态上下文中声明的内部类,则形参类型作为第一个参数包括显示封闭的实例。 要反映的构造方法是此 Class 对象所表示的类的公共构造方法,其形参类型与 parameterTypes 所指定的参数类型相匹配。

参数:

parameterTypes- 参数数组

返回:

与指定的 parameterTypes 相匹配的公共构造方法的 Constructor 对象

抛出:

NoSuchMethodException如果找不到匹配的方法。

SecurityException如果存在安全管理器 s,并满足下列任一条件: 

§ 调用 s.checkMemberAccess(this, Member.PUBLIC) 拒绝访问构造方法

§ 调用者的类加载器不同于也不是当前类的类加载器的一个祖先,并且对 s.checkPackageAccess() 的调用拒绝访问该类的包

     3,创建实例对象:

           通常方式:String str=new String(new StringBuffer("abc")); 

           反射方式:String str=(String)constructor.newInstance(new StringBuffer("abc"));        

       //调用获得的方法时要用到上面相同类型的实例对象。

     4Class的实例.newInstance()方法:如果不用这个方法也不会影响Java的开发。

           1,例子:String obj=(String)Class.forName("java.lang.String").newInstance();

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

           3,该方法内部的具体代码是怎么写呢?用到了缓存机制来保存默认构造方法的实例对象。

           4,如果想要得到没有参数的对象,则用这个比较好。反射比较耗时!!!导致程序性能下降。因此,如果要调用无参的构造方法则用这个方法比较好。

     5,示例代码:

package itheima;

import java.lang.reflect.*;

public class ReflectTest {

	public static void main(String[] args) throws Exception {
		// new String(new StringBuffer("abc"));
		Constructor constructor = // 编译器只看代码的定义,不看代码的执行。编译时,和运行时。
		Class.forName("java.lang.String").getConstructor(StringBuffer.class);// StringBuffer表示选择哪个构造方法。
		// 意思是:用constructor这个构造方法来创建一个String类型的对象,newStringBuffer("abc")是
		// 给constructor这个构造方法传递一个具体的参数。因为没有用泛型,所以得进行强转。返回的是Object。每调用一次,就创建一个对象。如果:String
		// str=(String)constructor.newInstance("abc");这样是错误的,因为该构造方法要接收的是StringBuffer类的实例。因此,类型得匹配。
		String str = (String) constructor.newInstance(new StringBuffer("abc"));// 传一个StringBuffer的对象!
		System.out.println(constructor);// public
										// java.lang.String(java.lang.StringBuffer)
		System.out.println(str.charAt(2));// c
		Class cl = constructor.getDeclaringClass();// 得到该构造方法所属的类的字节码实例。
		System.out.println(cl);// class java.lang.String
	}
}


十九,成员变量的反射:

package test;

import java.lang.reflect.*;

public class ReflectTest {

	public static void main(String[] args)throws Exception {
		ReflectPoint r1=new ReflectPoint(3,5);
		Field fieldY =r1.getClass().getField("y");//这里写成员变量名。
		//filedY不代表某个对象上的字段值,它只是表示ReflectPoint这个类里的一个成员变量。
		//如果想获取某个对象上的值则应该采用下面的方法。
		System.out.println(fieldY);//public int zhao.tai.ReflectPoint.y  完整的类名.成员变量。
		System.out.println(fieldY.get(r1));//5 传递get的参数得是某一个类的具体实例。比如,这里的r1。也就是说,get方法在不同的对象上所取出来的值是不一样的。
		Field fieldX=r1.getClass().getDeclaredField("x");//强力得到私有的。
  		System.out.println(fieldX);//private int zhao.tai.ReflectPoint.x   完整的类名.成员变量。
		fieldX.setAccessible(true);//可以强力获取得到r1对象上私有成员变量x的值。暴力反射!!!
		System.out.println(fieldX.get(r1));//3
	}
}

class ReflectPoint {
	private int x;
	public int y;

	public ReflectPoint(int x, int y) {// 这是用MyEclipse自动生生成的构造方法。
		super();
		this.x = x;
		this.y = y;
	}
}


二十,成员方法的反射:

package test;
import java.lang.reflect.*;
public class ReflectTest {
	public static void main(String[] args)throws Exception {
		//返回的methodCharAt是一个Stirng类里的方法,chaAt方法的参数也得用int.class类型来表示。
		String str="abc";
		//str.charAt(1);
		Method methodCharAt=String.class.getMethod("charAt", int.class);
		Object ch1=methodCharAt.invoke(str,1);//str对象调用String类中的methodCharAt方法。
		if(ch1 instanceof Character){
			Character ch=(Character)ch1;
			System.out.println(ch);//b
		}
		//new Object[]{new Integer(2)}//因为可以自动装箱。JDK1.4形式的。new Object[]{2};和前面的是一样的。
		System.out.println(methodCharAt.invoke(str, new Object[]{2}));//c
	}
}


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

详情请查看:http://edu.csdn.net/heima

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值