Java反射就是把java类中的各个组成部分映射成相应的java类。(简单来说,反射机制指的是程序在运行时能够获取自身的信息)。
Java反射机制主要提供了以下功能,这些功能都位于 java.lang.reflect包
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法
- 生成动态代理
一、Class类
想要知道一个类具体的信息,就要先获取到这个类的字节码文件(.class)对应的Class类型的对象。通过Class类中的方法就可以获取类的信息。
1.如何获取一个类的Class实例呢?
方法一: 直接通过一个类的静态变量class获取
Class cls=类名.class
方法二:通过实例变量提供的getClass()方法获取 ,例如:
String a=""; Class cls=a.getClass();
方法三:如果知道一个类的完整类名,可以通过静态方法Class.forName()获取 ,例如:
Class cls=Class.forName("java.lang.String");
一个类的Class实例是在类加载时被创建的,而一个类只会被加载一次,(即Class实例在JVM中是唯一的),所以它的hashCode()值也是唯一的
注意:基本数据类型也有Class实例,例如:
2.Class常用方法
(1)获取包路径:getPackage()
Class cls=DayOfWeek.class;
Package p=cls.getPackage();
if(p!=null) {
System.out.println("类所在包的名称"+p.getName());
}
(2)获取类名称: getName()
Class cls=DayOfWeek.class;
System.out.println("类/接口的完全限定名"+cls.getName());
(3)获取继承类: getSuperclass()
Class cls=DayOfWeek.class;
Class sup=cls.getSuperclass();
System.out.println("类的父类是:"+sup);
(4)获取实现接口: getInterfaces()
Class[] inter=cls.getInterfaces();
System.out.println("当前类的实现接口");
for(Class i:inter) {
System.out.println(i);
}
(5)获取构造方法: getConstructor() Constructor 对象(只能获取共有的构造方法)(括号内可传入参数,传入一个参数就是得到那一个参数相对应的构造方法,不传参数就是获取无参构造方法)
Constructor c1=cls.getConstructor()
getConstructors() Constructor型数组(只能获取共有的构造方法)
Constructor[] c1=cls.getConstructors()
for(Constructor con:construArray) {
System.out.println(con);
}
getDeclaredContruector() Constructor对象(可以获得所有的构造方法,包括私有的和公有的)(括号内输入参数,如果不输入则代表私有的无参构造方法)
Constructor c2=cls.getDeclaredConstructor()
getDeclaredContruectors() Constructor型数组(包括所有的构造方法)
Constructor[] c2=cls.getDeclaredConstructors()
(6)根据反射创建对象: newInstance()
// 读取类的名称
String filename=Files.readAllLines(Paths.get("E:\\学习文\\Cup.txt")).get(0);
// 得到类的对象
Class cls=Class.forName(filename);
// 创建3个对象
// 调用newInstance()相当于 Cup c=new Cup()
// 执行无参构造方法
Object o1=cls.newInstance();
Object o2=cls.newInstance();
Object o3=cls.newInstance();
System.out.println(o1);
System.out.println(o2);
System.out.println(o3);
(7)获取方法: getMethods() Methods型数组
Method[] m=cls.getMethods();
getDeclaredMethods() Methods对象
Method[] m=cls.getDeclaredMethods();
(8)获取成员变量: getFields() Field型数组
//所有public访问修饰符定义的字段(包括父类的)
Field[] f=cls.getFields();
getDeclareFileds() Field对象
//仅包含子类自己的
Field[] f=cls.getDeclaredFields();
二、Constructor类
(1)得到类的所有构造方法
Constructor constructors[]=Class.forName("java.lang.String").getConstructors();//先得到类对应的字节码对象,再得到构造方法
(2)得到类中某个具体的构造方法,在getConstructor中传入参数类型所对应的字节码
Constructor constructor=Class.forName("java.lang.String").getCondtructor(String.class)//得到String 类的 带有一个String类型参数的构造方法
使用Constructor类的目的是:用来创建相应类的对象
- 先得到一个类的构造方法;
- 然后再通过构造方法创建出类的对象
正常情况(不采用反射):String str=new String("hello");
反射情况:
1.先拿到String这个类的带有一个String类型参数的构造方法对象
Constructor con=String.class.getConstructor(String.class)
2.然后通过构造方法的newInstance()方法创建String类型的对象
String str=(String)con.newInstance("hello")
//传入字符串的值hello并要在前面通过强制类型 转换转换成String 类型的对象
三、Interface
查询一个类实现的接口
System.out.println("实现接口列表:");
Class[] cls2=String.class.getInterfaces();
for(Class c:cls2) {
System.out.println(c);
}
四、Field
- Class.getFields():得到Class对象的所有字段,返回的是Field数组
- Class.getField(String name)返回一个Field对象,它反映此Class对象所表示的类或接口的指定公有成员字段
- Field的对象所代表的某一个类的属性,而不是那个类的某一个对象的属性;如果要得到某个对象对应的属性值,需要通过get(Object obj)方法与某个对象具体关联
- 对于非公有属性只能通过Class的getDeclaredField(String fieldName)方法得到
- 对于私有属性要得到它所关联到的对象的值,通过Field的setAccessible(boolean boolean)方法设置
- Field类的getType()方法用来得到字段所属的类型
- Field类的getModifiers()方法用来获取成员变量访问修饰符
-
如果一个属性是私有属性,则那还需要调用setAccessible(true)来允许访问私有的属性
-
给成员变量赋值用set()方法,获取成员变量的值用get()方法
Class cls=Book.class; // 所有public访问修饰符定义的字段(包括父类的) // Field[] f=cls.getFields(); // 仅包含子类自己的 Field[] f=cls.getDeclaredFields(); for(Field file:f) { System.out.println("成员变量访问修饰符"+file.getModifiers()); System.out.println("成员变量名称:"+file.getName()); System.out.println("成员变量类型:"+file.getType()); System.out.println("成员变量访问修饰符:"+Modifier.toString(file.getModifiers())); }
给成员变量赋值:
Book类:
package com.ZhangSha.day10;
public class Book extends Product{
public String BookName;
private String auther;
private double price;
public double buy(double p,int v) {
System.out.println("您的会员等级为:"+v);
System.out.println("打折后价格为:");
return p*v*0.1;
}
private void jie() {
System.out.println("借书了");
}
public void buy() {
System.out.println("啦啦啦啦买东西了");
}
public String getBookName() {
return BookName;
}
public void setBookName(String bookName) {
BookName = bookName;
}
public String getAuther() {
return auther;
}
public void setAuther(String auther) {
this.auther = auther;
}
public double getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Book [BookName=" + BookName + ", auther=" + auther + ", price=" + price + "]";
}
public void BookName(String string) {
// TODO Auto-generated method stub
}
public Book(String bookName) {
super();
BookName = bookName;
}
public Book() {
super();
}
}
Class cls=Book.class;
Object obj=cls.newInstance();
// getField() 获取共有的成员变量
// getDeclaredField() 获取所有的成员变量(包括共有的和私有的)
// Field f=cls.getDeclaredField("BookName");
Field f=cls.getField("BookName");
f.set(obj, "lalla");
System.out.println(obj);
Field f2=cls.getDeclaredField("auther");
// 私有的成员变量就要设置setAccessible为true
f2.setAccessible(true);
f2.set(obj, "苏涵");
System.out.println(obj);
获取成员变量的值:
package com.aPesource.day6;
import java.lang.reflect.Field;
import com.ZhangSha.day10.Book;
public class IS_class5 {
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
Book b=new Book();
b.setBookName("书香");
b.setAuther("姜邢");
b.setPrice(87);
printinfo(b);
}
public static void printinfo(Object obj) throws IllegalArgumentException, IllegalAccessException {
Class cls=Book.class;
Field[] field=cls.getDeclaredFields();
for(Field f:field) {
System.out.println("成员变量名称:"+f.getName());
if(!f.isAccessible()) {
f.setAccessible(true);
}
System.out.println("成员变量内容:"+f.get(obj));
}
}
}
五、Method类
Method类用来表示类中的方法,通过Class对象的如下方法得到Method对象:
(1)Method getMethod(String name,Class<?>...parameterTypes)//要给出方法的名称和参数所对应的class类型 按名称得到某个特定的public方法(包括从父类或接口继承的方法)
(2)Method[] getMethods() 得到public方法(包括从父类或接口继承的方法)
(3)Method[] getDeclaredMethods() 得到所有的方法(不包括继承的方法)
(4)Method getDeclaredMethod(String name,Class<?>...parameterTypes) 按名称得到某个特定的方法(不包括继承的方法)
得到Method对象后,需要调用以下方法来在某个对象上执行该方法:
(1)invoke(Object obj,Object obj)第一个是在哪一个对象上调用,第二个是所要调的这个对象所要传入的实参(如果是静态方法则第一个为null)
(1)获取方法
//反射操作:获取方法
//每一个方法都会被封装成一个Method对象
public class IS_getMethod {
public static void main(String[] args) {
Class cls=Book.class;
// 包括继承的父类的所有方法
// Method[] m=cls.getMethods();
// 只包含子类的所有方法
Method[] m=cls.getDeclaredMethods();
for(Method method:m) {
System.out.println("方法的访问修饰符"+Modifier.toString(method.getModifiers()));
System.out.println("方法的返回值类型"+method.getReturnType());
System.out.println("方法的名称:"+method.getName());
System.out.println("------------------------");
// 获取所有的参数类型
System.out.println("方法的参数类型:");
Class[] p=method.getParameterTypes();
System.out.println(Arrays.toString(p));
System.out.println("----------------------------------");
// 获取所有的参数对象
Parameter[] p1=method.getParameters();
for(Parameter para:p1) {
System.out.println("参数名称"+para.getName());
System.out.println("参数类型"+para.getType());
}
}
}
}
(2)调用方法
//反射操作:调用方法
public class IS_getMethod2 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
Class cls=Book.class;
Object obj=cls.newInstance();//创建Book对象
Method m=cls.getMethod("buy",double.class,int.class);
// Method对象的invoke()作用
// 以反射的方式执行create()方法
double d=(double) m.invoke(obj, 87.6,3);
System.out.println(d);
}
}
(3)以反射的方式调用静态方法
//以反射的方式调用静态方法
public class IS_getMethod3 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// 计算以10为底的对数,获取某个数组的位数
System.out.println(Math.log10(84738)+1);
// 反射调用
Class math=Math.class;
Method m=math.getMethod("log10", double.class);
int size=Double.valueOf((double)m.invoke(null, 56728283)).intValue()+1;
System.out.println(size);
}
}
六、获取继承关系
instanceof 判断是否是什么类型 判断“引用”和“类型”之间的关系
isAssignableFrom 只有父类的引用才可以指向子类的对象,反之则不可 判断“类型”和“类型”之间的关系