------- android培训、java培训、期待与您交流! ---------
一、java1.5的新特性
1、静态导入
import语句可以导入一个类或者某个包中的所有类,同时import static可以导入一个类中的某个静态方法或者所有静态方法。
这样做的好处是,在代码中调用静态方法时不用再加类名点了。
静态导入的格式:import static java.util.类名.*;
2、可变参数
(1)当一个方法接受的参数个数不固定,可以使用可变参数来解决
1、Class类
(1) java中的各个类属于同一种事物,为了方便管理这些类就用Class类来描述这类事物。
(2) 获取Class的对象的方法(其实就是获取相应类的字节码文件对象)
<1>通过每个对象都具备的方法getClass来获取。
例如:Person p=new Person();
Classcla1=p.getClass();
这种方法的用法:在拿到对象后(不知道对象的具体类型)可以用对象的getClass()方法来获取对象的类型。这种方法的不好之处就在于必须建立具体的对象。
<2> 每一个数据类型(基本数据类型和引用数据类型)都有一个静态属性:class
例如:Class cla2=Person.class;
这种方法的用法:如果是明确地获得某个类的Class对象,主要用于传参。这种方法的不好处就是必须先明确类
前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。
<3> 使用的Class类中的方法,forName
例如:class cla3=forName(“java.lang.String”);
这种做法的好处:指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。
2、 反射
(1)定义:反射就是把类中的各个成员映射成相应的java类。
注:java类本身可以用Class类的对象来表示;类中的成员变量,方法,构造方法也可以映射出自己的类。
(2) Method类(方法)
<1> 获取类中的所有方法:getMethods()和getDeclaredMethods()获取私有方法
Class cl1=Class.forName("java.lang.String");
Method[] methods = cl1.getMethods();//获取的是该类中的公有方法和父类中的公有方法。
methods = cl1.getDeclaredMethods();//获取的是该类中的所有方法,包括私有方法。
<2>获取指定方法:getMethod(方法名,类型)
Class cl1=Class.forName("java.lang.String");
Method methods= cl1.getMethod("charAt",int.class);//获取指定的方法
method.invoke(obj(实例对象),方法参数);运行方法
<3>运行私有方法:getDeclaredMethod(方法名,类型)
Class cl1=Class.forName("java.lang.String");
Method method = cl1.getDeclaredMethod("charAt",int.class);//获取指定的方法
method.setAccessible(true);//一般很少用,因为私有就是隐藏起来,所以尽量不要访问
method.invoke(obj(实例对象),方法参数);运行方法
(3) Constructor类(构造方法)
<1> 获取一个类中所有构造方法:getConstructors()它的返回类型是一个Constructor类型的数组。
例如:Constructor[]cons=Class.forName(java.lang.String).getConstructors();
<2> 获取某一个构造方法:getConstructor()它的返回类型是一个Constructor类。
例如:Constructor con=Class.forName(java.lang.String).getConstructors(想获取的构造方法的参数);
<3> 调用获得的构造方法:newInstance()
String str=(String)con.newInstance(new StringBuffer(“abc”));
注:这里强转是因为编译时期只看变量名,不知变量的具体内容。
通常的方法:String str=newString(new StringBuffer(“abc”));
(4)Field类(成员变量)
<1> 公有成员变量访问
Field field = str.getField(fieldName);//获取指定类的的指定变量
file.get(有访问的对象)//返回类型是具体的变量类型。
<2> 私有成员的访问
Field fy=r.getClass().getDeclaredField("y");
fy.setAccessible(true);//让私有可以被访问
System.out.println(fy.get(r));
总结:反射的作用是用来实现框架的功能的. 框架就是在类出现之前就已经把类给用了,由于不知道用到什么类,所以就要用反射来解决这个问题.
三 内省(introspector)------(javabean)
javaBean是一种 特殊的类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。说白了:javabean就是这样一种类:类里面有一些私有的属性,要访问这些属性就必须提供一些set和get方法(这就是javabean的特殊之处).
内省是为了解决访问这些私有属性(反射)困难而出现的,
内省访问javabean的属性有两种方式:
(1).通过PropertyDescriptor类来操作javabean的属性
例子:
PropertyDescriptor dp=new PropertyDescriptor(propertyName,pt1.getClass());//建立属性描述对象,
// 并和属性以及它所在的类相关联
Method methodGetX=dp.getReadMethod();//通过属性描述类的方法获取getX这个方法
Object reVal=methodGetX.invoke(pt1);//获取具体对象的属性值
(2)通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。
例子:
BeanInfo beanInfo=Introspector.getBeanInfo(pt1.getClass());//通过内省类的静态方法来获取具体class文件的Bean的信息
PropertyDescriptor[]pds=beanInfo.getPropertyDescriptors();//获取所有属性
//遍历属性,获取需要的属性
for(PropertyDescriptor pd:pds)
{
if(pd.getName().equals(propertyName))
{
Method methodGetX=pd.getReadMethod();
Object reVal=methodGetX.invoke(pt1);
break;
}
}
由于内省的类过于繁琐,所以便出了BeanUtils包(和Arrays类似).
四.注解
(4)测试这三个类的继承关系
public class Test {
public static void main(String[] args) {
ClassLoader classLoader =Test.class.getClassLoader();
while(classLoader !=null){
System.out.println(classLoader.getClass().getName());
classLoader=classLoader.getParent();
}
System.out.println(classLoader);
}
}
打印结果是 :AppClassLoader ExtClassLoader null
分析:Test.class 存在于classpath指定的目录下,所以一开始classLoader是AppClassLoader(java类) ,循环条件为真,打印出了 AppClassLoader,由它们的继承关系可知AppClassLoader的父类是ExtClassLoader(java类),循环条件为真,打印出ExtClassLoader
由它们的继承关系可知ExtClassLoader的父类是BootStrap(非java类),循环条件为假,跳出循环将null打印出来.
2.类加载器的委托机制
委托机制的描述:当需要某个类加载器要加载指定的类的时候,并不是立刻到自己的管辖范围去加载指定的字节码文件,而是将这个指定的类传递给父类,由父类尝试去到自己的加载范围去加载这个类。就这样,一级级地向上递推到类加载器的最高父类:Bootstrap类加载器
加载过程:由某个子类加载器层层向上推进到Bootstrap类加载器加载。若最高父类类加载器无法加载指定的类,又开始层层向下递推到子类加载器进行加载。如果退回到发起者的类加载器还是没有办法加载指定的类,就抛出ClassNotFoundException这个异常。
3.自定义类加载器
(1)自定义类加载器的方式
1) 继承ClassLoader并覆盖父类中loadClass()方法;
2)继承ClassLoader 并覆盖父类中findClass()方法.
两种法能法比较:第一种就必须自己冲新编写委托机制(找父类),过于麻烦(不提倡这种做法)
第二种方法 可以把自己定义类加载器的逻辑写到findClass()中,(loadClass()方法可以调用findClass()).在loadClass()方法的逻辑中如果父类加载失败,就会调用到自定义的findClass方法中的内容。
(2)自定义类加载器的演示:
public class MyClassLoader extendsClassLoader
{
//覆盖findClass()方法在里面定义自己的加载方式.
protected Class<?> findClass(Stringname) throws ClassNotFoundException
{
try
{
FileInputStreamfis =new FileInputStream(new File(name +".class"));
byte[] classBytes =new byte[1024];
int length =fis.read(classBytes, 0, classBytes.length);
return defineClass(classBytes, 0,length);//将读到的内容转化成Class类的实例.
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return null;//保证编译可以通过.
}
}
4.动态代理类的分类(依据:目标类是否实现了特定的接口)
(1)通过JVM生成动态代理类(目标类必须实现某些接口)
(2)通过第三方类库CGLIB生成动态代理库(不需要目标类实现相应的接口)
5.系统代码出现在目标类的位置
(1)在调用目标方法前
(2)在调用目标方法之后
(3)在目标方法前后
(4)在处理目标方法异常的catch块中.
6 .JVM动态生成类练习
(1)获取动态类的构造方法
package cn.itcast.day3;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.Collection;
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//获取动态生成类的字节码文件getProxyClass(loader,interface);
Class clazzProxy=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//获取生成类的所有构造方法
printConstructors(clazzProxy);
}
//获取生成类的所有构造方法
public static void printConstructors(Class clazzProxy){
Constructor[] cons=clazzProxy.getConstructors();
for(Constructor con:cons)
{
String name=con.getName();
//将name存到一个容器中
StringBuilder sb=new StringBuilder(name);
sb.append("(");
//获取构造函数的参数
Class[] clazzParams=con.getParameterTypes();
for(int i=0;i<clazzParams.length;i++)
{
//将第一个参数添加到容器中
sb.append(clazzParams[i].getName());
if(i!=clazzParams.length-1)
sb.append(",");
}
sb.append(")");
//将容器中的内容打印出去
System.out.println(sb.toString());
}
}
}
打印结果:
$Proxy0(java.lang.reflect.InvocationHandler)
通过分析结果可知:动态生成的代理类只有一个构造方法并且含有参数构造方法的名字是$Proxy0,参数是一个接口.
(2)创建动态类的实例对象
newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler handler)//中间的参数只能用数组,不能用可变参数
Collection con1=(Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler() {
private ArrayList al=new ArrayList();
public Object invoke(Object proxy,Method method,Object[] args)throws Throwable
{
return method.invoke(al,args);
}
});
(3)动态代理类的运行原理(借用别人的图)