反射含路径问题部分笔记.docx

上传人:b****7 文档编号:23465472 上传时间:2023-05-17 格式:DOCX 页数:17 大小:21.55KB
下载 相关 举报
反射含路径问题部分笔记.docx_第1页
第1页 / 共17页
反射含路径问题部分笔记.docx_第2页
第2页 / 共17页
反射含路径问题部分笔记.docx_第3页
第3页 / 共17页
反射含路径问题部分笔记.docx_第4页
第4页 / 共17页
反射含路径问题部分笔记.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

反射含路径问题部分笔记.docx

《反射含路径问题部分笔记.docx》由会员分享,可在线阅读,更多相关《反射含路径问题部分笔记.docx(17页珍藏版)》请在冰豆网上搜索。

反射含路径问题部分笔记.docx

反射含路径问题部分笔记

源文件来自Y2笔记

◆反射(Reflect)

反射即将Class类中的所有的成员映射为相应的对象。

要学习反射那么需要先了解和掌握以下几个类:

描述

Class

描述所有的Class文件的共性

Filed

描述的是Class文件的中的属性的共性

Constructor

描述的是Class文件中的构造函数的共性

Method

描述的是Class文件中的函数的共性

1.获取指定类的Class对象

方式一:

类名.class

方式二:

对象名.getClass()

方式三:

forName(StringclassName)该方法是Class类的静态方法推荐

 

举例1:

获取字符串类的Class对象。

publicstaticvoidmain(String[]args)throwsException{

//使用不同的方式会过去Class对象

Classclazz1=String.class;

Classclazz2=newString("zhangsan").getClass();

//参数必须指定类的全名(类的全限定名)

Classclazz3=Class.forName("java.lang.String");

//class文件时候独一无二的,那么Class对象也应该是单例的

System.out.println(clazz1==clazz2);//true

System.out.println(clazz2==clazz3);//true

}

以上的方式都可以获取指定类的Class对象,在实际的开发中到底要使用哪一个?

一般的情况下我们都需要在不知道类名的情况下获取类的Class对象并进而获取类中包含的成员进行操作。

大家可以参考Tomcat的一个基本的server.xml文件

type="org.apache.catalina.UserDatabase"

description="Userdatabasethatcanbeupdatedandsaved"

factory="org.apache.catalina.users.MemoryUserDatabaseFactory"类

pathname="conf/tomcat-users.xml"/>

2.将Class对象中的属性进行反射为Filed对象

常用的获取属性字段的方法

方法

描述

Field[]getDeclaredFields()

获取所有声明的字段数组对象

Field[]getFields()

获取所有的声明的共有字段数组对象

FieldgetDeclaredField(Stringname)

获取指定名称的声明的字段对象

FieldgetField(Stringname)

获取指定名称的声明的共有字段对象

举例1:

获取所有的声明字段数组对象。

publicstaticvoidmain(String[]args)throwsException{

//获取Shape类的Class对象

Classclazz=Class.forName("cn.sve.bean.Shape");

//获取所有的属性

Field[]fs=clazz.getDeclaredFields();

System.out.println(fs.length);//2

//获取所有共有的属性

fs=clazz.getFields();

System.out.println(fs.length);//1

//获取指定名字的私有的属性

Fieldfield=clazz.getDeclaredField("x");

System.out.println(field);

//获取指定名字的共有的属性

field=clazz.getField("y");

System.out.println(field);

}

举例2:

调用Field类的方法进行字段对象的操作。

