反射相关


反射相关:[ 利用反射的各种操作都是在运行期进行的. ]


1.在面向对象的世界里,万事万物皆对象.

但是java语言中,静态的成员 与基本数据类型类 不是对象.

类是不是对象? 谁的对象呢?

类是对象,任何类都是java.lang.Class类的实例对象.

2.类java.lang.Class的对象到底如何表示呢?(与普通类的对象区别)

[There is a class named 'Class'] 一个名叫Class的类.

//官方称呼为: (一个类的)类类型(Class Type).

//一个类只能有一个类类型,或者理解成,它只是Class类的一个具体的实例对象.

所以,不管通过以下三种中任何一种方式,得到同一个类的类类型都是相同的.(都是同一个Class类的实例对象).

[上面关于类类型的理解一定要把握好.] 

已知一个类Foo, Foo f1=new Foo();

1.Class c1=Foo.class;[实际在告诉我们任何一个类都有一个隐含的静态成员变量class]

2.Class c2=f.getClass();[通过某个类的一个对象获取此类的类类型]

3.Class c3=Class.forName("包名.类名");[直接指定类的全称进行获取]

并且,c1==c2==c3.因为都是指Class的同一个实例对象Foo.该类称为Foo的类类型.

得到了某个类的类类型后,我们就可以通过它去创建该类的实例对象:

Foo f2 = (Foo) c1.newInstance();[前提是此类(Foo)必须要有无参构造方法]

3.Java动态加载类

1.Class.forName("类的全称").第三种途径则是动态加载类.

.不仅表示了类的类类型,还代表了是动态加载类.

.要区分开编译与运行.

.编译时刻加载类是静态加载类/运行时刻加载类是动态加载类.

public Class Office{

public static void main(String[] args){

//使用NEW关键字创建对象,是静态加载类,在编译时刻就需要

//加载所有的可能用到的类.所以相关的类不论是否用到都必须存在.

if("Word".equals(args[0]){

Word  w=new Word();

w.start();

}

if("Excel".equals(args[0]){

Excel e=new Excel();

e.start();

}

}

}

但是,我们更希望在使用的时候,用到哪个类(功能)去加载哪个类,不用的不加载.那么上面的例子是做不到的.因为不论用到哪个,其他的类必须全部存在.

那么,如何解决?----动态加载类,在运行时,用到哪个类再去加载哪个类.

public Class OfficeBetter{

public static void main(String [] args){

//动态加载指定类.

Class c=Class.forName(args[0]);

OfficeAble oa=(OfficeAble)c.newInstance();

//多态:实际是哪个类,就调用实际类中此项功能.

oa.start();

}


}

//给各个类制定一个统一的标准.(多态的应用)

public interface OfficeAble{

void start();

}

这样在编译OfficeBetter时,是完全通过的.而在运行时,需要你去指定具体用到哪个类,它就会去加载这个类.(非常好的设计思想@_@)

[所以,以后功能性的类尽量用这种设计思想,尽量用动态加载.这样更新的时候,只需要添加,删除各个功能类并且让各个功能类实现这一统一的标准(接口)]


4.反射获取方法的信息(返回值类型,方法名,参数类型)

Class c1=int.class;

Class c2=String.class;

Class c3=double.class;//与下面的Double完全不同.

Class c4=Double.class;

Class c5=void.class;

基本数据类型,void都有对应的类类型.

public Class ClassUtil{

public static void printMethodInfo(Object obj){

//首先获取对象所属类的类类型

Class c=obj.getClass();

//获取类的类名称

system.out.println("类的名称:"+c.getName());

//java.lang.reflect.Method类,万事万物皆对象,那么任何一条方法也是这 //Method类的对象.

//此方法获取的是所有的public 的函数,包括从父类继承来的方法(肯定 是public方法)

Method[] methods=c.getMethods();

//此方法返回的是此类自己声明的所有方法(包括public&private方法)

Method[] methods1=c.getDeclaredMethods();

for(int i=0;i<methods.length;i++){

//得到返回值类型的类类型(int.class,void.class)

Class returnType=methods[i].getReturnType();

//得到了返回值类型的名字.

system.out.print(returnType.getName());

//得到了方法的名字.

system.out.print(methods[i].getName());

//得到方法的参数类的类类型

Class[] paramTypes=method[i].getParameterTypes();

for(int j=0;j<paramTypes.length;j++){

//得到具体某个参数类型的名字

system.out.print(paramTypes[j].getName());

}

}

}

//成员变量也是对象.

//java.lang.reflect.Field类的对象.

//此类封装了关于成员变量的操作.

//getFields():获取所有public的成员变量

//getDeclaredFields():获取所有此类自己声明的成员变量(public&private)

public static void printFieldInfo(Object obj){

Class c=obj.getClass();

Field[] fields=c.getDeclaredFields();

for(Field field:fields){

//获得此成员变量的类类型

Class fieldType=field.getType();

String typeName=fieldType.getName();

//得到成员变量的名字.

String fieldName=field.getName();

system.out.println("fieldType:"+typeName+","+"fieldName:"+fieldName);

}

}

public static void printConstructorInfo(Object object) {
//1.由某个类的对象,得到 该类的 类类型.
Class<?> cls=object.getClass();
//2.由该类的类类型,得到该类的所有指定的构造函数.
Constructor[] constructors=cls.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.print("构造器名称: "+constructor.getName()+"   :参数类型:");
Class[] paramTypes=constructor.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName()+";");
}
System.out.println();
}
}

}

