目录
2.Constructor[ ] getConstructors()方法
4. Constructor[ ] getDeclaredConstructors()方法
3. getDeclaredField(String name)方法
一. 反射引入
回忆一下我们之前是如何使用类和对象的,首先我们会先定义一个类,其次new一个该类的具体对象,通过对象调用该类中的属性和方法,这对于我们自己的业务开发是没有问题的,因为一切都是已知的,但是像框架,tomcat,或者一些其他组件而言,他们事先是不知道有哪些类的,更不知道要创建哪些类的对象,只能根据我们配置的类的地址决定要操作哪个类,那么他们是如何根据类的地址,去创建该类的对象,并调用该类的方法,将我们查询到的数据封装到一个该类的对象中,这就要用到我们说的反射的概念
二. 反射概念和作用
反射机制:在程序运行的过程中,可以动态的获取类信息,可以动态创建类对象,可以调用对象的成员属性和方法的机制
作用:动态获取类信息
那么我们如何在程序运行过程中获得类信息? 可以通过Class类的对象来获得类信息
三. Class类
java为我们提供了一个Class类,当一个类被加载时,会为其创建一个Class类的对象,用来表示该类,通过Class类的对象可以获取该类中的所有信息
那么我们如何获得Class类的对象? 有以下三种方法可以获得Class类的对象
3.1 获得Class类的对象
1. 通过Class类中的forName()方法
public class Test2 {
//获得Class类的对象的三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式1
String s = "com.ffyc.javareflect.demo2.User";
Class c1 = Class.forName(s);//把给定地址的类进行了加载,为其创建Class对象
Class c2 = Class.forName(s);//把给定地址的类进行了加载,为其创建Class对象
System.out.println(c1);
System.out.println(c1==c2);
}
}
这种方式框架常用,通过我们在配置文件中配置的类的地址,框架可以得到该类的Class类的对象,从而就能拿到我们类中的一切信息,帮我们将查询到的信息封装到一个对象中
2. 直接用类名.Class
public class Test2 {
//获得Class类的对象的三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式2
Class c3 = User.class;
System.out.println(c2==c3);
}
}
3. 通过调用该类对象中的getClass()方法
public class Test2 {
//获得Class类的对象的三种方式
public static void main(String[] args) throws ClassNotFoundException {
//方式3
User user = new User();
Class c4 = user.getClass(); //通过已知的对象中的getClass()获得该对象类的Class对象
}
}
通过上述三种方法中的任意一种都能获得Class类的对象,有了Class类的对象,就可以任意的获取类中的信息
注意: 对于任意一个类,它的Class类的对象只有一个,但该类的对象可以有多个.这点要注意区分
我们获取到Class类的对象后,如何根据Class类的对象获得类中的信息呢?
四. 获取类中的构造方法
我们可以通过Class对象中的getConstructor等方法获得类中的构造函数如下
1.getConstructor() 方法
调用Class类中的Constructor getConstructor(Class<?>... parameterTypes) 方法获得指定(参数个数,类型)的公共的构造方法, 返回Constructor 来表示获得到的构造方法
因为构造方法的名字都相同,我们要想获得不同的构造方法只能通过参数的类型和个数来进行区分,所以当我们通过Class类的对象来调用getConstructor方法时,如果不传参数,获得的是公共的无参构造方法,如果想获得有参的构造方法,只需要传对应参数的类型的Class类对象
当我们获取到构造方法时,就又多了一种创建对象的方法,我们可以通过返回的Constructor对象来调用newInstance(); 创建具体类的对象
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String s = "com.ffyc.javareflect.demo2.User";
//加载类,并获得类的Class对象
Class c = Class.forName(s);
//通过Class类的对象,来创建User对象
//Object userobject = c.newInstance();
//System.out.println(userobject);
//获取类中的构造方法信息
Constructor constructor = c.getConstructor();//获得类中指定的公共的构造方法,将获得到无参的构造方法封装到一个Constructor中
Object userobject = constructor.newInstance();//通过构造方法中newInstance()创建对象
System.out.println(userobject);
Constructor constructor2 = c.getConstructor(String.class,String.class);//获得公共的有参构造方法
Object userobject1 = constructor2.newInstance("111","222");//创建对象,并为对象属性赋值
User user = (User) userobject1;
System.out.println(user);
}
}
总结创建对象的几种方式:
- new关键字
- 通过io流进行序列化和反序列化,反序列化时将对象从文件中读入到java程序中并创建对象
- 反射,通过Class类的对象中的newInstance()方法创建具体类的对象
- 反射,通过获得的构造方法中的newInstance()方法创建具体类的对象
2.Constructor[ ] getConstructors()方法
Constructor[ ] getConstructors()方法用于获得所有的公共的构造方法,并放到一个数组中
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String s = "com.ffyc.javareflect.demo2.User";
//加载类,并获得类的Class对象
Class c = Class.forName(s);
Constructor[] constructors = c.getConstructors();//获得所有的公共的构造方法
System.out.println(constructors.length);
}
}
3. getDeclaredConstructor()方法
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)获得指定的构造方法(包含私有,受保护,默认.公共)
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String s = "com.ffyc.javareflect.demo2.User";
//加载类,并获得类的Class对象
Class c = Class.forName(s);
Constructor constructor1 = c.getDeclaredConstructor();//获得类中指定的构造方法(包含私有的)
}
}
注意:
getConstructor()方法是获得指定参数的公共的构造方法
getDeclaredConstructor方法是获得指定参数的构造方法(包含私有)
4. Constructor[ ] getDeclaredConstructors()方法
Constructor<?>[] getDeclaredConstructors()获得所有的构造方法包含私有
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String s = "com.ffyc.javareflect.demo2.User";
//加载类,并获得类的Class对象
Class c = Class.forName(s);
Constructor[] constructors1 = c.getDeclaredConstructors();//获得所有的构造方法(包含私有的)
System.out.println(constructors1.length);
}
}
注意:
Constructor[ ] getDeclaredConstructors()方法可以获得所有的构造方法,包含私有
Constructor[ ] getConstructors()方法只能获得所有的公共的构造方法
五. 获取类中的成员变量
1. getField(String name)方法
Field field = getField(String name):获得指定名字的公共属性, 返回Field对象 表示获得属性
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String s = "com.ffyc.javareflect.demo2.User";
Class c = Class.forName(s);//获取类的Class对象
Object userobject = c.newInstance();//创建User类的对象
//获得类中的成员变量
//获得类中指定的公共的属性,把属性封装到一个Field对象中
Field userNameField = c.getField("userName");
}
}
2. getFields()方法
Field[] field = getFields(); 获得所有的公共的属性
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String s = "com.ffyc.javareflect.demo2.User";
Class c = Class.forName(s);//获取类的Class对象
Object userobject = c.newInstance();//创建User类的对象
//获得所有公共的属性
Field[] fields = c.getFields();
System.out.println(fields.length);
}
}
3. getDeclaredField(String name)方法
Field field = getDeclaredField(String name);获得指定名字的属性(包含私有)
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String s = "com.ffyc.javareflect.demo2.User";
Class c = Class.forName(s);//获取类的Class对象
Object userobject = c.newInstance();//创建User类的对象
//获得类中指定的属性(包含私有,受保护,默认,公共),把属性封装到一个Field对象中
Field userNameField = c.getDeclaredField("userName");
}
}
注意:
getField(String name)方法只能获得指定名字的公共成员变量
getDeclaredField(String name)方法既可以获得公共的也可以获得私有的
4. getDeclaredFields()
Field[] field = getDeclaredFields();获得所有属性(包含私有)
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String s = "com.ffyc.javareflect.demo2.User";
Class c = Class.forName(s);//获取类的Class对象
Object userobject = c.newInstance();//创建User类的对象
//获得所有的属性(包含私有的)
Field[] fields = c.getDeclaredFields();
System.out.println(fields.length);
//循环所有的属性,为属性赋值
for (Field f : fields){
f.setAccessible(true);//设置私有属性可以操作
f.set(userobject, "111");
}
System.out.println(userobject);
}
}
注意:
getFields()方法只能获得所有的公共的成员变量
getDeclaredFields()方法可以获得所有的成员变量(包含私有的)
六. 获取类中的成员方法
1. getMethod()
getMethod(String name,类<?>... parameterTypes)可以获取指定名字和参数的公共成员方法,因为java有方法重载所以不能只根据名字来确定获取哪个方法,还要通过参数类型和个数来加以区分
2. getMethods()
Methods[] getMethods()方法可以获取本类和父类所有公共的成员方法
3. getDeclaredField()
getDeclaredField(String name,类<?>... parameterTypes)可以获得指定名字和参数的成员方法(包含私有)
4. getDeclaredMethods()
getDeclaredMethods()方法可以获得本类的所有方法(包含私有)
以上方法只是获得了类中的成员方法,要调用类中的成员方法,需要用获得的成员方法的变量去调用invoke()方法,才能达到调用了成员方法的目的
public class Test5 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String s = "com.ffyc.javareflect.demo2.User";
Class c = Class.forName(s);
Object objectuser = c.newInstance();
Method eat = c.getMethod("eat" );
eat.invoke(objectuser );
Method eats = c.getMethod("eat", String.class);// 这个只是获得了成员方法
eats.invoke(objectuser, "肉"); //这才是真正调用了该成员方法
Method[] methods = c.getMethods();//获得本类和父类中所有公共的成员方法
Method[] methods1 = c.getDeclaredMethods();//获得本类中所有成员方法
System.out.println(methods.length);//15
System.out.println(methods1.length);//7
}
}
七. 反射的优缺点
优点:
1.增加程序的灵活性,可以在程序运行过程中动态的对类进行修改和操作
2.提高代码的复用率,比如动态代理
3.可以在运行过程中轻松获取任意一个类的方法,属性,并且还能通过反射进行动态调用
缺点:
1.反射会涉及到动态类型的解析,导致性能比非反射调用更低
2.使用反射技术通常要在一个没有安全限制的程序运行
3.反射可以绕过一些限制访问的属性或者方法,可能会导致破坏代码本身的抽象性