Java 16.基础加强
反射: 框架原理就是运用反射 半成品 可以在框架的基础上进行软件的开发 简化编码
意义:将类的各个组成部分封装成其他对象
好处:
1.可以在程序运行中,操作对象
例如:idea运行 String str="abc";
str会弹出可用方法 因为将str的类对象加载进内存提取来的Method[ ]
2.可以解耦 提高程序的扩展性
需要先获取class对象
1.Class.forName
2.Name.class
3.instance.class
Field获取
Class<?> cla = Class.forName("it.test.Person");
Field[] fields = cla.getDeclaredFields();
Field name = cla.getDeclaredField("name");
// 忽略访问权限的安全检查
name.setAccessible(true);
// 只能读取public修饰的属性
cla.getField("name");
Constructor获取
Constructor<?> constructor = cla.getConstructor();
Object o = constructor.newInstance();
// 获取带参数构造方法并实例化
Constructor<?> constructor1 = cla.getConstructor(String.class, int.class);
Object instance = constructor1.newInstance("于松江", 18);
Method获取
Method[] methods = cla.getMethods();
Constructor<?> constructor1 = cla.getConstructor(String.class, int.class);
Object instance = constructor1.newInstance("于松江", 18);
Method getName = cla.getMethod("getName");
// 调用方法 要传入对象 和参数
Object o = getName.invoke(instance);
System.out.println(o);
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* @ClssName ReflectTest
* @Autor Yu
* @Description TODO
* @Date 2019/3/20 16:33
* Version 1.0
* ClassLoader 类加载器 使用类加载器将类加载到内存中
* InputStream getResourceAsStream(String name) 返回用于读取指定资源的输入流。
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
// 将本类加载到内存
InputStream inputStream = ReflectTest.class
.getClassLoader().getResourceAsStream("obj.properties");
// 文件所在包的src文件中
properties.load(inputStream);
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
Class<?> cla = Class.forName(className);
Constructor<?> constructor = cla.getConstructor(String.class, int.class);
Object instance = constructor.newInstance("于松江", 18);
Method method = cla.getMethod(methodName);
Object o = method.invoke(instance);
System.out.println(o);
}
}
obj.properties
className=it.test.Person
methodName=toString
注解:面向计算机的描述文字
注释:面向程序员的描述程序的文字
概念描述:
JDK 1.5之后的新特性
说明程序的
使用注解@注解名称
作用分析:
1 编写文档 通过代码里标识的注解生成文件 cmd javadoc
2 代码分析:通过代码里的标注对代码进行分析【使用反射】
3 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查
@override
:检查被该注解标注的方法是否继承自父类
@Deprecated
:将程序标记成已过时 不建议使用
@SuppressWarnings
:压制警告 一般括号内填“all”
注解的基本格式:
public @interface Override {
}
自定义格式:public @interface 注解名称{}
本质:javap 反编译:
public interface it.annotation.MyAnno extends java.lang.annotation.Annotation {
}
属性:接口中的抽象方法
要求:1 属性的返回值有以下取值 不可以是void
基本数据类型
String
枚举
注解
以上类型的数组
定义了属性:在使用时需要给属性赋值
如果属性名是value 则可以在赋值时省略 如果是多个值 则必须带有属性名
元注解:定义注解上方的还有注解
用于注解的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Target
描述注解作用的位置:TYPE METHOD FIELD
@Retention
描述注解被使用的阶段:SOURCR CLASS RUNTIME
source 字节码文件时 注解不会保存在字节码文件上
class 类上 加载到内存中被使用 会被保存在字节码文件上
runtime 在字节码文件运行时执行 会被保存在字节码文件上 会被jvm获取到
一般定义runtime
@Documented
描述注解可以被抽取到doc文档中 会被保存到文档中
@Inherited
描述注解被子类继承
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno1 {
String className();
String methodName();
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* @ClssName AnnoationTest
* @Autor Yu
* @Description TODO
* @Date 2019/3/21 13:35
* Version 1.0
*/
@MyAnno1(className = "it.test.Person",methodName ="toString")
public class AnnoationTest {
public static void main(String[] args) throws Exception {
// 创建对应类的本类字节码文件对象
Class<AnnoationTest> personClass =AnnoationTest.class;
// 获取指定类上的注解对象
MyAnno1 annotation = personClass.getAnnotation(MyAnno1.class);
// 获取对应属性的值
String className = annotation.className();
String methodName = annotation.methodName();
//获取对应名字的字节码文件
Class<?> cla = Class.forName(className);
Constructor<?> constructor = cla.getConstructor(String.class, int.class);
Object newInstance = constructor.newInstance("于松江", 18);
Method method = cla.getMethod(methodName);
Object o = method.invoke(newInstance);
System.out.println(o);
}
}
用来做标记的注解 检测程序 并输出bug.txt文件
被测试文件:
/**
* @ClssName MathDemo
* @Autor Yu
* @Description TODO
* @Date 2019/3/21 14:05
* Version 1.0
*/
public class MathDemo {
@Check
public void add(){
System.out.println("1+2"+"="+(1+2));
}
@Check
public void subtraction(){
System.out.println("1-2"+"="+(1-2));
}
@Check
public void multiplication(){
System.out.println("1*2"+"="+(1*2));
}
@Check
public void division(){
System.out.println("1/0"+"="+(1/0));
}
}
注解文件:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}
测试文件:
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
/**
* @ClssName CheckMath
* @Autor Yu
* @Description TODO
* @Date 2019/3/21 14:17
* Version 1.0
*/
public class CheckMath {
public static void main(String[] args) throws Exception {
//创建输出流
PrintWriter printWriter = new PrintWriter(new FileOutputStream("bug.txt"));
// 创建对象
MathDemo mathDemo = new MathDemo();
// 获取该对象的字节码文件对象
Class<? extends MathDemo> mathDemoClass = mathDemo.getClass();
// 创建实例
MathDemo mathDemo1 = mathDemoClass.newInstance();
// 获取方法
Method[] methods = mathDemoClass.getMethods();
for (Method method : methods) {
// 是否包含Check注解
if (method.isAnnotationPresent(Check.class)) {
try {
method.invoke(mathDemo1);
} catch (Exception e) {
printWriter.println("异常方法名:"+method.getName());
printWriter.println("异常名:"+e.getCause().getClass().getSimpleName());
printWriter.println("异常原因:"+e.getMessage());
printWriter.println("------------------------------");
printWriter.close();
}
}
}
}
}