您的位置:首页 > 编程语言 > Java开发

Java反射原理

2016-02-23 14:05 369 查看

一、Class类的应用

1.类类型的对象该如何表示

public class Foo{
public void say(){
System.out.println("hello world");
}
}

public class ClassDemo1{
public static void main(String[] args){
//Foo的实例对象
Foo foo1 = new Foo();
//Foo这个类本身也是一个实例对象
//任何一个类都是Class类的实例对象
//这个实例对象有三种表示方式

//第一种方式,实际在告诉我们任何一个类都有一个隐含的静态成员变量
Class clazz1 = Foo.class;

//第二种方式,已知该类的对象,通过getClass方法得到
Class clazz2 = foo1.getClass();

//第三种表达方式,通过Class类的静态方法forName()加全限定名
try{
Class clazz3 = Class.forName("com.destiny.reflect.Foo");
}catch(ClassNotFoundException e){
e.printStackTrace();
}

//不管clazz1还是clazz2都代表了Foo类的类类型,一个类只可能是一个Class类的一个实例对象
System.out.println(clazz1 == clazz2);
//官方文档:clazz表示了foo类的类类型
//万事万物皆对象,是Class类的对象,这个对象我们称之为该类的类类型

//我们完全可以通过类的类类型创建该类的实例对象,即通过clazz创建Foo的实例对象
Foo foo1 = clazz1.newInstance();
foo1.say();

}
}


编译:编译时期加载类是静态加载类

运行:运行时期加载类是动态加载类

public class Word{
public static void start(){
System.out.println("word......start");
}
}

public class Office{
public static void main(){
//由于我们只有Word类而没有Excel类,因此本类在编译时无法通过
//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{
<span style="white-space:pre">	</span>public static void main(String[] args){
<span style="white-space:pre">	</span>try{
//动态加载类,在运行时刻加载
Class clazz = Class.forName(args[0]);
//通过类类型创建对象
//使用Word与Excel的抽象接口OfficeAble
OfficeAble oa = (OfficeAble)clazz.newInstance();
oa.start();
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
}


2.基本数据类型

类中存在的关键字都存在类类型

public class ClassDemo2{
public static void main(String[] args){
//int的类类型
Class clazz1 = int.class;
//String的类类型,String类字节码
Class clazz2 = String.class;

Class clazz3 = double.class;
Class clazz4 = void.class;

System.out.println(clazz2.getName());		//java.lang.String
System.out.println(clazz2.getSimpleName());	//String
}
}

public class ClassUtil{
//打印类的信息,包括类的成员变量、成员函数
public static void printClassMessage(Object obj){
//要获取类的信息,首先要获取类的类类型
//一直参数obj,是一个对象
Class clazz = obj.getClass();
System.out.println("类的名称是:"+clazz.getName());
//Method是方法的对象
//一个成员方法就是一个method对象
//getMethods()方法获取的是所有public方法,包括从父类继承而来的
//getDeclaredMethod()获取的是所有该类自己生命的方法,无视访问权限
Method[] methods = clazz.getMethods();
for(int i = 0; i < methods.length; ++i){
//得到方法的返回值类型的类类型
Class returnType = methods[i].getReturnType();
//通过返回值的类类型打印返回值类型
System.out.println(returnType.getName()+" ");
//得到方法名称
System.out.println(methods[i].getName()+"(");
//获取参数类型===>得到的是参数裂变的类型的类类型
Class[] paramTypes = methods[i].getParamTypes();

for(Class clazz : paramTypes){
System.out.println(class.getName()+",");
}

System.out.println(")");
}
}
}


3.成员变量的反射

成员变量也是对象

java.lang.reflect.Field
Field类封装了关于成员变量的操作

Field[] fields = clazz.getFields();
//Field[] fields = clazz.getDeclaredFields();
for(Field field : fields){
//得到成员变量类型的类类型
Class fieldType = field.getType();
String typeName = fieldType.getName();
//得到成员变量的标识符
String fieldName = field.getName();
}


二、方法的反射操作

1.如何获取某个方法

一个方法的名称和其参数列表可以唯一决定一个方法

2.方法反射的操作

method.invoke(对象, 参数列表);

3.案例

public class A{
public void print(int a, int b){
System.out.println(a+b);
}

public String print(String a, String b){
System.out.println(a.toUpperCase() +","+ b.toLowerCase());
}
}

public class MethodDemo1{
public static void main(String[] args){
//获取print(int, int)方法
//1.获取类的类类型
A a = new A();
Class clazz = a.getClass();
//2.获取方法,名称和参数列表来决定
//getMethod()获取的是public
Method method = clazz.getMethod("print", new Class[]{int.class, int.class});
Method method = clazz.getMethod("print", int.class, int.class);

//方法的反射操作
//用方法对象来进行调用
//如果方法没有返回值,那么obj的值为null
//如果方法有返回值,那么obj就是该方法的返回值,需要强制类型转换
Object obj = method.invoke(a, new Object[]{10, 20});
Object obj = method.invoke(a, 10, 20);
}
}


三、通过Class, Method了解泛型的本质

反射的操作都发生在运行期

public class MethodDemo4{
List list1 = new ArrayList();
List<String> list2 = new ArrayList<String>();
list2.add("hello");
//list2.add(10);
Class clazz1 = list1.getClass();
Class clazz2 = list2.getClass();

System.out.println(clazz1 == clazz2);
//输出结果为true,说明编译之后的结果是去泛型化
//即编译后,list2不再具有泛型
//java中集合的泛型是防止错误输入,只在编译阶段有效,绕过编译泛型就不再发生作用
//我们可以通过方法的反射绕过编译
Method method = clazz2.getMethod("add", Object.class);
//绕过编译执行add方法
method.invoke(list2, 10);
//添加成功,成功绕过泛型的限制
System.out.println(list2.size);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: