Class类:描述众多java类的对象。代表内存里的一份字节码。
有三种方式可以获取一个类的Class文件。
方法一:是通过该类对象.getClass()方法。
方法二:通过Class类的静态方法,Class.forName("name");
方法三:是同过类名.class方法获取。
对于基本类型的封装类,还可以通过封装类类型.TYPE方式获取其对应的基本数据类型的class文件,例如:Integer.TYPE == int.class ;
Class.forName()方法的作用,一是如果指定的字节码已经加载到内存中,则获取指定的字节码,
二是如果指定的字节码没有加载进内存,则先将其加载进内存,然后获取这份字节码。
Class类的常用方法:
Class.forName(String className); //返回与带有给定字符串名的类或接口相关联的 Class 对象。
getAnnotation(Class<A> annotationClass); //如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
getAnnotations(); //返回此元素上存在的所有注释的数组。
getClassLoader(); //返回该类的类加载器。
getConstructors(); //返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
getConstructor(Class... parameterTypes);//返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
getDeclaredConstructor(Class... parameterTypes);//返回一个私有 Constructor 对象,
该对象反映此 Class 对象所表示的类或接口的指定构造方法。
getField(String name); //返回一个字段。
getMethod(String name, Class... parameterTypes); //返回一个方法。
getDeclaredField(String name);//返回一个生命为私有的字段。
getDeclaredMethod(String name, Class... parameterTypes);//返回一个私有方法,第一个参数方法名,第二个参数返回类型。
isInterface(); //指定的Class是否是一个接口。
isPrimitive(); //指定的Class是否是一个基本类型。
isArray(); //判断指定的Class文件是否表示一个数组。
Reflect。反射:一个类有多个组成部分,例如,成员变量,方法,构造方法等。反射就是加载类,并解刨出类的各个组成部分。
通过反射得到构造函数,方法,字段实例。
通过反射获得一个类的空参数构造函数:
Class clazz = Class.forName("cn.itcast.Person"); //通过反射提取该类字节码。
Constructor c = clazz.getConstructor(null); //通过getConstructor方法获取此类的空参数构造函数。
Person p = (Person)c.newInstance(null); //通过此构造函数创建该类对象,因为返回类型是Object,所以要进行提升。
类的构造函数为私有时的做法:
Class clazz = Class.forName("cn.itcast.Person");
Constructor c = clazz.getDeclaredConstructor(List.class); //通过getDeclaredConstructor方法获取此类的私有参数构造函数。
c.setAccessible(true); //暴力反射。将此构造函数的Accessible方法设置为true,可以打开私有的访问权限。
Person p = (Person)c.newInstance(new ArrayList());
通过反射获得一个类的方法:
Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Method method = clazz.getMethod("run",null); //通过getMethod方法获得此类的空参数run方法。
method.invoke(p,null); //通过Class类的invoke方法运行此方法,需要传入对象p,参数为null。
通过反射获取有两个参数的方法:
Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Method method = clazz.getMethod("eat",String.class,int.class); //通过getMethod方法获得此类两个参数eat方法。
method.invoke(p,"apple",5); //
通过反射获取一个有返回值得方法:
Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Method method = clazz.getMethod("run",String.class,int[].class); //通过getMethod方法获得此类的空参数run方法。
Class[] cs = method.invoke(p,"pao",new int[]{1,2,3}); //通过Class类的invoke方法运行此方法,需要传入对象p,参数为null。
通过反射获取一个私有的方法:
Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Method method = clazz.getDeclaredMethod("run",InputStream.class); //通过getMethod方法获得此类的InputStream参数run方法。
method.setAccessible(true); //暴力反射。
method.invoke(p,new FileInputStream("c:\\1.txt"));
通过反射获取一个静态的方法:
//Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Method method = clazz.getMethod("run",String.class);
method.invoke(null,"isrun");
反射main函数
//Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Method method = clazz.getMethod("main",String[].class);
method.invoke(null,(Object)String[]{"aaa","bbb","ccc"});
通过反射获得一个类的字段:
反射一个公有的字段:
Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Field f = clazz.getField("name"); //通过名称获取字段。
Class type = f.getType(); //获取该字段的类型。
String str = (String)f.get(p); //通过get方法获取字段的值。
f.set(p,"abc"); //给p对象的f字段赋值。
f.get(p); //获取p对象f字段的值。
反射一个私有的字段:
Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Field f = clazz.getDeclaredField("name"); //通过名称获取字段。
f.setAccessible(true);
Class type = f.getType(); //获取该字段的类型。
String str = (String)f.get(p); //通过get方法获取字段的值。
f.set(p,"abc"); //给p对象的f字段赋值。
f.get(p); //获取p对象f字段的值。
反射一个静态私有的字段:
Person p = new Person();
Class clazz = Class.forName("cn.itcast.Person");
Field f = clazz.getDeclaredField("name"); //通过名称获取字段。
f.setAccessible(true);
Class type = f.getType(); //获取该字段的类型。
String str = (String)f.get(p); //通过get方法获取字段的值。
f.set(p,"abc"); //给p对象的f字段赋值。
f.get(p); //虽然是静态方法,但是此处需要传入一个对象才可获取。
用反射将一个对象中的所有字符串字段中的一个字母替换成另一个字母。
private static void changeStringValue(Object obj){
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 applyType(ArrayList<Integer> list){
System.out.println("pao.....");
}
Method method = reflect1.class.getMethod("applyType", ArrayList.class);
Type[] types = method.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType) types[0];
System.out.println(pType.getRawType());
System.out.println(pType.getActualTypeArguments()[0]);
内省:IntroSpector,主要用于对JavaBean进行操作,JavaBean是一种特殊的java类,如果一个类中有get set方法,那么
这个类就可以被当做一个JavaBean来操作。一个类的属性是由其get set方法决定的。
javabean:
通过内省的方法得到一个类的get方法:
例如:
public static Object getProperty(Object obj,String propertyName) throws Exception{
//通过存储器操作propertyName属性的set和get方法。
PropertyDescriptor pd = new PropertyDescriptor(propertyName, obj.getClass());
//获取propertyName字段的读取方法。
Method getMethod = pd.getReadMethod();
//读取obj对象propertyName字段上的值。
Object retValue = getMethod.invoke(obj);
return retValue;
}
public static Object getProperty1(Object obj,String propertyName) throws Exception{
BeanInfo bInfo= Introspector.getBeanInfo(obj.getClass());
PropertyDescriptor[] propertyDescriptors = bInfo.getPropertyDescriptors();
String reValue = null;
for(PropertyDescriptor pd : propertyDescriptors){
if(pd.getName().equals(propertyName)){
Method getMethod = pd.getReadMethod();
reValue = (String) getMethod.invoke(obj);
break;
}
}
return reValue;
}
Beanutils工具包:是Apache公司提供的用于操作JavaBean的工具包,此工具包简化了对JavaBean的操作。
例如,使用BeanUtils设置和获取某个对象的某个属性。
BeanUtils.setProperty(pt1,"x","9"); //设置pt1这个对象的x这个属性,值为9。
BeanUtils.getProperty(pt1,"x"); //获取pt1这个对象x字段的属性值。
jdk7的一个新特性:通过BeanUtils设置Map的属性。
Map map = {name:"zxx",age:"18"};
BeanUtils.setProperty(map,"name","lhm");
使用PropertyUtils设置和获取一个对象的属性。
PropertyUtils.setProperty(pt1,"x",9);
PropertyUtils.getProperty(pt1,"x");
//通过PropertyUtils同样也可以达到BeanUtils的设置和获取效果,两者的不同之处在于
//PropertyUtils设置对象的属性时,需要使用对象的本身类型,而BeanUtils不论对象本身是什么类型
//都需要使用字符串。获取对象属性时PropertyUtils返回的对象本身的类型,而BeanUtils则都返回字符串。
BeanUtils只支持8种数据类型的转换,其他类型须自定义类型转换器。
例如:
ConvertUtils.register(new Converter(){
public Object convert(Class Type,Object value){ //覆写接口中的方法。
if(value==null) //判断传入的值是否为空。
retrun null;
if(!(value instanceof String)){
throw new ConversionException("请传入String类型的数据");
}
String str = (String)value;
if(str.trim().equals(""))
return null;
SimpleDateFormat adf = new SimpleDateFormat("yyyy-MM-dd"); //定义一个格式化的格式。
try{
return df.parse(str); //格式化时可能发生异常,不能抛出比父类更多的异常。
}
catch(ParseException e){
throw new RuntimeException(e);
}
}
},Date.class);
也可以用已定义号的转换器:例如:
ConvertUtils.reqister(new DateLocalConverter(),Date.class);
将Map集合中的数据填充到指定的Bean中:
Map map = new HashMap();
map.put("name","zhangsan");
map.put("password","123");
map.put("age","23");
map.put("birthday","1982-2-22");
ConvertUtils.register(new DateLocalConverter(),Date.class);
Person bean = new Person();
BeanUtils.populate(bean,map); //将map集合中的数据填充到bean中。
注解的自定义方法:
@interface 注解名{}
例如:
@Retention(RetentionPolicy.RUNTIME) //元注解。RUNTIME表示的是,让注解保留到运行时。
//除此之外,还有两个一个是:@Retention(RetentionPolicy.CLASS)保存到字节码阶段。
//另个一个是:@Retention(RetentionPolicy.SOURCE)保存到源文件阶段。
public @interface ItcastAnnotation{}
在一个自定义注解上加上元注解:@Target((ElementType.METHOD),(ElementType.TYPE)) //表示此注解可以作用的范围。检测某一个类上是否有某个注解:
类名.class.isAnnotationPresent(注解名.class); //先得到该类的字节码,在调用字节码的isAnnotationPresent方法。
得到某一个注解的方法:
getAnnotation(注解名.class);
为注解添加属性:
//1,定义一个注解类。
public @interface ItcastAnnotation{
//给注解定义一个String属性,并设置缺省值。
String color defult "bule";
String value();
//定义一个数组属性,并设置缺省值。
int[] arrayAttr() defult {3,4,5};
}
注解的应用实例:
@Retention(RetentionPolicy.RUNTIME)
public @interface ItcastAnnotation{
//为color属性设置默认属性为blue。
String coloer() default "blue";
String value();
int[] arrayA default {3,4,5};
//定义一个枚举类型的属性。
EnumTest.TrafficLamp lamp() default TrafficLamp.RED;
//定义一个注解属性,并为其指定缺省值。
MetaAnnotation annotationAttr(); default @MetaAnnotation("arrs");
}
public @interface MetaAnnotation{
String value();
}
@ItcastAnnotation(color="red",value="abc",arrayA={1,2,3})
public class AnnotationTest{
//因为color有默认属性,所以可以不用设置。当只有一个属性需要设置时,可以不写属性名和等号。
@ItcastAnnotation("xyz")
public static void main(String[] args){
//判断某一个类上是否有某个注解。
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
//通过反射获取指定的注解。
ItcastAnnotation annotation = (ItcastAnotation)AnnotationTest.class.getAnnotatio(ItcastAnnotation.class);
//调用注解的属性。
System.out.println(annotation.color());
}
}
}
*/
类加载器:ClassLoader
自定义类加载器需要继承ClassLoader并覆写finedClass()方法。
自定义一个类加载器的实例:
public class MyClassLoader extends ClassLoader {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
}
//自定义一个加密方法,使用自定义类加载器可以解密被此加密方法加密过的类。
private static void cypher(InputStream ips,OutputStream ops)throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b^0xff);
}
}
private String classDir;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classFileName = classDir+"\\"+name+".class";
try {
//读取此文件,并解密。
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
fis.close();
byte[] bytes = bos.toByteArray();
System.out.println("aabbb");
return defineClass(bytes,0,bytes.length);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.findClass(name);
}
public MyClassLoader(){
}
//传入需要加载的类文件的相对路径
public MyClassLoader(String classDir){
this.classDir = classDir;
}
}