java反射技术

Object obj = new Person("xxc",99);
//获得Class的实例的三种方式
//1.通过对象的getClass()方法获得
Class clazz1 = obj.getClass();
//2.通过表示类名的字符串来获得,注意:这里的字符串必须是完整路径,否则找不到这个类
String className = "com.xxc.reflet.Person";
Class clazz2 = Class.forName(className);
//3.用类名.class的方式获取
Class clazz3 = Person.class;
System.out.println(clazz3);
System.out.println(clazz1 == clazz3);//true
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz3 == clazz2);//true
//获取基本数据类型的Class对象,void也是一种类型。
Class intClazz = int.class;
System.out.println(intClazz);//打印int
Class voidClazz = void.class;
System.out.println(voidClazz);//打印void



/*
 * 获得类中定义的所有属性
 * getField(String name)返回一个属性,是这个类或接口当中的公共成员字段   返回类型 Field
 * getFields()返回这个类或接口中所有公共成员字段  返回类型 Field[]
 * 
 * getDeclaredField(String name)返回一个已声明的属性,可以是这个类或接口中任意权限的字段   返回类型 Field
 * getDeclaredFields() 返回这个类或借口中所有已声明的成员字段,任意权限  返回类型 Field[]
 */
Class clazz = Person.class;
Field[] fields = clazz.getDeclaredFields();
for(Field f: fields){
	System.out.println("属性名         "+f.getName());
	System.out.println("类型:   "+f.getType());
}
/*
 * 用反射获取类中的成员字段:
 * 1.先根据这个属性的名字,拿到这个属性
 * 2.设置反射的对象在使用时应该取消 Java 语言访问检查,说白了就是不受权限的限制,可以访问private
 * 3.返回指定对象上此 Field 表示的字段的值。 get(obj)参数的obj表示一个对象。返回obj对象里的字段。
 */
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
Object value = nameField.get(obj);
System.out.println(value);
/*
 * 利用反射来改某个对象里的属性,第一个参数表示要修改哪个对象,第二个表示被修改属性的值。
 * 至于修改哪个属性,并不是在参数里指定的,调用set方法的那个类就表示哪个属性
 */
nameField.set(obj, "xxm");
System.out.println(obj);


/*
 * 获得类中定义的所有方法
 * getMethod(String name, Class<?>... parameterTypes)  返回这个类或接口中公共的方法  返回类型Method  第一个参数表示哪个对象,第二个参数表示参数类型  int.class
 * 													          因为光是指定函数名没用,重载的话就不能明确指出是哪一个方法。
 * getMethods() 返回这个类或接口中所有公共的方法  返回类型是Method[]
 * 
 * getDeclaredMethod(String name, Class<?>... parameterTypes)  返回这个类或接口中任意权限的方法  返回类型是Method 
 * 
 * getDeclaredMethods() 返回这个类或接口中任意权限的所有方法 返回类型是Method[]
 */
Object obj = new Person("xxc",99);
Class clazz = obj.getClass();
Method[] methods = clazz.getDeclaredMethods();
for(Method m : methods){
	System.out.println(m.getName());//返回方法名
	System.out.println(m.getReturnType().getName());//返回方法的返回类型,如果直接是m.getReturnType()则会在返回类型前加class java.lang.String
	Class[] parameterTypes = m.getParameterTypes();//获取方法中的参数类型,并封装在一个数组中
	for(Class parameterType : parameterTypes){//遍历参数类型数组
	System.out.print("参数类型  "+parameterType.getName());//获取参数类型名称
      }
}
Method method = clazz.getDeclaredMethod("run",String.class,int.class,String.class);//获取需要调用的方法对象  第一个参数是方法名字,第二个参数是参数类型
method.invoke(obj, "xxc",20,"男");//调用方法,第一个参数是具体对象,第二个参数是方法的实参



