servlet没有主方法,但是为什么可以运行呢?
因为tomcat有主方法,servlet需要在tomcat上运行,tomcat会进行一系列的调用
用反射:
tomcat不知道我们写的类的名字,没有办法new出来
什么是反射?
拥有分析任何一个类的能力
为什么有反射?
相对于servlet来说;servlet本身没有main方法,为了让我们的servlet响应方法能够运行,我们要有分析类的能力,所以应用反射
一个类有哪些信息?
全局变量、方法、对象、构造器、父类、接口
反射能获取类的哪些信息?
凡是人眼能看到的信息,反射全部可以获取
类和对象之间的关系?
类是构建对象的模板,对象是类的实例化
反射如何获取
为什么类信息储存在方法区当中?
Java源文件先被编译成.class二进制字节码文件
static和类的关系:static修饰的变量、方法都属于类,可以被所有对象共享
this和对象的关系:this代表当前对象
this和static不能够共用
this是当前对象。所以static初始化之后,this才会被创建,static方法是没有this的,
静态方法是整个类的方法,不属于单独的类对象方法,也就是没有this这个指向对象本身的指针。
方法区存储类信息
栈:变量信息
堆:对象
类并不是直接加载到方法区中,而是通过类加载器
反射要想获取类信息,必须生成类对象
反射如何获取类信息?
三种反射获取类的方式
1.通过对象的getClass方法进行获取
2.通过Class.forName()方法获取 //里面填写类的路径 tomcat就是用的这个
调用静态方法 forName 获得类名对应的 Class 对象。
String dassName = "java.util .Random";
Class cl = Class.forName(dassName);
3.通过静态属性class可直接获取到该类型对应的Class对象 例如:T.class 将代表匹配的类对象
面试题:是否能通过反射拿到类的私有信息(暴力反射)
可以,但是这里要设置成true
加入参是因为:只根据名字不能区分两个方法,需要加上参数才能区分方法
package GUI;
import java.lang.reflect.Method;
public class Bdemo {
public static void main(String[] aaaa) throws Exception {
Class ca = Class.forName("GUI.Bperson");
Object xx = ca.newInstance();
Method aa = ca.getMethod("m1", null);
aa.invoke(xx, null);
Method aa2 = ca.getMethod("m2",int.class,String.class);
aa2.invoke(xx,100,"牛牛最帅" );
}
}
package GUI;
public class Bperson {
public void m1() {
System.out.println("嘻嘻");
}
public void m2(int aa,String bb) {
System.out.println("嗯嗯" + aa +"," + bb);
}
}
Person
public class Person {
//全局变量
private String name;
public int age;
char sex;
protected int height;
//带参构造器
public Person(String name, int age, char sex, int height) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
}
//无参构造器
public Person(){
}
public void eat(int num){
System.out.println("跑的很快");
}
private void eat(int num,String name){
System.out.println("吃的很多");
}
//同一个类中,拥有同一个方法名,不同的参数列表
void fly(){
System.out.println("飞不起来");
}
protected void jump(){
System.out.println("跳的很高");
}
}
三种反射获取类的方式
//第一种方式,磁盘节点
Class class1 = Class.forName("com.qcby.Reflection.Person");
//第二种方式,类对象阶段
Class class2 = Person.class;//用类名.class
//第三种方式:运行时阶段
Person person = new Person();
Class class3 = person.getClass();//已经生成了对象,用getClass
//用三种阶段的对象获取类信息
System.out.println("这是第一种方式");
Field[] fields1 = class1.getDeclaredFields();
for (Field field:fields1){
System.out.println(field);
}
System.out.println("这是第二种方式");
Field[] fields2 = class1.getDeclaredFields();
for (Field field:fields2){
System.out.println(field);
}
System.out.println("这是第三种方式");
Field[] fields3 = class1.getDeclaredFields();
for (Field field:fields3){
System.out.println(field);
}
反射获取类的全局变量信息的方式(用第一种方式当作例子)
java.lang.NoSuchFieldException异常
有时候使用反射进行Field相关操作的时候会出现这样异常,一般原因有两种:
1.本身就没有该Field;
2.有该Field,但是该Field是使用private修饰的,而在获取该Field的时候,需要使用getDeclaredField这个方法。
//获取全局变量信息的方式
//1.获取类当中所有的全局变量
Field[] fields4 = class1.getDeclaredFields();
for (Field field:fields4){
System.out.println("获取到的全部的类信息"+fields4);
}
Field[] fields5 = class1.getFields();
for(Field field:fields5){
System.out.println("获取的全部public类型的类信息"+fields5);
//getFileds()当前只输出了一个类信息
//方法名如果加上Declared可以获取全部信息
//不加只能获取修饰public的信息
}
//获取指定的全局变量
Field[] fieldSex = class1.getDeclaredFields();
System.out.println("获取的指定的类信息(sex)"+fieldSex);
反射获取类的全局变量
1、类.getDeclaredFields()
获取所有的全局变量 需使用field数组接收
2、getFields()
获取所有的public修饰的全局变量 需要使用field数组接收
3、类对象. getDeclaredField("变量名")
能够获取指定的任何修饰符修饰的全局变量信息,需要用filed接收
4、类对象.getFields("变量名")
能够获取指定的public修饰符修饰的全局变量信息,需要使用filed接收
获取类的方法的方式
//如果我们想要获取Person中的eat方法
Method[] methods = class1.getDeclaredMethods();
for(Method method:methods){
System.out.println("获取到的全部的方法的信息"+method);
}
Method[] methods1 = class1.getMethods();
for (Method method:methods1){
System.out.println("获取到的全部public类型的的方法的信息"+method);
}
//如果我们想要获取eat
Method method1=class1.getDeclaredMethod("eat",int.class,String.class);
System.out.println("获取到的指定的方法的类信息('eat',int.class,String.class"+method1);
class1.getDeclaredMethod("eat",int.class); // 正确写法
class1.getMethod("eat",int.class,String.class);
//错误写法 因为getMethod获取指定方法的参数类型错误 getMethod获取的是public的指定的方法信息
//而有String.class的eat方法是private类型,而不是public类型
获取成员方法的方式
1、 类对象.getDeclaredMethods()
获取所有的 方法信息, Method来接收
2、类对象.getMedthods()
获取public修饰的 方法信息 Method
3、类对象.getDeclaredMethod("方法名",所有参数类型)
获取所有指定的方法信息
4、类对象.getMethod("方法名",所有参数类型)
获取public的指定的方法信息 Method
private Person(int age){ }
Constructor constructor1= class1.getDeclaredConstructor(int.class);
constructor1.setAccessible(true);
Person person1 = (Person) constructor1.newInstance(1);
System.out.println("person1="+person1);
总结:构造方法的方式
1、 类对象.getDeclaredConstructors()
获取所有的 方法信息, Constructor来接收
2、类对象.getConstructors()
获取所有的public修饰的 方法信息 Constructor
3、类对象.getDeclaredConstructor("方法名",所有参数类型)
获取所有指定的方法信息
4、类对象.getConstructor("方法名",所有参数类型)
获取public的指定的方法信息 Constructor
如果是private修饰的需要暴力反射,否则会出现报错
constructor1.setAccessible(true);