------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------
反射技术
反射就是在程序运行过程中,通过.class文件动态的获取类的信息(属性,构造,方法),并调用
注意:JAVA不是动态语言,因为动态语言强调在程序运行过程中不仅能获取并调用类里面的属性和方法,还要求能够给类增加属性和方法,而JAVA中的反射只能获取调用,不能修改类的结构
java.lang.reflect.Constructor:构造方法管理器,通过该对象的newInstance方法能有创建构造方法.
在反射中包含Declared的方法表示获取私有的成员内容,一般结合setAccessible(true)方法一起使用.
反射就是将JAVA类中的各个成分映射成相应的JAVA类
JAVA中九个预定义的实例对象
基本数据类型(byte、boolean、short、int、long、double、float、char)字节码对象以及void.class
另外:具有相同的数据类型和维度的数组在java中映射成同一个Class对象
判断是否为数组类型,用Class.isArray()方法
(1)案例
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.*;
import java.util.*;
class banana{
private int x;
private int y;
public void banana(int x,int y)
{
this.x=x;
this.y=y;
}
}
class apple {
public static void main(String[] args)throws Exception{
// TODO Auto-generated method stub
String str="123456";
//获取Class对象方法
Class a1=String.class;//通过所有数据类型都有静态属性.class来获取
Class a2=str.getClass();//通过对象getClass()方法获取
// Class.forName(包名.类名);
Class a3=Class.forName("java.lang.String");//通过Class类的静态方法forName()和获得Class对象的类名来获取
System.out.println((a1==a2));
System.out.println((a1==a3));
System.out.println((a2==a3));
/*Constructor类。。。。。构造方法的反射、Constructor的实例对象代表类的一个构造方法
用constructor类创建实例对象(反射创建)
注意:1.创建newInstance方法中的参数列表必须与Constructor类中的getConstructor()方法中的参数列表一致;
2.每调用一次newInstance方法,即构造一个对象
3.可以指定构造函数
*/
//获取一个类中所有的构造方法
//Constructor[] b1=Class.forName("java.lang.String").getConstructors();
//获取一个类中的某一个构造方法
Class b2=Class.forName("java.lang.String");
Constructor b22=b2.getConstructor(StringBuffer.class);
//String s1="456";//一般实例化对象
//String b3=(String)constructor.newInstance(new StringBuffer("456"));//通过反射实例化对象
/*
Field类。。。。。。(成员变量的反射)
常用的方法:
1.Field getField(String s);//只能获取该类公有和父类中公有
2.Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有
3.setAcessible(true);如果是私有字段,要先将私有字段进行取消权限检查的能力。也称暴力访问
4.set(Object obj,Object value)将指定对象变量上此Field对象表示的字段设置为指定的新值
5.Object get(Object obj);返回指定对象上Field表示的字段的值
*/
Method类。。。。。。(成员方法的反射):代表某个类中的一个成员方法
* 常用方法:
* 1.Method[]getMethods();只获取公共和父类中的所有方法
* 2.Method[]getDeclaredMethods();获取本类中方法包含私有方法
* 3.Medthod[]getMethod("方法名",参数.class(空参可以写null));
* 4.Object invoke(Object obj,参数);调用方法:如果方法是静态的,invoke中的参数可写为null
*
* 通过反射来调用main函数,invoke()方法传递一个字符串数组参数的方法
* 1.me.invoke(null,new object[](new String[]{“11”,“22”,“33”}));
* 2.me.invoke(null,(Object)new String[]{“11”,“22”,“33”});
* */
String str1="abcd";//实例化str1对象
//通过反射获取方法
Method mchar=Class.forName("java.lang.String").getMethod("charAt",int.class);
//通过invoke方法获取执行charAt里面的功能,当invoke第一个参数为null时,代表调用main函数
System.out.println(mchar.invoke(str1, 1));
//不清楚类名调用方法,体现了反射功能的强大
//Method me=Class.forName("fansge.Test12").getMethod("main",String[].class);
//me.invoke(null, (Object)new String[]{"aa","bb","cc"});
Object[] obj=new Object[]{"123",1};
System.out.println("obj=:"+obj);
Class e1=Class.forName("Three11.javaBeanElement");//获取测试类的字节码
Object bean=e1.newInstance();//通过字节码获取对象
BeanInfo info=Introspector.getBeanInfo(e1);//内省测试类,获取javaBean的属性信息
PropertyDescriptor[] pds=info.getPropertyDescriptors();//获取javaBean属性数组
//for迭代每个具体的属性
for(PropertyDescriptor pd : pds)
{
//获取属性名
Object name = pd.getName();
//获取属性类型
Object type = pd.getPropertyType();
//获取get方法
Method getMethod = pd.getReadMethod();
//获取set方法
Method setMethod = pd.getWriteMethod();
//因为测试类是一个本类所以要去除它
if(!"class".equals(name))
{
//调用修改前的属性
if(getMethod!=null)
System.out.println("修改前:"+getMethod.invoke(bean, null));
//修改各种属性
if(type==String.class)
setMethod.invoke(bean, "www.itcast.com");
else if(type==boolean.class)
setMethod.invoke(bean, true);
else if (type==double.class)
setMethod.invoke(bean, 0.01d);
else if(type==int.class)
setMethod.invoke(bean, 100);
//调用修改后的属性
if(getMethod!=null)
System.out.println("修改后:"+getMethod.invoke(bean, null));
}
}
}
}
//测试的类
class javaBeanElement
{
private boolean flag;
private int x;
private String str;
private char[] ch;
private long l;
private double d;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public void show(long l)
{
this.l = l;
System.out.println("http://www.itcast.com");
}
}
(2)知识点
1.具有相同类型和维数的数组属于同一类型,即有相同的Class实例对象
2.数组的字节码文件名是:数组类型的第一个大写字母;例:int为I
3.数组对象的Class的实例对象的getSuperclass()返回的是父类Object类的Class对象
4.基本类型的一维数组可以当做Object类型使用,不能当做Object[]类型使用;非基本类型
的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
5.Arrays.asList()方法处理int[]和String[]时的差异:1.4和1.5新特性差别。1.4无法处理int数组, 返回给1,5处理,1.5将int数组作为一个参数处理
6.数组的反射:Array工具类用于完成数组反射的操作。
Array.getLength(Object obj);//获取数组长度
Array.get(Object obj,int x);// 获取数组中的元素
7.获得某个数组中的某个元素的类型
(3)内省JavaBean(特殊的Java类)
1.类中的方法以set哦get打头的类。可以将JavaBean当作普通的类来操作,而不可以将普通类当作JavaBean操作。
一个类当作JavaBean使用时,可以根据方法的名字推断出Java的属性名。去掉get或set剩下的部分就是属性的名。
剩下部分的第二个字母是小写,则第一个字母就是要变成小写。剩下部分的第二个字母是大写则第一个字母则是大写。
如:getSun 属性名:sum
2.JavaBean包含的属性
boolean/Boolean :默认值为true int/Integer ;默认值为100
String :默认值为字符串 double/Double:默认值为0.01D
(4)类加载器
A.类加载器:
类加载器就是加载类的工具,Jvm运行的时候需要加载class文件,在内存中字节码。加载class,并生成字节码文件的过程是由类加载器完成的。因为类加载器也是java类,任何类都是需要类加载器加载的,所以一定有一个不是java类的加载器,BootStrap,Jvm还内置了2个类加载器,ExtClassLoader和AppClassLoader,他们是由BootStrap加载。
BootStrap:加载的是 java包,javax包,这些系统级的包,在JRE/lib/rt.jar包内。
ExtClassLoader则JRE/lib/ext/*.jar,这里是加载该目录下的所有jar包。
如果要手动编写System类的话就必须自己编写一个类加载器,不要委托机制才可以加载到。
(5)类加载器的委托机制
类加载器加载线程中的第一个类,如果这个类中还有其他类的话,则用这个类加载器加载其他的类。就是A类中引用了B类,那么加载AB类的加载器都是同一个。每个类加载器加载类的时候都会委托给上级加载,当上级没有加载到这个类的话就返回给原加载器,如果还是加载不到就会报异常ClassnotFoundException。
(6)代理
A.面向方面的编程AOP(Aspect Oriented Program)
系统中可能存在交叉业务需要切入到系统中的一方面,如:
安全 事务 日志
StudentService ---|----------|------------|-------------
CourseService ----|----------|------------|-------------
MiscService ------|----------|------------|-------------
面向方面的编程的目标就是要是交叉的业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码运行起来的效果是一样的,如:
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
使用代理技术正好解决这样的问题,代理是实现AOP功能的核心和关键技术。
B.Proxy类和InvocationHandler接口提供了生成动态代理的功能
反射技术
反射就是在程序运行过程中,通过.class文件动态的获取类的信息(属性,构造,方法),并调用
注意:JAVA不是动态语言,因为动态语言强调在程序运行过程中不仅能获取并调用类里面的属性和方法,还要求能够给类增加属性和方法,而JAVA中的反射只能获取调用,不能修改类的结构
java.lang.reflect.Constructor:构造方法管理器,通过该对象的newInstance方法能有创建构造方法.
在反射中包含Declared的方法表示获取私有的成员内容,一般结合setAccessible(true)方法一起使用.
反射就是将JAVA类中的各个成分映射成相应的JAVA类
JAVA中九个预定义的实例对象
基本数据类型(byte、boolean、short、int、long、double、float、char)字节码对象以及void.class
另外:具有相同的数据类型和维度的数组在java中映射成同一个Class对象
判断是否为数组类型,用Class.isArray()方法
(1)案例
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.*;
import java.util.*;
class banana{
private int x;
private int y;
public void banana(int x,int y)
{
this.x=x;
this.y=y;
}
}
class apple {
public static void main(String[] args)throws Exception{
// TODO Auto-generated method stub
String str="123456";
//获取Class对象方法
Class a1=String.class;//通过所有数据类型都有静态属性.class来获取
Class a2=str.getClass();//通过对象getClass()方法获取
// Class.forName(包名.类名);
Class a3=Class.forName("java.lang.String");//通过Class类的静态方法forName()和获得Class对象的类名来获取
System.out.println((a1==a2));
System.out.println((a1==a3));
System.out.println((a2==a3));
/*Constructor类。。。。。构造方法的反射、Constructor的实例对象代表类的一个构造方法
用constructor类创建实例对象(反射创建)
注意:1.创建newInstance方法中的参数列表必须与Constructor类中的getConstructor()方法中的参数列表一致;
2.每调用一次newInstance方法,即构造一个对象
3.可以指定构造函数
*/
//获取一个类中所有的构造方法
//Constructor[] b1=Class.forName("java.lang.String").getConstructors();
//获取一个类中的某一个构造方法
Class b2=Class.forName("java.lang.String");
Constructor b22=b2.getConstructor(StringBuffer.class);
//String s1="456";//一般实例化对象
//String b3=(String)constructor.newInstance(new StringBuffer("456"));//通过反射实例化对象
/*
Field类。。。。。。(成员变量的反射)
常用的方法:
1.Field getField(String s);//只能获取该类公有和父类中公有
2.Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有
3.setAcessible(true);如果是私有字段,要先将私有字段进行取消权限检查的能力。也称暴力访问
4.set(Object obj,Object value)将指定对象变量上此Field对象表示的字段设置为指定的新值
5.Object get(Object obj);返回指定对象上Field表示的字段的值
*/
Method类。。。。。。(成员方法的反射):代表某个类中的一个成员方法
* 常用方法:
* 1.Method[]getMethods();只获取公共和父类中的所有方法
* 2.Method[]getDeclaredMethods();获取本类中方法包含私有方法
* 3.Medthod[]getMethod("方法名",参数.class(空参可以写null));
* 4.Object invoke(Object obj,参数);调用方法:如果方法是静态的,invoke中的参数可写为null
*
* 通过反射来调用main函数,invoke()方法传递一个字符串数组参数的方法
* 1.me.invoke(null,new object[](new String[]{“11”,“22”,“33”}));
* 2.me.invoke(null,(Object)new String[]{“11”,“22”,“33”});
* */
String str1="abcd";//实例化str1对象
//通过反射获取方法
Method mchar=Class.forName("java.lang.String").getMethod("charAt",int.class);
//通过invoke方法获取执行charAt里面的功能,当invoke第一个参数为null时,代表调用main函数
System.out.println(mchar.invoke(str1, 1));
//不清楚类名调用方法,体现了反射功能的强大
//Method me=Class.forName("fansge.Test12").getMethod("main",String[].class);
//me.invoke(null, (Object)new String[]{"aa","bb","cc"});
Object[] obj=new Object[]{"123",1};
System.out.println("obj=:"+obj);
Class e1=Class.forName("Three11.javaBeanElement");//获取测试类的字节码
Object bean=e1.newInstance();//通过字节码获取对象
BeanInfo info=Introspector.getBeanInfo(e1);//内省测试类,获取javaBean的属性信息
PropertyDescriptor[] pds=info.getPropertyDescriptors();//获取javaBean属性数组
//for迭代每个具体的属性
for(PropertyDescriptor pd : pds)
{
//获取属性名
Object name = pd.getName();
//获取属性类型
Object type = pd.getPropertyType();
//获取get方法
Method getMethod = pd.getReadMethod();
//获取set方法
Method setMethod = pd.getWriteMethod();
//因为测试类是一个本类所以要去除它
if(!"class".equals(name))
{
//调用修改前的属性
if(getMethod!=null)
System.out.println("修改前:"+getMethod.invoke(bean, null));
//修改各种属性
if(type==String.class)
setMethod.invoke(bean, "www.itcast.com");
else if(type==boolean.class)
setMethod.invoke(bean, true);
else if (type==double.class)
setMethod.invoke(bean, 0.01d);
else if(type==int.class)
setMethod.invoke(bean, 100);
//调用修改后的属性
if(getMethod!=null)
System.out.println("修改后:"+getMethod.invoke(bean, null));
}
}
}
}
//测试的类
class javaBeanElement
{
private boolean flag;
private int x;
private String str;
private char[] ch;
private long l;
private double d;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
public void show(long l)
{
this.l = l;
System.out.println("http://www.itcast.com");
}
}
(2)知识点
1.具有相同类型和维数的数组属于同一类型,即有相同的Class实例对象
2.数组的字节码文件名是:数组类型的第一个大写字母;例:int为I
3.数组对象的Class的实例对象的getSuperclass()返回的是父类Object类的Class对象
4.基本类型的一维数组可以当做Object类型使用,不能当做Object[]类型使用;非基本类型
的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
5.Arrays.asList()方法处理int[]和String[]时的差异:1.4和1.5新特性差别。1.4无法处理int数组, 返回给1,5处理,1.5将int数组作为一个参数处理
6.数组的反射:Array工具类用于完成数组反射的操作。
Array.getLength(Object obj);//获取数组长度
Array.get(Object obj,int x);// 获取数组中的元素
7.获得某个数组中的某个元素的类型
(3)内省JavaBean(特殊的Java类)
1.类中的方法以set哦get打头的类。可以将JavaBean当作普通的类来操作,而不可以将普通类当作JavaBean操作。
一个类当作JavaBean使用时,可以根据方法的名字推断出Java的属性名。去掉get或set剩下的部分就是属性的名。
剩下部分的第二个字母是小写,则第一个字母就是要变成小写。剩下部分的第二个字母是大写则第一个字母则是大写。
如:getSun 属性名:sum
2.JavaBean包含的属性
boolean/Boolean :默认值为true int/Integer ;默认值为100
String :默认值为字符串 double/Double:默认值为0.01D
(4)类加载器
A.类加载器:
类加载器就是加载类的工具,Jvm运行的时候需要加载class文件,在内存中字节码。加载class,并生成字节码文件的过程是由类加载器完成的。因为类加载器也是java类,任何类都是需要类加载器加载的,所以一定有一个不是java类的加载器,BootStrap,Jvm还内置了2个类加载器,ExtClassLoader和AppClassLoader,他们是由BootStrap加载。
BootStrap:加载的是 java包,javax包,这些系统级的包,在JRE/lib/rt.jar包内。
ExtClassLoader则JRE/lib/ext/*.jar,这里是加载该目录下的所有jar包。
如果要手动编写System类的话就必须自己编写一个类加载器,不要委托机制才可以加载到。
(5)类加载器的委托机制
类加载器加载线程中的第一个类,如果这个类中还有其他类的话,则用这个类加载器加载其他的类。就是A类中引用了B类,那么加载AB类的加载器都是同一个。每个类加载器加载类的时候都会委托给上级加载,当上级没有加载到这个类的话就返回给原加载器,如果还是加载不到就会报异常ClassnotFoundException。
(6)代理
A.面向方面的编程AOP(Aspect Oriented Program)
系统中可能存在交叉业务需要切入到系统中的一方面,如:
安全 事务 日志
StudentService ---|----------|------------|-------------
CourseService ----|----------|------------|-------------
MiscService ------|----------|------------|-------------
面向方面的编程的目标就是要是交叉的业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码运行起来的效果是一样的,如:
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
使用代理技术正好解决这样的问题,代理是实现AOP功能的核心和关键技术。
B.Proxy类和InvocationHandler接口提供了生成动态代理的功能