反射机制
反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。 简单的来说,就是不通过new,使用类中的属性和方法。
为什么需要反射机制:
1 通过new创建对象 是静态加载类,在编译时刻就需要加载所的有的可能使用的类 (通过动态加载类可以解决该问题)
2 动态加载类是在运行的时刻加载 -------(一般情况下功能性的类使用动态加载类)
编译时刻加载类是静态加载类
运行时刻加载类是动态加载类
反射机制的优缺点:
优势:运行期类型的判断,动态类加载:提高代码灵活度
劣势:性能瓶颈,反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多
反射机制的应用场景:
- JDBC 的数据库的连接
- Spring 框架的使用
Class类
在面向对象的世界里,万事万物皆对象。
普通的数据类型不是对象,但是Java给我们提供了封装类,类中的静态成员不是对象,他是属于类的,类是对象,他是java.langa.Class类的实例对象
如何不用new,获取类中的属性和方法?
三种方式:
1.
类名.class
// 1.类名.class 方式都返回Class
Class class1= Foot.class;
2.
类的实例对象.getClass()
//创建类的实例对象
Foot foot = new Foot();
// 类的实例对象.getClass()
Class class2 = foot.getClass();
3.
Class.forName("类的路径")
// 3.Class.forName("类的路径");
Class class3= Class.forName("/ReflesTest/src/cn/reflex/Foot.java"); //包名+类名
创建所需要的Person类
package cn.reflex.dome;
public class Person {
//带参构造
public Person(int age, String name, String sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
//无参构造
public Person() {
}
//共有属性
public int age;
public String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//私有属性
private String sex;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
1.获取类的包名、类名
/**
* 获取包名及类名
*/
public static void Dome1(){
Class class1=Person.class;
System.out.println("类的包名"+class1.getPackage().getName());
System.out.println("类的类名"+class1.getName());
}
2.给类的属性赋值
/**
* 获取类的信息
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static void Dome2() throws InstantiationException, IllegalAccessException{
Class class1=Person.class;
Person person=(Person) class1.newInstance(); //创建Class的实例
person.setSex("男");
person.setName("小黑");
System.out.println(person.getName()+person.getSex());
}
3.获取类的构造 给构造属性赋值
/**
* 获取类的构造函数
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public static void Dome3() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Class<Person> class1=Person.class;
//构造 前提条件是类中要有构造 默认构造 无参构造
Constructor[] constructors = class1.getConstructors();
//比如在你的类中无参构造在上面[0] 带参构造[1]
//[0]下标表示类中的第一个构造
//[0]此代码中带参构造在第一个,在括号中直接的复制
Person person=(Person)constructors[0].newInstance(18,"小黑","男");
System.out.println(person.getName()+person.getSex()+person.getAge());
//[1]表示无参构造
Person person2 = (Person) constructors[1].newInstance();
person2.setAge(55);
System.out.println(person2.getAge());
}
4.获取类中的成员变量
/**
* 获取类中所有的成员变量
* */
private static void Dome4() {
Class class1=Person.class;
//成员变量不一定是一个,所有用数组接收
Field[] fields = class1.getDeclaredFields();
//循环遍历数组
for (Field field : fields) {
//如果类中有私有变量也想获取怎么办,那就加上下面这一句话
field.setAccessible(true);
//获取成员变量名称
System.out.println(field.getName());
//获取成员变量的数据类型
System.out.println(field.getType().getName());
}
}
4.1 给类中共有属性赋值
//获取类中的方法及方法中的参数 三个参数分别是 类中的方法名称 方法中的参数
Method method1 = class2.getDeclaredMethod("print",int.class,int.class);
//给方法中的参数赋值 把类的实例对象传进入
method1.invoke(foot,1,10);
4.2 给类中私有属性赋值
// 获取类中的方法及方法中的参数 方法名 参数1,参数2
Method method1 = class2.getDeclaredMethod("add", int.class, int.class);
// 如果要给私有方法赋值使用setAccessible(true)
method1.setAccessible(true);
// 给方法中的参数赋值 把类的实例对象传进入 类的对象实例,参数1,参数2
method1.invoke(foot, 1, 10);
5.
获取单个成员变量
/**
* 获取单个成员变量
* @throws SecurityException
* @throws NoSuchFieldException
*
* */
public static void Dome5() throws NoSuchFieldException, SecurityException{
Class class1=Person.class;
//想要获取成员变量的名称
Field field = class1.getDeclaredField("age");
System.out.println(field.getName());
System.out.println(field.getType().getName());
}
6.获取实现的接口名称 、继承的名字、类中的方法
创建所需的接口、类
//接口
package cn.reflex.dome;
public interface ISuper {
public void fly();
}
//类 并继承Person类 实现接口
package cn.reflex.dome;
public class Super extends Person implements ISuper {
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void Wear(String cloths) {
System.out.println("超人有"+cloths);
}
@Override
public void fly() {
System.out.println("I Can Fly");
}
}
6.1获取类中实现的接口名称
1 //获取接口
2 //可以实现多个接口,所有用数组
3 Class[] interfaces = class1.getInterfaces();
4 //遍历数组
5 for (Class<?> class3 : interfaces) {
6 System.out.println(class3.getName());
7 }
6.2获取类继承的父类名称
//获取父类名称
//在这里要得到子类中的信息
Class<Super> class1=Super.class; //子类
Class<?> class2 = class1.getSuperclass();
System.out.println(class2.getName());
6.3获取类中的方法
//获取方法
//同样方法不是一个,用数组
Method[] methods = class1.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i].getName());
}
6.4获取类中的成员
//获取类中成员
Field[] fields = class1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
7.调用类中的方法,这里用的是子类
/**
* 调用类中的方法
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InstantiationException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* */
public static void Dome7() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
Class<Super> class1=Super.class;
//1.想要调用的方法名称传过去
Method method = class1.getMethod("fly");
//创建类的实例
method.invoke(class1.newInstance());
//2.想要调用的方法名称和方法中的参数
Method method2 = class1.getMethod("Wear",String.class);
method2.invoke(class1.newInstance(), "蓝白相间");
}
执行结果:
8.使用反射操作泛型集合
比如我们定义一个数组ArrayList<String> list=new ArrayList<String>(); 想数组添加的值必须是String类型的,那如果我们想要添加int类型的怎么办?所以就要用到反射。因为
反射是在编译后执行的
泛型集合是在编译前限定的
使用反射可以绕过编译直接添加到集合中
/**
* 泛型集合
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* */
public static void Dome8() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//定义集合,向集合添加元素
ArrayList<String> list=new ArrayList<String>();
list.add("小花");
Class<? extends ArrayList> class1 = list.getClass();
//add是自已定义的,可以随便定义
Method method = class1.getMethod("add",Object.class);
method.invoke(list, 100);
System.out.println(list.size());
}
我们怎么知道是否添加到集合了呢?使用list.size()输出集合长度