获取继承关系:获取父类+获取接口
获取父类和继承的方法为:
- getSuperclass() --> 获取当前对象的父类
- getInterfaces() --> 获取当前对象实现的接口
有了class实例,可以通过该实例获取它的父类,以及它所实现的接口
//反射操作:获取继承关系
public class Demo6 {
public static void main(String[] args) {
//父类
Class superClass = FileInputStream.class.getSuperclass();
System.out.println("父类:"+superClass.getName());//java.io.InputStream
System.out.println("父类的父类:"+superClass.getSuperclass().getName());//java.lang.Object
//System.out.println("父类的父类的父类:"+superClass.getSuperclass().getSuperclass().getName());
//接口
System.out.println("==========实现接口列表");
Class[] interfaceClassArray = MyStringComparator.class.getInterfaces();
for(Class inf : interfaceClassArray) {
System.out.println(inf.getName());
}
}
}
class MyStringComparator implements Serializable,RandomAccess{
//....
}
在继承树中Object类位于根节点,它没有父类且它时所有类的父类
判断继承关系
instanceof运算符:判断某个引用类型的对象是否是某个引用类型,用于向下转型
isAssignableFrom()方法:判断某个类型是否可以被某个类型调用,判断向上转型是否成立
//判断继承关系
public class Dmeo7 {
public static void main(String[] args) {
//instanceof运算符:判断"引用"和"类型"之间的关系
Object obj = Integer.valueOf(3211);//Integer继承了Number,实现了Comparable
System.out.println("是否为Intege类型?"+(obj instanceof Integer));
System.out.println("是否为Double类型?"+(obj instanceof Double));
System.out.println("是否为Number类型?"+(obj instanceof Number));
System.out.println("是否为Comparable类型?"+(obj instanceof Comparable));
//isAssignableFrom()方法:判断"类型"与"类型"之间的关系
System.out.println("Integrt => Integer?" + Integer.class.isAssignableFrom(Integer.class));
System.out.println("Number => Integer?" + Integer.class.isAssignableFrom(Number.class));
System.out.println("Integrt => Number?" + Number.class.isAssignableFrom(Integer.class));
System.out.println("Integrt => Comparable?" + Comparable.class.isAssignableFrom(Integer.class));
}
}
访问字段
对于任意一个Object类,获取了它的Class类,就可以获取它的全部信息。以下就是获取它的字段信息,也就是它的成员变量信息,并通过不同的方法获取其成员变量中的某一个具体的信息。
获取字段的方法有:
方法 | 作用 |
getFields() | 获取public访问修饰符定义的字段(包含父类) |
getDeclaredFields() | 获取所有定义的字段(仅包含自己) |
getField(name) | 根据字段名获取某个public访问修饰符定义的字段(包含父类) |
getDeclaredField(name) | 根据字段名获取某个定义的字段(仅包含自己) |
获取该字段的具体某个信息:
方法 | 作用 |
getModifiers() | 获取成员变量访问修饰符,返回值是int类型 |
Modifier.toString(f.getModifiers()) | 获取成员变量访问修饰符,返回值String类型 |
getType() | 获取成员变量类型 |
getName() | 获取成员变量名称 |
//反射操作:访问字段(成员变量)
//每个字段都会被封装成一个Field对象
public class Demo8 {
public static void main(String[] args) {
Class cls = Book.class;
//获取public访问修饰符定义的字段(包含父类)
//Field[] fields = cls.getFields();
//获取所有定义的字段(仅包含自己)
Field[] fields = cls.getDeclaredFields();
for(Field f : fields) {
System.out.println("成员变量访问修饰符(int):"+f.getModifiers());
System.out.println("成员变量访问修饰符:"+Modifier.toString(f.getModifiers()));
System.out.println("成员变量类型:"+f.getType());
System.out.println("成员变量名称:"+f.getName());
System.out.println();
}
}
}
class Book{
public String name;
public int stock;
private Date dateTime;
private double sale;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStock() {
return stock;
}
public void setStock(int stock) {
this.stock = stock;
}
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date dateTime) {
this.dateTime = dateTime;
}
public double getSale() {
return sale;
}
public void setSale(double sale) {
this.sale = sale;
}
@Override
public String toString() {
return "Book [name=" + name + ", stock=" + stock + ", dateTime=" + dateTime + ", sale=" + sale + "]";
}
}
存入字段值
在获取到成员变量后,我们主要是相对成员变量进行一些操作,比如给它赋值或者获取它的值等,在硬编码阶段,会通过创建已知类型的实例化对象,并调用它的get或set方法进行取值或赋值,但是在不知目标实例的情况下,我们就需要通过反射的方法来进行操作。
以存值为例:
首先需要获取Class类型的对象,通过newInstance()方法以无参构造创建实例,然后获取我们想要存值的那个字段,并通过set方法给它传入我们所要存入的值。
//通过反射方式,完成成员变量值保存
public class Dmeo9 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
//编译期完成对象类型和成员变量的访问
//Book book = new Book();
//book.setName = "活着";
//运行期
//使用反射的方式。完成成员变量保存值
Class cls = Book.class;//获取Class类型对象
Object obj = cls.newInstance();
//公有成员变量
//按照字段名称,获取指定字段
Field field = cls.getDeclaredField("name");
//参数1:目标Book对象
//参数2:存入成员表变量的值
field.set(obj, "活着");
//私有成员变量
Field field2 = cls.getDeclaredField("dateTime");
field2.setAccessible(true);
field2.set(obj, new Date(2,5,24));
System.out.println(obj);
}
}
访问成员变量的值:
//反射操作:访问对象中的成员变量(字段)值
public class Demo10 {
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
Book book = new Book();
book.setName("活着");
book.setSale(32);
book.setStock(333);
book.setDateTime(new Date(2,5,24));
printInfo(book);
}
public static void printInfo(Object obj) throws IllegalArgumentException, IllegalAccessException {
//输出参数对象的所有成员变量和值
Class cls = obj.getClass();
Field[] fields = cls.getDeclaredFields();
for(Field field : fields) {
System.out.println("成员变量名称:" + field.getName());
//判断是否可以访问
if(!field.isAccessible()) {
field.setAccessible(true);
}
System.out.println("成员变量内容:" + field.get(obj));
}
}
}
注意:
- 想要对访问修饰符为Private的成员变量进行访问时,必须设置setAccessible()为true
- set方法进行存值时,第一个参数为目标Book对象,第二个参数为存入成员变量的值
获取方法
通过class实例获取方法时,所有方法都会被封装成一个Method对象,C获取方法的方法有
方法 | 作用 |
getMthods() | 获取public访问修饰符定义的方法(包含父类) |
getDeclaredMthods() | 获取所有定义的方法(仅包含自己) |
getMthod(name) | 根据方法名获取某个public访问修饰符定义的方法(包含父类) |
getDeclaredMthod(name) | 根据方法名获取某个定义的方法(仅包含自己) |
//反射操作:获取方法
//每一个方法都会被封装成一个Method对象
public class Demo11 {
public static void main(String[] args) {
Class cls = Book.class;
//获取所有public方法(包括父类)
//Method[] method = cls.getMethods();
//获取所有方法(仅包含当前类)
Method[] method = cls.getDeclaredMethods();
for(Method m : method) {
System.out.println("获取方法的访问修饰符:" + Modifier.toString(m.getModifiers()));
System.out.println("获取方法的名称:" + m.getName());
System.out.println("获取方法的返回值类型:" + m.getReturnType());
//获取所有的参数类型
//Class[] types = m.getParameterTypes();
//System.out.println("获取所有的参数类型:" + types);
//获取所有的参数对象·
Parameter[] para = m.getParameters();
for(Parameter p : para) {
System.out.println("获取参数类型名:"+p.getName());
System.out.println("获取参数类型:"+p.getType());
System.out.println("==============================");
}
}
}
}
调用方法
在硬编码调用方法时,首先通过A a = new B(),创建该类型的对象,再通过对象名.方法名对方法进行调用,在反射操作中,首先应获取需要的Class对象,然后通过newInstance()方法创建该对象(无参构造,有参构造使用Constustor),再通过getMethod()方法获取该方法,使用invoke(),以反射的方式执行该方法。
invoke() --> 最常用的方法对象的方法,第一个参数:类型对象,第二个参数:需要传入的值
//反射操作:调用方法
public class Demo12 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//Base b = new Base();
//int r = b.create();
//int r = b.create(100);
//获取Calss对象
Class cls = Base.class;
Object obj = cls.newInstance();//创建Base对象
//按照方法名称和”参数类型“获取Methid方法对象
//create():无参方法
//Method method = cls.getMethod("create");
//create(int x):有参方法
Method method = cls.getMethod("create", int.class);
//Method对象的invoke()方法
//以反射的方式执行create()方法
int r = (int)method.invoke(obj, 1000);
System.out.println(r);
}
}
class Base{
public int create() {
return create(100);
}
public int create(int x) {
return (int) Math.random();
}
}
当使用标准库中的类名调用某个方法时,invoke()的一个参数设置为null即可
//调用方法:类名调用
public class Dmeo13 {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
//计算以10为底的对数
//获取莫个指定数字的位置
System.out.println((int)Math.log10(123345)+1);
//反射调用
Class cls = Math.class;
Method methodLog10 = cls.getDeclaredMethod("log10", double.class);
int size = Double.valueOf((double)methodLog10.invoke(null, 123345)).intValue()+1;
System.out.println(size);
}
}