注解
概念
注解可以增强java代码,同时利用反射技术可以扩充实现很多功能。被广安应用于三大框架底层。传统通过xml文本文件声明方式,现在最主流的开发都是基于注解方式,代码量少,框架可以更具注解取自动生成很多代码,从而减少代码量,程序更易读。
分类
- JDK自带注解
- 元注解
- 自定义注解
JDK注解
- @Override
- @Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期
- @SupperssWarnings("deprection")忽略警告
- @SafeCarargs jdk1.7出现,堆污染,不常用
- @FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用
元注解
- @Target注解在哪里:类上、方法上、属性上
- @Retention注解的生命周期:原文件中、class文件中、运行中
- @Inherited允许子注解继承
- @Documented生成javadoc时会包含注解,不常用
- @Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用
- @Target ElementType.class
描述注解的使用范围:
@Target(ElementType.ANNOTATION_TYPE) 应用于注释类型
@Target(ElementType.CONSTRUCTOR)应用于构造函数
@Target(ElementType.FIELD)应用于字段或属性
@Target(ElementType.LOCAL_VARIABLE)应用于局部变量
@Target(ElementType.METHOD)应用于方法级
@Target(ElementType.PACKAGE)应用于包声明
@Target(ElementType.PARAMETER)应用于方法的参数
@Target(ElementType.TYPE)应用于类的元素
- @Retention
定义了该注解被保留的时间长短,某些注解仅出现在源代码中,而被编译器丢弃;
而另一些却被编译在class文件中;编译在class文件中的注解可能会被虚拟机忽略,而另一些在class被装载时将被读取。
@Retention(RetentionPolicy.SOURCE)在源文件中有效(即源文件保留)
@Retention(RetentionPolicy.CLASS)在class文件中有效(即class保留)
@Retention(RetentionPolicy.RUNTIME)在运行时有效(即运行时保留)
自定义注解
定义注解
1.定义注解,设置注解的使用范围@Target,啥都不写,哪儿都能用
@Target({ElementType.METHOD,ElementType.PACKAGE})//作用范围
@Retention(RetentionPolicy.SOURCE)//生命周期
@Target({ElementType.TYPE})//作用于类上
@interface Test{
//定义属性
int age() default 0;//使用时,必须给age属性赋值,如age=X。除非设置好默认值
//()不是参数,也不能写参数,只是特殊语法
//4.特殊属性value
String value() defalut "";//使用时,必须给value属性赋值,如:X | value=x,除非设置号默认值
}
使用注解
@Test(value="",age=0)
class HelloTest{
String name;
}
解析注解
判断注解是否存在
public class TesstAnnotation { public static void main(String[] args) throws ClassNotFoundException { Class<?>clazz=Class.forName("javapro.spring.annotation.HelloController"); Controller c=clazz.getAnnotation(Controller.class); if (c!=null){ System.out.println(c); System.out.println(c.value()); } } }
反射
概念
Reflection(反射)是Java程序开发的特征之一,它允许运行中的Java程序对自身进行检查,或者说“自审”,也有称作“自省”。反射可以在运行时获取一个类的所有信息,可以获取到任何定义的信息(包括成员变量,成员方法,构造器等),并且可以操纵类的字段,方法,构造器等部分。
为什么需要反射
要获得未知类的底层功能调用,就需要反射技术实现
反射Class类对象
Class.forName(“类的全路径”);
类名.class
对象.getClass();
常用方法
获取包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名
成员变量定义信息
getFields()//获得所有公开的成员变量,包括继承的变量
getDeclaredFields()//获得本类定义的成员变量,包括私有,不包括 继承的变量
getField(变量名)
getDeclaredField(变量名)
构造方法定义信息
getConstructor(参数类型列表)//获得公开的构造方法
getConstructor()//获得所有公开的构造方法
getDeclaredConstructors()//获得所有构造方法,包括私有,不包括继承的方法
getDeclaredConstructor(int.class,String.class)
方法定义信息
getMethods()//获得所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获得本类定义的方法,包括私有,不包括继承的方法
getDeclared(方法名,int.class,String.class)
反射新建实例
c.newInstance();//执行无参构造
c.newInstance(6,"abc");//执行有参构造
c.getConstructor(int.class,String.class);//执行含参构造
反射调用成员变量
c.getDeclaredField(变量名);//获取变量
c.setAccessible(true);//使私有成员允许访问
f.set(实例,值);//为指定实力的变量赋值,静态变量,第一参数给null
f.get(实例);//访问指定实例的变量的值,静态变量,第一参数给null
反射调用成员方法
Method m=c.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法语序被调用
m.invoke(实例,参数数据类型);//让指定的实例来执行该方法
反射的应用
创建类
class Students{ String name="jack"; int age=20; public Students(){ System.out.println("无参构造"); } public Students(String name){ System.out.println("含参构造"+name); } public Students(int age ){ System.out.println("show()..."+age); } }
获取类对象
private static void method()throws Exception{ Class clazz=Students.class; Class<?>clazz2=Class.forName("test.Students"); Class clazz3=new Students( ).getClass(); System.out.println(clazz.getName()); System.out.println(clazz2.getName()); System.out.println(clazz3.getName()); }
获取构造方法
private static void method3(Class clazz){ Constructor[]cs=clazz.getDeclaredConstructors(); for (Constructor c:cs){ String name=clazz.getSimpleName(); System.out.println(name); Class[] cs2=c.getParameterTypes();//参数 System.out.println(Arrays.toString(cs2)); } }
Students
[]
Students
[class java.lang.String]
Students
[int]
获取成员方法
private static void method4(Class clazz){ Method[]ms=clazz.getMethods(); for (Method method:ms){ String name=method.getName(); System.out.println(name); Class<?>[]cs=method.getParameterTypes(); System.out.println(Arrays.toString(cs)); } }
wait(继承Object实现的方法)
[]
wait(继承Object实现的方法)
[long, int]
wait(继承Object实现的方法)
[long]
equals(继承Object实现的方法)
[class java.lang.Object]
toString(继承Object实现的方法)
[]
hashCode(继承Object实现的方法)
[]
getClass(继承Object实现的方法)
[]
notify(继承Object实现的方法)
[]
notifyAll(继承Object实现的方法)
[]
类 Object
是类层次结构的根类。每个类都使用 Object
作为超类。所有对象(包括数组)都实现这个类的方法。
获取成员变量
private static void method5(Class clazz){ Field [] fs=clazz.getFields();//获取public的属性 for (Field f:fs){ String name=f.getName(); String tname=f.getType().getSimpleName(); System.out.println(name); System.out.println(tname); } }
成员变量必须为公开的,否则获取不到。(默认为default)或者getFields变为getDeclaredFields
创建对象
public static void main(String[] args) throws Exception { String s=new Scanner(System.in).nextLine(); Class<?>clazz=Class.forName(s); Object o1=clazz.newInstance();//用无参构造 System.out.println(o1); Constructor<?> c=clazz.getConstructor(String.class);//用含参构造 Object o2=c.newInstance("jack"); System.out.println(o2); }
练习:熟悉API
public class Teachers { public String name="jack"; int age=20; public Teachers(){} public Teachers(String name,int age){ this.name=name; this.age=age; } public void show(){ System.out.println("Teacher.show()"); } public String toString(){ return "Teacher[name="+name+",age="+age+"]"; } }
public class TestTeachers { public static void main(String[] args) throws Exception { Class<?>clazz=Class.forName("test.Teachers"); method(clazz);//方法 method2(clazz);//属性 method3(clazz);//构造 } private static void method3(Class clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Constructor c=clazz.getConstructor();//无参构造 System.out.println(c.newInstance(null)); Constructor cc=clazz.getConstructor(String.class,int.class);//含参构造 System.out.println(cc.newInstance("我妹最漂亮",222)); } private static void method2(Class clazz) throws NoSuchFieldException { Field f=clazz.getField("name");//属性必须时public的 Field f2=clazz.getDeclaredField("age"); System.out.println(f.getType().getName()); System.out.println(f2.getType().getName()); } private static void method(Class clazz) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { Method m=clazz.getMethod("show", null); Object obj=clazz.newInstance(); m.invoke(obj);//执行方法 } }
暴力反射
指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。
创建Person类
public class Person { private String name="jack"; private int age=22; private void show(int [] a){ System.out.println("show()..."+ Arrays.toString(a)); } private void test(){ System.out.println("test()..."); } }
public class TestPerson { public static void main(String[] args) throws Exception { Class <?>clazz=Class.forName("test.Person"); // method(clazz);//隐私属性 method2(clazz);//执行方法 } private static void method2(Class<?> clazz) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { Method m=clazz.getDeclaredMethod("show", int[].class); Object obj=clazz.newInstance(); m.setAccessible(true); m.invoke(obj ,new int[]{1,2,3}); } private static void method(Class<?> clazz) throws NoSuchFieldException, IllegalAccessException, InstantiationException { Field f=clazz.getDeclaredField("name"); System.out.println(f.getType().getName()); f.setAccessible(true);//属性隐私可见 Object obj=clazz.newInstance(); f.set(obj, "我妹最漂亮");//设置值 System.out.println(f.get(obj));//获取值 //所有属性 Field[] fs=clazz.getDeclaredFields(); for (Field ff:fs){ System.out.println(ff); ff.setAccessible(true);//暴力反射 System.out.println(ff.get(obj)); } } }