学习概述:Java 内省和Java Bean.java 注解,以及框架的部分知识
学习目标:理解内省的概念,学会使用内省来操作Java Bean,对于Java EE框架大脑里有一个大体的概念。学会使用Beanutils,以及对注解的反射应用,注解往往是自己以前比较忽略的部分,认为注解只是程序的注释,除了增强程序的可读性之外没什么作用,这种想法是错误的,对于这部分知识,一定要深入掌握,改变这种错误观点。
反射的最大价值:实现框架
1.框架与框架要解决的核心问题
框架与工具类的区别:工具类被用户类调用,而框架则是调用用户提供的类。
框架要解决的核心问题:因为在写程序时才知道要被调用的类名,所以在程序中无法采用new关键字创建实例对象,而要使用反射的方式来做。
模拟通过配置文件得到ArrayList实例对象(反射应用)
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;
public class TestReflect {
public static void main(String[] args){
try{
InputStream ips = new FileInputStream("test.properties");
Properties prop = new Properties();
prop.load(ips);
String classname = (String) prop.get("classname");
try{
Class<?> coll = Class.forName(classname);
@SuppressWarnings("unchecked")
Collection<String> a =(Collection<String>) coll.newInstance();
a.add("abc");
a.add("abc");
System.out.print(a.size());
}
catch(ClassNotFoundException e){
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
catch(IOException e){
e.printStackTrace();
}
}
}
小细节:配置文件应该放在什么地方?在实际项目中,没有用相对路径的,一种解决方式是采用绝对路径。但是绝对路径不能用硬编码,而是计算出来。可以采用类加载器,示例如下:class.getClassLoader().getResourceStream( 文件名);
2.内省及引出JavaBean
什么是JavaBean,Javabean是一种特殊的Java类,主要用于传递的数据信息,类中的属性均为私有的,所有的属性都有get和set方法。外部程序不能直接访问Java Bean的状态信息,这种类中的方法主要用于访问私有变量,Java Bean是对面向对象三大特征之一:封装的完美诠释。
如果想在Java模块之间传递很多信息,可将这些新意一起封装到一个JavaBean中,特别是在Java EE开发中,Java Bean有广阔的应用,也被称为值对象(VO)。
一个Java Bean实例:
public class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age=age;
}
}
public class IntroSpectorDemo {
/**
* @param args
* @throws NoSuchFieldException
* @throws SecurityException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, IntrospectionException, InvocationTargetException, NoSuchMethodException {
// TODO Auto-generated method stub
Person p = new Person(1,"james");
PropertyDescriptor pd = new PropertyDescriptor("name", Person.class);
Method mR = pd.getReadMethod();
Object object = mR.invoke(p);
System.out.println(object);
//得到bean的set方法改变bean的值
Method mW = pd.getWriteMethod();
mW.invoke(p,"kobe");
}
}
<2>复杂内省操作
import org.apache.commons.beanutils.BeanUtils;
/*
* javabean的内省操作,如果不适用内省,那么我们只能用反射的方法得到bean的get和set方法,有了内省之后操作方便了很多。
*/
public class IntroSpectorDemo {
/**
* @param args
* @throws NoSuchFieldException
* @throws SecurityException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws IntrospectionException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, IntrospectionException, InvocationTargetException, NoSuchMethodException {
// TODO Auto-generated method stub
Person p = new Person(1,"james");
PropertyDescriptor pd = new PropertyDescriptor("name", Person.class);
Method mR = pd.getReadMethod();
Object object = mR.invoke(p);
System.out.println(object);
//得到bean的set方法改变bean的值
Method mW = pd.getWriteMethod();
mW.invoke(p,"kobe");
System.out.println(p.getName());
//使用IntroSpector进行复杂内省操作
BeanInfo beanInfo = Introspector.getBeanInfo(p.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor propertyDescriptor:pds){
System.out.println(propertyDescriptor.getReadMethod().getName());
}
//使用更加专业省事的工具类操作Java Bean
//System.out.println(BeanUtils.getProperty(p, "name"));
BeanUtils.setProperty(p, "age", "15");
Field f = Person.class.getDeclaredField("age");
f.setAccessible(true);
System.out.println(f.getInt(p));
}
}
注意:使用BeanUtils是不要忘记导入两个jar包:commons-beanutils.jar和commons-logging.jar.
public @interface Test{
}
定义了这个Annotation之后,就可以在程序的任何地方用来使用该Annotation,使用Annotation时的语法非常类似于public,final这样的修饰符。通常可用于修饰程序中的类,方法,变量,接口等定义,通常我我们应当把Annotation放在所有修饰符前面 。
package com.lee.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*
* 自定义注释
*/
// 元数据:定义了注解的生存周期以及目标
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
}
package com.lee.Annotation;
//编写一个应用自定义注解的测试类
public class AnnotationDemo2 {
@MyAnnotation
public static void method1(){}
@MyAnnotation
public static void method2(){}
public static void method3(){}
}
package com.lee.Annotation;
import java.lang.reflect.Method;
//反射得到方法的注释,以有没有方法注释作为标准判定该方法是否应该执行
public class TestProcessor {
public static void process(String clazz) throws Exception, ClassNotFoundException{
int passed=0;
int failed=0;
//反射得到类的所有方法
for(Method m:Class.forName(clazz).getMethods()){
if(m.isAnnotationPresent(MyAnnotation.class)){
//测试的方法都是static修饰的
m.invoke(null);
passed++;
}
else{
failed++;
}
}
int methodSum = passed+failed;
System.out.println("共运行了: "+methodSum+ "方法");
System.out.println("成功了:" +passed+"个方法");
}
public static void main(String[] args) throws ClassNotFoundException, Exception{
process("com.lee.Annotation.AnnotationDemo2");
}
}
public @interface Test{
String name();
int age();
}
特别要注意的是:一旦使用了带有成员变量的Annotation时,需要为该Annotation中的变量赋值,如下所示
public class Test{
@Test(name="abc",age=6)
public void info(){
... ...
}
}
package com.lee.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo {
}
package com.lee.Annotation;
import java.lang.annotation.Annotation;
/**
*
* @李亮亮
* 自定义注解的应用
*/
@AnnotationDemo
public class AnnotationTest {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
//先判断注解在不在
if(AnnotationTest.class.isAnnotationPresent(AnnotationDemo.class)){
Annotation annotation = AnnotationTest.class.getAnnotation(AnnotationDemo.class);
System.out.println(annotation);
}
}
}