/*通过反射获取构造函数,以及其中的参数类型,构造函数名称,用构造函数创建对象。
 *getConstructors() 获取某一个类中所有的公共权限构造函数
 *getConstructor(Class<?>... parameterTypes) 获取某一个类中指定参数类型的公共权限构造函数 
 *
 *getDeclaredConstructors() 获取某一个类中所有的任意权限的构造函数
 *getDeclaredConstructor(Class<?>... parameterTypes) 获取某一个类中指定参数类型的任意权限的构造函数
 */
Object obj = new Person("xxc",99);
Class clazz = obj.getClass();
Constructor[] constructors = clazz.getDeclaredConstructors();
for(Constructor constructor : constructors){
	System.out.println("构造函数名字"+constructor.getName());
	System.out.println("构造函数的参数类型:");
	Class[] parametersTypes = constructor.getParameterTypes();
	for(Class parametersType : parametersTypes){
		System.out.print(parametersType.getName());
		System.out.println();
	}
}
//调用有参构造函数,创建对象
/*
 * 下面这句话的第二个参数能写数组的原因是因为在1.5前,这里的第二个参数就是数组类型。
 * 它和可变参数最主要的区别就是,当调用的函数是没有参数的,那么可变参数的可以不用写,而用数组类型表示的需要写null
 */
Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
//Constructor constructor = clazz.getDeclaredConstructor(new Class[]{String.class,int.class});JDK1.5之前用的
Person person = (Person)constructor.newInstance("xxx",99);//使用反射获取的有参构造函数创建对象
System.out.println(person);



Person类

public class Person {
	private String name;
	private int age;
	
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}

	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
	public void run(String str,int age,String sex){
		System.out.println(str+"  "+age+"  "+sex);
	}
}


获取类或方法前的修饰:

Package pack = clazz.getPackage();//获取某个类的包名
System.out.println("包名--->"+pack.getName());
		
		
int num = clazz.getModifiers();//可以获取类的修饰内容
/*
 * 以下这个方法这样用有局限性,因为一个类既有public修饰,又有abstract修饰
 * Modifier.PUBLIC=1
 * Modifier.abstract=1024
 * 那么此时有两个修饰就是1025,所以再用Modifier.PUBLIC就不能正确判断了。
 * 这时可以用Modifier.isPublic(num)来进行判断。
 */
if(num == Modifier.PUBLIC){
	System.out.println("这个类的修饰符是PUBLIC");
}
if(Modifier.isPublic(num)){
	System.out.println("这个类的修饰符是PUBLIC");
}
Method run = clazz.getDeclaredMethod("run",String.class,int.class,String.class);
if(Modifier.isPublic(run.getModifiers())){//函数中也有获取修饰符类型的方法
	System.out.println("Run方法是PUBLIC修饰的");
}



练习:通过反射,做一个面向接口的,能计算任何形状面积的方法。

创建接口(此接口中有计算面积的抽象方法):

package com.xxc.reflet.test;

public interface InterfaceTest {
	double getArea();
}	


实现接口的类(圆)

package com.xxc.reflet.test;

public class ChangFangXing implements InterfaceTest{
	private double height;
	private double width;
	public double getArea() {
		return height*width;
	}
	
}


实现接口的类(长方形)

package com.xxc.reflet.test;

public class ChangFangXing implements InterfaceTest{
	private double height;
	private double width;
	public double getArea() {
		return height*width;
	}
	
}


测试:
package com.xxc.reflet.test;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Field;

public class RefletTest {
	public static void main(String[] args) throws Exception {
		System.out.println("请输入要计算的图形名称");
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String name = br.readLine();
		Class clazz;
		try {
			clazz = Class.forName("com.xxc.reflet.test."+name);
		} catch (Exception e) {
			System.out.println("不存在这样的图形");
			return;
		}
		InterfaceTest ift = (InterfaceTest)clazz.newInstance();
		Field[] parameterType = clazz.getDeclaredFields();//获得所有的数据域
		for(Field f : parameterType){
			System.out.println("请输入:"+f.getName());
			double num = Double.parseDouble(br.readLine());
			f.setAccessible(true);//将所有的域设置为可访问的。
			f.setDouble(ift, num);
		}
		double area = ift.getArea();
		System.out.println("图形面积是:"+area);
	}
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值