Java反射机制基础之反射操作(继承关系+字段的操作)

获取继承关系:获取父类+获取接口

获取父类和继承的方法为:

  1. getSuperclass() --> 获取当前对象的父类
  2. 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);	
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值