Java基础反射
一、前言
反射机制的存在允许程序在执行期借助reflection API来实现获取任何类的内部信息,并能直接操作任意对象的内部属性及方法,简而言之就是不采取常规的new一个对象来实现对象的创建,而是用类来创建对象操作对象,使用场景往往是编写代码时部分功能还不确定何时被使用?哪一部分会被使用?(什么时候用?用哪一个的问题)二、反射提供的功能
- 对象的创建
- 获取类的属性
- 获取类内部的方法
- 判断一个对象所属的类
- 获取泛型信息
- 处理注解
- 生成动态代理
反射所提供的功能都发生在程序的运行过程当中,实时动态的处理对象的有关问题
三、相关API
Java.lang.Class:代表一个类
Java.lang.reflect.Method:代表类的方法
Java.lang.reflect.Field:代表成员变量
Java.lang.reflect.Constructor:代表类的构造器
四、class类
- 在object类中定义的方法
该方法被所有的类继承,此方法返回的类就是一个class类public final Class getClass()
- class类的常用方法
- newInstance():通过调用无参构造器实现实例化
Class personClass = person.class;
Object o = personClass.newInstance();
System.out.println(o.toString());
结果:
五、实例
@Test
public void test1() throws Exception {
//获取对象的class类
Class personClass = person.class;
//获得类的名称
String name = personClass.getName();
System.out.println(name);
//直接获取无参对象
Object o = personClass.newInstance();
System.out.println(o.toString());
//通过反射创建对象
//获得构造器
Constructor constructor = personClass.getDeclaredConstructor(String.class,String.class);
//通过构造器创建对象
Object tom = constructor.newInstance("tom","12");
//调用对应的属性
Field age = personClass.getDeclaredField("age");
age.setAccessible(true);
age.set(tom, "10");
//调用方法
Method show = personClass.getDeclaredMethod("show");
show.setAccessible(true);
show.invoke(tom);
//输出tom的信息
System.out.println(tom);
}
public class person {
private String name;
private String age;
public person(String name, String age) {
this.name = name;
this.age = age;
}
private person(String name) {
this.name = name;
}
public person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public void show(){
System.out.println("这是show方法!!");
}
@Override
public String toString() {
return "person{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
六、发现的一些问题
正常情况下通过反射的方式可以拿到对象的私有属性和私有的方法,而常规方法是无法使用类内部私有的方法和属性,但是如果用错方法就还是拿不到这些私有的东东
譬如:
Field age = personClass.getField("age");
//当我们调用的是getField方法时,该属性只能是public修饰
//如果想获得的属性是private的话,只能用getDeclaredField方法来获取
同理在调用构造器和方法时也要注意这个问题
七、在项目中发现的一些东西
咳咳…后面才是今天得正题
前端页面我写了一个表单是这样的:
<form action="userServlet" method="post">
<input type="hidden" name="action" value="login" />
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名"
autocomplete="off" tabindex="1" name="username"
value="${requestScope.username}" />
<br />
<br />
<label>用户密码:</label>
<input class="itxt" type="password" placeholder="请输入密码"
autocomplete="off" tabindex="1" name="password" />
<br />
<br />
<input type="submit" value="登录" id="sub_btn" />
</form>
这个页面我觉得大部分人都可以读懂,主要想说的是在这里我是用了一个隐藏域hidden,提交了一个键值对< action login >,有没想过为什么要传这样一个值呢?
接下来讨论得是Javaweb原生得一些东西,虽然我知道后边得springboot等一些框架在这方面已经做的很好了,但是我仍认为这是一种懒汉方式,有些注解只是知道怎么用还是不行的,现在我们就javaweb这种原生的方式来说一下怎么解决servlet的映射问题
一个servlet应用中可能包含多种方法,但是映射关系确是
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>com.warrior.web.testServlet</servlet-class>
</servlet>
也就是说访问一个程序的时候,要实现的功能只能在doget()或者doPost()方法中写一坨,这样不利于解耦,于是我们就可以通过反射的方式去获取servlet类中的相应方法并执行来解决这个问题
看这个例子:
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决post请求中文乱码问题
// 一定要在获取请求参数之前调用才有效
req.setCharacterEncoding("UTF-8");
// 解决响应的中文乱码
resp.setContentType("text/html; charset=UTF-8");
String action = req.getParameter("action");
try {
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// System.out.println(method);
// 调用目标业务 方法
method.invoke(this, req, resp);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);// 把异常抛给Filter过滤器
}
}
首先写一个抽象的servlet类,其余servlet类都继承该类,我们在重写HttpServlet类的方法的时候,获取参数中的关键字来判断最终使用该类的哪一个方法