4.1.11什么是反射(reflection)机制
参考网址(http://blog.youkuaiyun.com/liujiahan629629/article/details/18013523)
一、反射的概念:
主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关语义。
反射是Java的一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码链接。但是反射使用不当成本会很高。
二、反射机制的作用:
1.反编译:.class->.java
2.通过反射机制访问java对象的属性、方法、构造方法等。
看到这里,可能对反射机制还是不能理解到底是怎么一回事,没事,接下来看到具体的实现,就会理解了。
三、具体功能实现:
1.获取类。反射机制获取类有三种方法,我们可以按照如下三种方法获取Sub类型,在这里之所以和大部分博客实例不一样是因为我的java版本是1.8.0_111,按照那种实现编译器会报错:
//使用反射机制加载类
//方法1:
//如下这样用会出错, java.lang.ClassNotFoundException: Sub
//Class c = Sub.class;
//编译器要求给Class带上参数,要按照如下代码格式
Class<Sub> c = Sub.class;
//方法2:
//在传入类名参数时,要连包名一起传入
Class<?> c = Class.forName("com.LearningJava.pro20170528.Sub");
//此处虽然也有提示要给Class加参数,可是不加也可照常运行
//方法3:
Sub sub = new Sub();
//Class<? extends Sub> c = sub.getClass();
Class c = sub.getClass();
2.创建对象。获取到类以后,我们利用newInstance来创建类的对象。
//方法3:
Sub sub = new Sub();
//Class<? extends Sub> c = sub.getClass();
Class c = sub.getClass();
//向上转型
Base b = (Base) c.newInstance();
b.f();
3.获取属性。分为所有属性和特定的属性。
a.获取所有的属性:
//获取整个类
Class c = Class.forName("java.lang.Integer");
//获取所有的属性?
Field[] fs = c.getDeclaredFields();
//定义可变长的字符串,用来存储属性
StringBuffer sb = new StringBuffer();
//通过追加的方法,将每个属性拼接到此字符串中
//最外边的public定义
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
//里边的每一个属性
for(Field field:fs){
sb.append("\t");//空格
sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
sb.append(field.getName()+";\n");//属性的名字+回车
}
sb.append("}");
System.out.println(sb);
b.获取特定的属性。
public static void main(String[] args) throws Exception{
<span style="white-space: pre;"> </span>//以前的方式:
/*
User u = new User();
u.age = 12; //set
System.out.println(u.age); //get
*/
//获取类
Class c = Class.forName("User");
//获取id属性
Field idF = c.getDeclaredField("id");
//实例化这个类赋给o
Object o = c.newInstance();
//打破封装
idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
//给o对象的id属性赋值"110"
idF.set(o, "110"); //set
//get
System.out.println(idF.get(o));
}
看到这里就大概明白了前面概念里所说的,反射机制所谓的“访问、检测、和修改它本身状态或行为的能力”,这就相当于我们在代码中利用反编译获取类,然后创建该类所表示的一个新实例,也就是.class->.java。
反射机制提供的一个最主要的功能就是可以在运行时动态的创建类的对象。
完整实例如下:
TestReflection.java
package com.LearningJava.pro20170528;
class Base{
public void f(){
System.out.println("Base");
}
}
class Sub extends Base{
public void f(){
System.out.println("Sub");
}
}
public class TestReflection {
public static void main (String[] args) throws Exception{
//使用反射机制加载类
/*方法1:
这样用会出错, java.lang.ClassNotFoundException: Sub
Class c = Sub.class;
编译器要求给Class带上参数,要按照如下代码格式
Class<Sub> c = Sub.class;*/
/*方法2:
在传入类名参数时,要连包名一起传入*/
//Class<?> c = Class.forName("com.LearningJava.pro20170528.Sub");
//方法3:
Sub sub = new Sub();
//Class<? extends Sub> c = sub.getClass();
Class c = sub.getClass();
//向上转型
Base b = (Base) c.newInstance();
b.f();
}
}
运行结果:
Sub
4.1.12 package有什么作用
package的作用是吧.java文件、.class文件以及其他resource文件(如.xml文件)有条理的进行组织。
具体而言,有如下两个作用:第一、提供多层命名空间,解决命名冲突,使得处于不同package中可以存在同名的类。第二、对类按照功能进行分类,是项目结构更加清晰。
package的用法一般如下(此处以源文件所在的目录为当前目录):
1>在每个源文件的开头加上”package packagename;”,然后源文件所在目录下创建一个新目录,名称为packagename.
2>用javac指令编译每个sourcename.java源文件,将生成的sourcename.classname文件复制到packagename目录
3>用java指令运行程序:java packagename sourcename