什么是反射
反射调用流程:
对应类、构造器,对象、成员变量、方法等,都是
//获取类
User user = clazz.newInstance();
//获取方法
Method method = clazz.getDeclaredMethod("setUserName",String.class);
//调用
method.invode(user,"shunXu");
通过反射,能够对私有域进行操作。
Java采用泛型擦除机制引入泛型。 Java中的泛型仅仅是给编译器javac使用,确保数据的安全性和免去类型强转的麻烦。但是,一旦编译完成,所有和泛型相关的类型全部被擦除。
为了通过反射操作泛型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType来代表不能被归一到Class中的类型但是又和原始类型齐名的类型。
最常见的用法还是在框架中
可以通过反射获得相关注解信息。
//获得类的所有注解
Annotation[] annotations = clazz.getAnnotations();
for(Annotation a:annotations){
System.out.println(a);
}
//获得指定类注解
User user = (User) class.getAnnotation(User.calss);
System.out.println(user.value());
//获得指定属性注解
Field f = clazz.getDeclaredField("userName");
User user = f.getAnnotation(User.class);
System.out.println(User.columnName()+"---"+User.type()+"---"+User.length());
应用场景
动态编译的常用做法:
//编译并执行,但实际上还是静态
Runtime run = Runtime.getRuntime();
Process process = run.exec("javac -cp d:/myJava/ HelloWorld.java");
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null,null,sourceFile);
System.out.println(result==0?"编译成功":"编译失败");
compiler.run中的参数说明
通过Runtime.getRuntime();
//编译并执行,但实际上还是静态
Runtime run = Runtime.getRuntime();
Process process = run.exec("javac -cp d:/myJava/ HelloWorld.java");
通过反射运行编译好的类
通过脚本引擎执行其他语言的代码,以js为例。
//获得脚本引擎
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine engine = sem.getEngineByName("javascript");
//定义变量,存储到引擎上下文中
engine.put("password","123123");
//定义脚本代码
String jscode = "var user = {name:'shunXu',age:18};";
jscode += "println(user.name);";
//执行脚本
engine.eval(jscode);
System.out.println(engine.get("password"));
运行时操作字节码可以实现如下功能
优势
常见字节码操作类库
作为数据的存储格式或用于存储软件的参数,程序解析此配置文件,就可以达到不修改代码就能更改程序的目的。
解析方法分为四种
前两种为基础方法,后两者为Java专属方法。
顺序访问模式,当SAX对XML进行解析时,会触发一系列事件,并激活相应时间的处理函数(事件驱动)
相关方法:
实例
<PIANT>
<ZONE></ZONE>
</PIANT>
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class PlantXml{
public static void main(String[] args)throws Exception {
//1.获取解析工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//2.从解析工厂获取解析器
SAXParser parse = factory.newSAXParser();
//3.编写处理器
//4.加载处理器
PHandler handler = new PHandler();
//5.解析
parse.parse(Thread.currentThread().getContextClassLoader()
.getResourceAsStream("xmlStudy/plant_catalog.xml")
,handler);
}
}
//3.编写处理器
class PHandler extends DefaultHandler{
private List<Plant> plants; //所有plants
private Plant plant; //当前解析的单个plant,在标签开始时new,在标签结束时加入容器
private String tag; //由于characters不能得到内部属性,因此在这里保存
@Override
public void startDocument() throws SAXException {
//解析仅仅开始一次,因此也可当作类构造器进行初始化
plants = new ArrayList<Plant>();
System.out.println("----------解析开始----------");
}
@Override
public void endDocument() throws SAXException {
System.out.println("----------解析结束----------");
System.out.println(plant.getZONE());
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
System.out.println("----------"+qName+"标签解析开始----------");
System.out.println();
if (null!=qName) {
if (qName.equals("PLANT")) {
plant = new Plant();
}
tag = qName;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("----------"+qName+"标签解析结束----------");
System.out.println();
if (qName.equals("PLANT")) {
plants.add(plant);
}
tag=null;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String contents = new String(ch,start,length).trim();
//此处使用else-if存放属性
if (contents.length()>0 && tag!=null) {
if (tag.equals("ZONE")) {
plant.setZONE(Integer.valueOf(contents)); //注意类型转换,string->int
} //由于标签缩进问题,由于空的部分没有tag名字,因此tag还是上一次的ZONE,但是拿到的contests实际为空,因此最终ZONE为空
} //因此,在每一次的tag完成使命之后(endElement),需要赋值为空,在使命开始时(characters),要进行非空判断
}
}
xml解析在web框架开发中非常常见,不过解析过程都是框架自动完成,程序员只需要配置解析文件。
特征:仅使用具体类,而不使用接口、大量使用Collections类
若跨平台,则考虑SAX(JDOM基本没啥用,DOM虽然性能也不好,但是在其他平台上(如js中)会使用) 若不跨平台,果断DOM4J