注解与反射

注解

注解(Annotation)

作用:
1.不是程序本身 , 可以对程序作出解释.(这一点和注释(comment)没什么区别)
2.可以被其他程序(比如:编译器等)读取
格式:
注解是以"@注释名"在代码中存在的 , 还可以添加一些参数值 , 例如:@SuppressWarnings(value=“unchecked”).
在哪里使用?
可以附加在package , class , method , field 等上面 , 相当于给他们添加了额外的辅助信息, 我们可以通过反射机制编程实现对这些元数据的访问

内置注解

@Override : 定义在 java.lang.Override 中 , 此注释只适用于修辞方法 , 表示一个方法声明打算 重写超类中的另一个方法声明.

@Deprecated : 定义在java.lang.Deprecated中 , 此注释可以用于修辞方法 , 属性 , 类 , 表示不 鼓励程序员使用这样的元素 , 通常是因为它很危险或者存在更好的选择

@SuppressWarnings : 定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息. p 与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的, 我们选择性的使用就好了 .
1) @SuppressWarnings(“all”)
2) @SuppressWarnings(“unchecked”)
3) @SuppressWarnings(value={“unchecked”,“deprecation”})

元注解

元注解的作用就是负责注解其他注解 , Java定义了4个标准的meta-annotation类型,他们被用来 提供对其他annotation类型作说明 .
这些类型和它们所支持的类在java.lang.annotation包中可以找到 .( @Target , @Retention , @Documented , @Inherited )
@Target : 用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Retention : 表示需要在什么级别保存该注释信息 , 用于描述注解的生命周期 Ø (SOURCE < CLASS < RUNTIME)
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解

自定义注解

使用@interface自定义注解时 , 自动继承了java.lang.annotation.Annotation接口
解析:
@ interface用来声明一个注解 , 格式 : public @ interface 注解名 { 定义内容 }

其中的每一个方法实际上是声明了一个配置参数.

方法的名称就是参数的名称.

返回值类型就是参数的类型 ( 返回值只能是基本类型,Class , String , enum ).

可以通过default来声明参数的默认值

如果只有一个参数成员 , 一般参数名为value

注解元素必须要有值 , 我们定义注解元素时 , 经常使用空字符串,0作为默认值


public @interface Action {  // 无属性值
}
 
public @interface Action { // 有属性值 
   String action() default "A";
   int value() default  0;
}

声明2个注解

@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
   String action() default "构造函数";
}
 
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation {
   String describe() default "描述";
   Class type() default void.class;
}

注解@Action 使用于构造函数,有一个描述属性,@FieldAnnotation适用于注解属性常量,包含一个String类型的描述和修饰的类型

使用:


public class ConstructorExample {
 
   @FieldAnnotation(describe = "名字" ,type = String.class)
   public String name;
   @FieldAnnotation(describe = "分数",type = int.class)
   protected int core;
 
   @Action()
   public ConstructorExample(String name, int core) throws NumberFormatException {
      this.core = core;
      this.name = name;
   }
}

反射( Reflection)

Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借 助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
Class c = Class.forName(“java.lang.String”)
注解与反射_第1张图片

反射的优缺点

优点:
可以实现动态创建对象和编译,体现出很大的灵活性
缺点:
对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望 做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作

反射相关的API

java.lang.Class:代表一个类
java.lang.reflect.Method : 代表类的方法
java.lang.reflect.Field : 代表类的成员变量
java.lang.reflect.Constructor : 代表类的构造器

Class类

在Object类中定义了以下的方法,此方法将被所有子类继承

public final Class getClass()
此方法返回值的类型是一个Class 类,此类是Java反射的源头,实际上所 谓反射从程序的运行结果来看也很好理 解,即:可以通过对象反射求出类的名称。
常用方法:

