注解与反射机制(Annocation、Reflection)
注解(Java.Annotation)
注释(comment)
注解作用:
1.可以被其他程序(比如:编译器等)读取
2.不是程序本身,可以对程序作出解释(和注释差不多)
注解的格式:
@注解名,还可以添加一些内置参数值
比如@SuppressWarnings(value = "unchecked")
注解的使用地点:
可以在package,class,method,field上使用,相当于给他们添加了一些辅助信息,我们可以通过反射机制编程实现对这些源数据的访问
内置注解
注解的常用几种:
@Override 方法的重写
@Deprecated 不推荐使用,或存在危险,有更好的方法替代,但是可以使用,使用的方法打有横杠
@SuppressWarnings()镇压警告,编写代码时,黄色警告被镇压,后面有参数,可以传递一个或多个参数
@SuppressWarnings("all")
@SuppressWarnings("unchecked")
@SuppressWarnings("unchecked","desprecatoin"),
元注解
作用:用来注解其他注解
//Target,用来注解自定义注解的使用范围,
//参数类型 ElementType[] value()
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention,表示注解在什么时候有效
//SOURCE<CLASS<RUNTIME
@Retention(RetentionPolicy.SOURCE)
//Documented 该注解是否出现在javadoc里面
@Documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
}
自定义注解
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自定义注解
public class TestAnnotation02 {
//注解可以显示赋值,如果没有默认值,必须赋值
@MyAnnotation02(name = "小明")
public void test01(){
}
@MyAnnotation03("小明")
public void test03(){
}
}
//元注解,对自定义注解的注解
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
//自定义注解的格式 public @interface 自定义注解名
@interface MyAnnotation02{
// 注解的参数 参数类型 参数名() ;
String name();
//设置 默认值格式为 参数类型 参数名() default 默认值;
int age() default 21;
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation03{
//如果注释中只有一个参数,将参数名命名为value,这样在赋值时候,可以省略赋值名
String value();
}
添加的这些辅助信息,可以通过反射机制来读取这些元数据信息
反射机制(Reflection)
静态语言与动态语言
动态语言:在运行的时候可以改变其结构的语言:比如javascript、Object-C、C#、PHP、phython
静态语言:在运行时结构不发生改变:比如Java,C,C++
Java不是动态语言,但是可以通过反射机制来获得类似动态语言,可以成为“准动态语言”。
Java反射机制提供的功能
1.运行时判断任意一个对象所属的类
2.运行时构造任意一个类对象
3..运行时判断任意一个类所具有的成员变量和方法
4.在运行时获取泛型信息
5.在运行时调用任意一个对象的成员变量和方法
6.在运行时处理注解
7.生成动态代理
............
Java反射的优缺点
优点:可以实现动态创建对象和编译,体现出很大的灵活性
缺点:对性能有影响。使用反射基本是一种解释操作,我们可以告诉jvm,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。
package annotation;
public class TestReflect01 extends Object{
public static void main(String[] args) throws ClassNotFoundException {
//通过反射来获取类的Class对象
Class c1 = Class.forName("annotation.User");
Class c2 = Class.forName("annotation.User");
Class c3 = Class.forName("annotation.User");
//一个类在内存中只有一个Class对象
//一个类被加载后,类的整个结构都会被封装在Class对象中
System.out.println(c1);//三者输出相同
System.out.println(c2);
System.out.println(c3);
}
}
class User{
private String name;
private int age;
private int id;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
'}';
}
}
获取class对象的几种方法:
package annotation;
//获取class对象的几种方法
public class TestReflect02 {
public static void main(String[] args) throws ClassNotFoundException {
Person student = new Student();
//通过在Object类中继承的getClass()方法,来返回一个class对象
Class c1 = student.getClass();
System.out.println(c1);//c1,c2,c3打印结果相同
//通过Class类中静态方法forName("类的路径(className)"),来返回一个class对象,这个方法必须知道其类的地址
Class c2 = Class.forName("annotation.Student");
System.out.println(c2);
//通过类名.class,来返回一个class对象
Class c3 = Student.class;
System.out.println(c3);
//基本内置类型的包装类都有一个TYPE属性,可以通过这个静态属性来返回一个class对象
Class<Integer> c4 = Integer.TYPE;
System.out.println(c4);//int
//获取父类class对象
Class superclass = c1.getSuperclass();
System.out.println(superclass);
}
}
class Person {
public String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
public Student() {
this.name = "学生";
}
}
class Teacher extends Person{
public Teacher() {
this.name = "老师";
}
}
哪些类型可以有Class对象?
只要元素的类型和纬度是一样的,就是同一个Class.
package annotation;
import java.lang.annotation.ElementType;
public class TestClass01 {
public static void main(String[] args) {
Class c1 = Object.class;//类的class对象
Class c2 = Comparable.class;//接口的class对象
Class c3 = String[].class;//一维数组的class对象
Class c4 = int[][].class;//二维数组的class对象
Class c5 = Override.class;//注解的class对象
Class c6 = ElementType.class;//枚举的class对象
Class c7 = Integer.class;//基本数据类型的class对象
Class c8 = void.class;//void类型的class对象
Class c9 = Class.class;//class类型的class对象
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
//只要元素的类型和纬度是一样的,就是同一个Class.
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass());//两者相同
System.out.println(b.getClass());
}
}
运行结果:
类的加载过程
类初始化
package annotation;
//测试类初始化时,主动引用和被动引用
public class TestClass02 {
static {
System.out.println("main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//1.主动引用,先加载父类,再加载子类
// Son son = new Son();
//2.反射也会产生主动引用
// Class.forName("annotation.Son");
//3.不会产生类的引用
// System.out.println(Son.b);//调用父类的静态常量,son本身不会加载,father被加载了
// Son[] sons = new Son[10];//子类和父类都不会加载
System.out.println(Son.M);//常量池中常量,并不会引起子类和父类的加载
}
}
class Father{
static int b = 2;
static {
System.out.println("父类被加载了");
}
}
class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
}
static int m = 10;
static final int M = 10;//常量池
}
类加载器
用class类中的方法来获取该类的类名、属性、方法、构造器
package annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//测试用class类中的方法来获取该类的类名、属性、方法、构造器
public class TestClass04 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("annotation.A");
//获取类名
System.out.println(c1.getName());//包名.类名
System.out.println(c1.getSimpleName());//简单的类名
System.out.println("====================");
//获取属性
Field[] fields = c1.getFields();//获取公共属性
for (Field field : fields) {
System.out.println(field);
}
fields = c1.getDeclaredFields();//获取全部属性
for (Field field : fields) {
System.out.println("----"+field);
}
System.out.println(c1.getField("name"));//获取特定名称的公共属性
System.out.println(c1.getDeclaredField("id"));//获取特定名称的属性,包括私有属性
System.out.println("====================");
//获取类的方法
Method[] methods = c1.getMethods();//获取该类的所有公共方法,包括继承来的,不包括私有方法
for (Method method : methods) {
System.out.println(method);
}
methods = c1.getDeclaredMethods();//获取该类本身自有的方法,包括私有方法
for (Method method : methods) {
System.out.println("-----"+method);
}
System.out.println(c1.getMethod("getName",null));//返回指定名称的公有方法,为什么会名称后有参数,方法的重载
System.out.println(c1.getDeclaredMethod("test",null));//返回指定名称的所有方法,包括私有方法
System.out.println("====================");
//获取类的构造器
Constructor[] constructors = c1.getConstructors();//获取公共构造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
constructors = c1.getDeclaredConstructors();//获取所有构造器,包括私有
for (Constructor constructor : constructors) {
System.out.println("----"+constructor);
}
System.out.println(c1.getConstructor(String.class, int.class, int.class));//获取指定参数类型的公有构造器
System.out.println("---"+c1.getDeclaredConstructor(String.class, int.class, int.class));//获取指定参数类型的构造器,包括私有构造器
}
}
class A{
public String name;
private int id;
public int age;
public A() {
}
public A(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void test(){}
}
动态创建对象执行方法
package annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//通过反射,来动态的创建对象
public class TestClass05 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获取class对象
Class c1 = Class.forName("annotation.B");
//构造一个对象
/* B b = (B)c1.newInstance();//本质是调用类的无参构造器
System.out.println(b);*/
//通过调用构造器,来创建对象
/*Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);//本质是调用了有参的构造器
B b1 = (B)constructor.newInstance("小明", 0001, 12);
System.out.println(b1);*/
//通过反射来操作方法
B b2 = (B)c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(b2,"小明");//invoke:激活(对象,方法参数列表的值)
System.out.println(b2);
//通过反射操作属性
//不能直接操作私有属性,需要取消安全检测,setAccessible(true)
B b3 = (B)c1.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);//因为属性为private,需要取消安全检查,默认为false,为true时,取消安全检查
name.set(b3,"小明");
System.out.println(b3);
}
}
class B{
private String name;
private int id;
private int age;
public B() {
}
public B(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "B{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
性能比较
package annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//分析性能问题
public class TestClass06 {
//普通方法调用
public static void test01(){
C c = new C();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
c.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法执行10亿次需要"+(endTime-startTime)+"ms");
}
//反射方式调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
C c = new C();
long startTime = System.currentTimeMillis();
Class c1 = c.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
for (int i = 0; i < 1000000000; i++) {
getName.invoke(c,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式调用执行10亿次需要"+(endTime-startTime)+"ms");
}
//反射方式调用 关闭检测
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
C c = new C();
long startTime = System.currentTimeMillis();
Class c1 = c.getClass();
Method getName = c1.getDeclaredMethod("getName", null);
getName.setAccessible(true);
for (int i = 0; i < 1000000000; i++) {
getName.invoke(c,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式调用 关闭检测执行10亿次需要"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
}
class C{
private String name;
public C() {
}
public C(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
运行结果:
所以,能关闭安全检测,就关闭安全检测,这样能加快程序的运行速度
反射操作泛型
空缺,需补齐
反射操作注解
ORM:Object relationship Mapping 对象关系映射(类生成的对象与数据库中的表对应)
package annotation;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
//练习反射操作注解
public class TestClass07 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
//通过反射获得注解,同时获得注解的值
Class c = Class.forName("annotation.Worker");
AnnocationClass annocationClass = (AnnocationClass)c.getAnnotation(AnnocationClass.class);
System.out.println(annocationClass.value());
//获得类中指定的注解(获取特定注解,必须要获取特定的该元素)
Field name = c.getDeclaredField("name");
AnnocationField annotation = (AnnocationField)name.getAnnotation(AnnocationField.class);
System.out.print(annotation.columnName()+" ");
System.out.print(annotation.type()+" ");
System.out.print(annotation.length()+" ");
}
}
@AnnocationClass("db_table")
class Worker{
@AnnocationField(columnName = "varchar",type = "String",length = 3)
private String name;
@AnnocationField(columnName = "id",type = "int",length = 10)
private int id;
@AnnocationField(columnName = "age",type = "int",length = 3)
private int age;
public Worker() {
}
public Worker(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Worker{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface AnnocationClass{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface AnnocationField{
String columnName();
String type();
int length();
}