publicstaticvoidmain(String[]args)throwsException{

//获取Shape类的Class对象

Classclazz=Class.forName("cn.sve.bean.Shape");

//获取所有的属性

Field[]fs=clazz.getDeclaredFields();

System.out.println(fs.length);//2

//获取所有共有的属性

fs=clazz.getFields();

System.out.println(fs.length);//1

Shapeshape=newShape();//20

//获取指定名字的私有的属性

Fieldfield=clazz.getDeclaredField("x");

System.out.println(field);

//操作私有的属性x

System.out.println("属性名:

"+field.getName());

//获取x的属性值,需要暴力的反射

field.setAccessible(true);

System.out.println("设置之前的x值:

"+field.get(shape));

//设置x的属性值

field.set(shape,20);

System.out.println("设置之后的x值:

"+field.get(shape));

//获取指定名字的共有的属性

field=clazz.getField("y");

System.out.println(field);

//给属性y进行设置值

System.out.println("属性名:

"+field.getName());

//获取设置属性值之前的值

System.out.println("设置之前的y值:

"+field.get(shape));//20

field.set(shape,30);//30

System.out.println("设置之后的y值:

"+shape.y);//30

}

以上的代码可以通过程序进行反射类中的属性字段并操作,但是没有进行静态属性的反射和操作。

举例3:

反射静态的成员属性。

publicstaticvoidmain(String[]args)throwsException{

//获取Shape类的Class对象

Classclazz=Class.forName("cn.sve.bean.Shape");

//获取共有的静态属性

Fieldfield=clazz.getField("z");

System.out.println("设置之前的z值:

"+field.get(null));

field.set(null,40);

System.out.println("设置之后的z值:

"+field.get(null));

}

3.将Class对象中的方法进行反射为Method对象。

publicstaticvoidmain(String[]args)throwsException{

//获取Shape类的Class对象

Classclazz=Class.forName("cn.sve.bean.Shape");

//获取所有的声明的方法

Method[]ths=clazz.getDeclaredMethods();

System.out.println(ths.length);//2

//获取私有的带参数的sayHello方法

MethodsayHello=clazz.getDeclaredMethod("sayHello",String.class);

System.out.println(sayHello);

//调用私有的方法

sayHello.setAccessible(true);

sayHello.invoke(newShape(),"zhangsan");

//获取所有的共有的方法

ths=clazz.getMethods();

System.out.println(ths.length);//10

//获取带参数的共有的方法

Methodgreet=clazz.getDeclaredMethod("greet",String.class);

System.out.println(greet);

//方法的调用

greet.invoke(newShape(),"zhangsan");

}

4.将Class对象中的构造函数进行反射为Constructor对象。

publicstaticvoidmain(String[]args)throwsException{

//获取Shape类的Class对象

Classclazz=Class.forName("cn.sve.bean.Shape");

//获取所有的声明的构造函数

Constructor[]cons=clazz.getDeclaredConstructors();

System.out.println(cons.length);//3

//获取带参数的私有的构造函数对象

Constructorcon=

clazz.getDeclaredConstructor(int.class,int.class);

System.out.println(con);

//暴力反射私有的构造函数创建对象

con.setAccessible(true);

Shapemyshape=(Shape)con.newInstance(400,500);

System.out.println(myshape.getX()+","+myshape.y);

//获取所有的共有的构造函数

cons=clazz.getConstructors();

System.out.println(cons.length);//2

con=clazz.getConstructor(int.class);

System.out.println(con);

//调用构造函数创建对象

Shapeshape=(Shape)con.newInstance(100);

System.out.println(shape.getX());

}

面试题:

请简单的叙述出你所可以创建的对象的几种方式?

第一种:

直接使用new关键字

第二种:

Construnctor.newInstance

第三种:

枚举

第四种:

单例、工厂模式

 

◆内省(Introspect)

其实在以上的反射技术体验中我们发现其实反射的对象一般是一个具有特定功能的一个类。

引入一个基本的概念:

JavaBean

如果一个类提供了封装好的属性、构造函数(无参数)、共有的get和set方法以及简单的业务逻辑方法那么将这样的一个类称之为JavaBean类。

对于一个javaBean的操作无非就是给属性值进行操作或函数的调用。

使用反射比较繁琐,那么SUN就提供了内省的技术方便大家进行JavaBean类的操作。

描述

BeanInfo

对JavaBean进行描述的接口

Introspector

描述所有的JavaBean的成员类

PropertyDescriptor

描述的是JavaBean的属性类

举例1:

使用属性描述器类操作JavaBean属性。

创建一个Book的javabean类

publicclassBook{

privateStringname;//null

privateStringauthor;//null

privatedoubleprice;//0.0

privateDatedate;//null

publicBook(){

super();

}

publicBook(Stringname,Stringauthor,doubleprice,Datedate){

super();

this.name=name;

this.author=author;

this.price=price;

this.date=date;

}

//省略get和set方法

}

使用内省技术进行简单的属性的操作。

publicstaticvoidmain(String[]args)throwsException{

//获取一个属性的描述器对象就相当于获取了属性的名、set和get方法

PropertyDescriptorpd=new

PropertyDescriptor("name",Book.class);

//获取set方法

Methodset=pd.getWriteMethod();

//调用该方法设置属性的值

Bookbook=newBook();

System.out.println("设置前获取name属性值:

"+book.getName());

set.invoke(book,"JavaSE进阶");

System.out.println("设置后获取name属性值:

"+book.getName());

//获取get方法

Methodget=pd.getReadMethod();

System.out.println(get.invoke(book,null));

}

以上的代码每次都只能操作一个属性,这样就比较繁琐。

可以使用其他的类直接获取所有的属性描述器通过循环来直接操作。

publicstaticvoidmain(String[]args)throwsException{

//获取指定的BeanInfo对象

BeanInfoinfo=Introspector.getBeanInfo(Book.class);

//获取Book类中的所有的属性的描述器对象

PropertyDescriptor[]pds=info.getPropertyDescriptors();

//输出长度

System.out.println(pds.length);

//查看数组的第一个属性描述器是谁

PropertyDescriptorpd=pds[0];

//作者

System.out.println(pd.getName());

Bookbook=newBook();

//给书设置作者信息

pd.getWriteMethod().invoke(book,"zhangsan");

System.out.println(pd.getReadMethod().invoke(book,null));

}

总结:

其实发现在使用内省进行属性操作的时候要结合反射一起使用。

面试题:

一个JavaBean中为什么必须要提供一个无参数的构造函数?

原因一:

为了可以做父类。

原因二:

为了可以使用反射创建对象。

 

◆BeanUtils工具

在实际的开发中我们经常需要将用户的录入的数据进行封装为对象,那么如果使用反射和内省技术就会变得吃力。

因此本节主要给大家讲解一个开源的操作JavaBean的一个工具即BeanUtils。

下载:

http:

//www.apache.org

beanutils-1.8.0.zip

commons-logging.jar

包的引入:

在项目中创建一个文件夹如libs,然后将整个项目需要的第三方的jar包可以直接拷贝带该目录,随后打开该目录全选右键Buildpathaddpath看到奶瓶子即可

举例1:

使用BeanUtils工具封装用户提交的数据。

publicstaticvoidmain(String[]args)throwsException{

//模拟用户的输入的数据如下

Stringname="XML基础";

Stringauthor="zhangsan";

Stringprice="99.99";

Stringdate="2016-07-07";

Bookbook=newBook();

//任务是将以上的属性设置给指定的Book对象

BeanUtils.setProperty(book,"name",name);

BeanUtils.setProperty(book,"author",author);

BeanUtils.setProperty(book,"price",price);

//查看属性是否封装好

System.out.println(book);

}

发现使用上面的代码可以省略基本数据类型的转型的问题。

进而提高代码的开发效率。

举例2:

自定义一个类型转换器类。

publicstaticvoidmain(String[]args)throwsException{

//模拟用户的输入的数据如下

Stringname="XML基础";

Stringauthor="zhangsan";

Stringprice="99.99";

Stringdate="2016-07-07";

Bookbook=newBook();

//注册一个自己的转换器

/**

*converter指定具体的转换器

*clazz遇到什么类型调用上面的转换器

*/

ConvertUtils.register(

newConverter(){

//回调方法

@Override

publicObjectconvert(Classtype,Objectvalue){

if(value==null){

returnnull;

}

//转换为String

Stringdata=(String)value;

//将指定格式的字符串转换为Date

SimpleDateFormatformat=newSimpleDateFormat("yyyy-MM-dd");

Datedate=null;

try{

date=format.parse(data);

returndate;

}catch(ParseExceptione){

e.printStackTrace();

returnnull;

}

}

},

Date.class);

//任务是将以上的属性设置给指定的Book对象

BeanUtils.setProperty(book,"name",name);

BeanUtils.setProperty(book,"author",author);

BeanUtils.setProperty(book,"price",price);

BeanUtils.setProperty(book,"date",date);

//查看属性是否封装好

System.out.println(book);

}

如果每次遇到一个复杂类型都需要自定义转换器,那样的话实在麻烦。

大家看在开发的时候可以先查看该接口是否提供了有效的实现类。

ConvertUtils.register(newDateLocaleConverter(),Date.class);

其实真正的封装好的数据需要存储在数据库中,那么javabean的数据类型应该和数据库的数据类型保持一致,那么在声明持久化javabean的时候需要全部为数据库的基本数据类型。

因此大家在JavaBean中需要导入的是java.sql.Date类,这样就直接可以将日期自动转换了。

举例3:

实现封装好的JavaBean对象的属性拷贝。

//实现属性封装数据的一个拷贝

Bookcopy=newBook();

System.out.println(copy);

PropertyUtils.copyProperties(copy,book);

System.out.println(copy);

思考:

如果使用BeanUtils封装用户的数据,那么也就是一个一个设置啊?

岂不是也很麻烦?

其实在真是的环境中我们可以直接获取用户提交的所有的数据信息,只需要进行遍历即可,但是为了方便快速的设置,那么可以将javabean中的属性名和用户提交的数据名保持一致。

框架体验

其实所谓的框架就是通过一些配置文件来将需要运行的模块以及类、方法在软件启动的时候自动运行。

如果将需要运行类以及模块配置在文件中那么便于后期的一个维护。

1.创建一个配置文件如下

run=cn.sve.service.UserService

me=autoRun

value=jack,lucy

2.创建两个实现接口的服务类

UserService.java

publicclassUserServiceimplementsService{

//提供自动运行的方法

publicvoidautoRun(Stringnames){

//使用,号切割用户列表

String[]ns=names.split(",");

//遍历

for(Stringname:

ns){

System.out.println("姓名:

"+name);

}

}

}

StartService.java

publicclassStartServiceimplementsService{

//提供自动运行的方法

publicvoidautoRun(Stringnames){

//使用,号切割用户列表

String[]ns=names.split(",");

//遍历

f

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 调查报告

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1