方法名 功能
static ClassforName(String name) 返回指定类名name的Class对象
Object newInstance() 调用缺省构造函数,返回Class对象的一个实例
getName() 返回此Class对象所表示的实体(类,接口,数组类 或void)的名称
Class getSuperClass() 返回当前Class对象的父类的Class对象
Class[] getinterfaces() 获取当前Class对象的接口
ClassLoader getClassLoader() 返回该类的类加载器
Constructor[] getConstructors() 返回一个包含某些Constructor对象的数组
Method getMothed(String name,Class… T) 返回一个Method对象,此对象的形参类型为 paramType
Field[] getDeclaredFields() 返回Field对象的一个数组

获取Class对象的三种方法:

public class Fanshe {
    public static void main(String[] args) {
        //第一种方式获取Class对象  
        Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
        Class stuClass = stu1.getClass();//获取Class对象
        System.out.println(stuClass.getName());

        //第二种方式获取Class对象
        Class stuClass2 = Student.class;
        System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个

        //第三种方式获取Class对象
        try {
            Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
            System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

哪些类型可以有Class对象?
class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
interface:接口 []:数组 enum:枚举 annotation:注解@interface
primitive type:基本数据类型 void

反射的使用

通过泛型获取构造方法


/*
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 * 
 * 1.获取构造方法:
 * 		1).批量的方法:
 * 			public Constructor[] getConstructors():所有"公有的"构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
     
 * 		2).获取单个的方法,并调用:
 * 			public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
 * 			public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
 * 		
 * 			调用构造方法:
 * 			Constructor-->newInstance(Object... initargs)
 */
public class Constructors {
 
	public static void main(String[] args) throws Exception {
		//1.加载Class对象
		Class clazz = Class.forName("Testoo.Student");
		
		
		//2.获取所有公有构造方法
		System.out.println("**********************所有公有构造方法*********************************");
		Constructor[] conArray = clazz.getConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		
		System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
		conArray = clazz.getDeclaredConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		System.out.println("*****************获取公有、无参的构造方法*******************************");
		Constructor con = clazz.getConstructor(null);
		//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
		//2>、返回的是描述这个无参构造函数的类对象。
	
		System.out.println("con = " + con);
		//调用构造方法
		Object obj = con.newInstance();
	//	System.out.println("obj = " + obj);
	//	Student stu = (Student)obj;
		
		System.out.println("******************获取私有构造方法,并调用*******************************");
		con = clazz.getDeclaredConstructor(char.class);
		System.out.println(con);
		//调用构造方法
		con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
		obj = con.newInstance('男');
	}
	
}
class Student {
	
	//---------------构造方法-------------------
	//(默认的构造方法)
	Student(String str){
		System.out.println("(默认)的构造方法 s = " + str);
	}
	
	//无参构造方法
	public Student(){
		System.out.println("调用了公有、无参构造方法执行了。。。");
	}
	
	//有一个参数的构造方法
	public Student(char name){
		System.out.println("姓名:" + name);
	}
	
	//有多个参数的构造方法
	public Student(String name ,int age){
		System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
	}
	
	//受保护的构造方法
	protected Student(boolean n){
		System.out.println("受保护的构造方法 n = " + n);
	}
	
	//私有构造方法
	private Student(int age){
		System.out.println("私有的构造方法   年龄:"+ age);
	}
 
}

结果:
注解与反射_第2张图片
获取成员变量并且调用


public class Fields {
 
		public static void main(String[] args) throws Exception {
			//1.获取Class对象
			Class stuClass = Class.forName("Testoo.Student2");
			//2.获取字段
			System.out.println("************获取所有公有的字段********************");
			Field[] fieldArray = stuClass.getFields();
			for(Field f : fieldArray){
				System.out.println(f);
			}
			System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
			fieldArray = stuClass.getDeclaredFields();
			for(Field f : fieldArray){
				System.out.println(f);
			}
			System.out.println("*************获取公有字段**并调用***********************************");
			Field f = stuClass.getField("name");
			System.out.println(f);
			//获取一个对象
			Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student2 stu = new Student2();
			//为字段设置值
			f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
			//验证
			Student2 stu = (Student)obj;
			System.out.println("验证姓名:" + stu.name);
			
			
			System.out.println("**************获取私有字段****并调用********************************");
			f = stuClass.getDeclaredField("phoneNum");
			System.out.println(f);
			f.setAccessible(true);//暴力反射,解除私有限定
			f.set(obj, "18888889999");
			System.out.println("验证电话:" + stu);
			
		}
	}
class Student {
	public Student2(){
		
	}
	//**********字段*************//
	public String name;
	protected int age;
	char sex;
	private String phoneNum;
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", sex=" + sex
				+ ", phoneNum=" + phoneNum + "]";
	}
	
	
}

结果:
注解与反射_第3张图片
获取成员方法并调用

public class MethodClass {
 
	public static void main(String[] args) throws Exception {
		//1.获取Class对象
		Class stuClass = Class.forName("Testoo.Student3");
		//2.获取所有公有方法
		System.out.println("***************获取所有的”公有“方法*******************");
		stuClass.getMethods();
		Method[] methodArray = stuClass.getMethods();
		for(Method m : methodArray){
			System.out.println(m);
		}
		System.out.println("***************获取所有的方法,包括私有的*******************");
		methodArray = stuClass.getDeclaredMethods();
		for(Method m : methodArray){
			System.out.println(m);
		}
		System.out.println("***************获取公有的show1()方法*******************");
		Method m = stuClass.getMethod("show1", String.class);
		System.out.println(m);
		//实例化一个Student对象
		Object obj = stuClass.getConstructor().newInstance();
		m.invoke(obj, "刘德华");
		
		System.out.println("***************获取私有的show4()方法******************");
		m = stuClass.getDeclaredMethod("show4", int.class);
		System.out.println(m);
		m.setAccessible(true);//解除私有限定
		Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
		System.out.println("返回值:" + result);
		
		
	}
}
class Student3 {
	//**************成员方法***************//
	public void show1(String s){
		System.out.println("调用了:公有的,String参数的show1(): s = " + s);
	}
	protected void show2(){
		System.out.println("调用了:受保护的,无参的show2()");
	}
	void show3(){
		System.out.println("调用了:默认的,无参的show3()");
	}
	private String show4(int age){
		System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
		return "abcd";
	}
}


注解与反射_第4张图片

ORM(Object relationship Mapping --> 对象关系映射)

注解与反射_第5张图片
类和表结构对应
属性和字段对应
对象和记录对应

利用注解和反射完成

public class TestORM {
    public static void main(String[] args) throws Exception {
        //通过反射获取注解信息
        Class c1 = Class.forName("Test00.Student4");

        Annotation[] annotations = c1.getAnnotations();//获得这个类的所有注解信息
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        //获得注解的值
        //通过注解的 value方法 获得注解的值
        Annotation annotation = c1.getAnnotation(TableKuang.class);
        TableKuang annotation1 = (TableKuang) annotation;
        System.out.println(annotation1.value());

        Field field = c1.getDeclaredField("id");
        System.out.println(field);
        //获得字段的注解
        FieldKuang annotation2 = field.getAnnotation(FieldKuang.class);
        //获得注解的参数信息
        System.out.println(annotation2.columnName());
        System.out.println(annotation2.length());
        System.out.println(annotation2.type());

    }
}

//学生的实体类
//db : database -->数据库
@TableKuang("db_student")
class Student2{

    @FieldKuang(columnName = "id",type = "int",length = 10)
    private int id;
    @FieldKuang(columnName = "db_age",type = "int",length = 3)
    private int age;
    @FieldKuang(columnName = "name",type = "varchar",length = 20)
    private String name;

    public Student4() {
    }
    public Student4(int id, int age, String name) {
        this.id = id;
        this.age = age;
        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;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}


//表名-->类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableKuang{
    String value();
}

//字段类的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldKuang{

    //参数类型  参数名
    String columnName();//列名
    String type();//类型
    int length();//长度

}

你可能感兴趣的:(JAVA)