5.方法反射来调用方法.

语法:m.invoke(obj,参数);

obj.print(参数);

//b.print(10,20);方法的反射操作是用method为进行方法调用.与b.print(10,20)效 //果一样.可变参数Object...可以写成new Object[]{10,20},也可以直接写入各个参 //数:10,20;

public class Test4 {
	/**
	 * 学习如何获得方法对象,通过方法对象调用方法执行.
	 * @param args
	 */
	public static void main(String[] args) {
		B b=new B();
		Class<?> cls=b.getClass();
		try {
			Method method=cls.getDeclaredMethod("print", new Class[]{int.class,int.class});
			Object object=method.invoke(b, 10,20);
			Method method2=cls.getDeclaredMethod("print", new Class[]{String.class,String.class});
			Object object2=method2.invoke(b, new String[]{"Manny","HaiXia"});
			/**
			 * 学习如何获得字段对象,并且更改它的值;
			 */
			Field field=cls.getDeclaredField("count");
			field.setAccessible(true);
			field.set(b, 100);
			System.out.println(field.get(b));
		} catch (NoSuchMethodException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
class B{
	private int count;
	public void printCount() {
		System.out.println(count);
	}
	public void print(int a,int b) {
		System.out.println(a+b);
	}
	
	public void print(String a,String b) {
		System.out.println(a.toUpperCase()+","+b.toLowerCase());
	}
}

6.通过反射了解集合泛型 的本质;


/**
	 * 集合泛型 的本质是编译期起检查作用的.而反射是在运行期进行的,自然就绕过了编译期的检查.
	 * @param args
	 */
	
	public static void main(String[] args) {
		ArrayList<String> list1=new ArrayList<>();
		ArrayList list2=new ArrayList();
		list2.add("hello");
		list1.add("hello");
		list2.add(20);
		Class cls1=list1.getClass();
		Class cls2=list2.getClass();
		//运行期时,list1&list2的类的类型没有区别;即不存在了泛型这个检查;
		System.out.println(cls1==cls2);
		
		try {
			Method method=cls1.getDeclaredMethod("add",Object.class);
			method.invoke(list1	, 20);
			System.out.println(list1.size());
			//取出时仍然要用反射,绕过编译期的泛型检查.
			//所以泛型不仅要检查放的数据类型是否符合泛型,还要检查拿出的数据类型是否符合泛型;
			Method method2=cls1.getDeclaredMethod("get", int.class);
			System.out.println(method2.invoke(list1, 1));
			/*for(int i=0;i<list1.size();i++){
				System.out.println(list1.get(i));
			}*/
			/*Method[] eMethods=cls1.getDeclaredMethods();
			for (Method method : eMethods) {
				System.out.print(method.getName()+";");
				Class[] paraTypes = method.getParameterTypes();
				for (Class class1 : paraTypes) {
					System.out.print(class1.getName());
					
				}
				System.out.println();
			}*/
			 
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值