反射
Java反射机制:是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制,很多优秀的开源框架都是通过反射完成的。
获取Class对象:
- 第一种通过类名.Class,例如:Class cl=User.Class;
- 第二种通过对象名.getClass,例如 User u=new User(); Class cl=u.getClass();
- 第三种通过Class.forName()方式,例如Class cl=Class.forName(com.shsxt.Demo.User);
反射中获取修饰符的方法-------getModifiers()
//获取Class对象
//com.ysh.demo.pratise12.User表示哪个包下哪个类
Class cl=Class.forName("com.ysh.demo.pratise12.User");
//获取属性名为name的属性
Field field=cl.getDeclaredField("name");
//获取修饰符
int n=field.getModifiers();
//将获取到的修饰符转为字符串
System.out.println(Modifier.toString());
通过构造器来创建一个类的对象:
package com.ysh.demo.review08;
import java.lang.reflect.*;
public class ClassTest01 {
public static void main(String[] args) throws Exception{
//获取Class对象
//com.ysh.demo.pratise12.User表示哪个包下哪个类
Class<User> cl=User.class;
//指定构造函数
//调用带有一个参数且参数类型为int型的构造函数
Constructor cons1=cl.getConstructor(int.class);
User user1=(User)cons1.newInstance(1);
System.out.println(user1);
//调用带有两个参数且参数类型顺序为(String,int)的构造函数
Constructor cons2=cl.getConstructor(String.class,int.class);
//调用哪个构造函数必须在newInstance()方法中传入相对应的实参
User user2=(User)cons2.newInstance("yang",19);
System.out.println(user2);
}
}
class User {
private String name;
private String id;
private int age;
public User(){
}
public User(String name) {
this.name = name;
}
public User(int age) {
this.age = age;
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User(String name, String 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 String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void test1(){
System.out.println("hello");
}
private static void test2(){
System.out.println("world");
}
public static void test3(){
System.out.println("hello1");
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", age=" + age +
'}';
}
}
通过反射来获取一个类的属性:
package com.ysh.demo.review08.one;
import java.lang.reflect.Field;
public class ClassTest02 {
public static void main(String[] args) throws Exception {
//构建Class对象
Class<User> cl=User.class;
//获取属性数组
Field[] field=cl.getDeclaredFields();
//获取指定属性名的属性,在这里我指定了名为name的属性
Field field1=cl.getDeclaredField("name");
User user=cl.getConstructor(String.class,String.class,int.class).newInstance("yang","123",12);
//增强for遍历存储属性名的数组
for (Field f:field){
System.out.println(f);
}
//修改属性的值
field1.set(user,"灰太狼");
//获取属性的值
field1.get(user);
//获取属性名
System.out.println(field1.getName());
//获取属性的修饰符 Modifier.toString()是将字符变为字符串
System.out.println(Modifier.toString(field1.getModifiers()));
}
}
class User {
private String name;
private String id;
private int age;
public User(){
}
public User(String name) {
this.name = name;
}
public User(int age) {
this.age = age;
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User(String name, String 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 String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private void test1(){
System.out.println("hello");
}
private static void test2(){
System.out.println("world");
}
public static void test3(){
System.out.println("hello1");
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", age=" + age +
'}';
}
}
数组在反射中的应用(借助Array):
package com.ysh.demo.review08;
import java.lang.reflect.Array;
public class ArrayClassTest02 {
public static void main(String[] args) {
//创建一个数组,并给数组赋予长度
Object obj=Array.newInstance(String.class,10);
//判断是否是数组
if(obj.getClass().isArray()){
//输出数组的长度
System.out.println(Array.getLength(obj));
}
Array.set(obj,0,"红太狼");
System.out.println(Array.get(obj, 0));
}
}
注解
注解的分类:
- 标记注解:一个没有成员定义的Annotation类型被称为标记注解;
- 单值注解:只有一个值
- 完整注解:拥有多个值
根据注解使用方法和用途分类:
- JDK内置系统注解
- 元注解
- 自定义注解
内置注解
@Override:限定重写父类方法,若想要重写父类的一个方法时,需 要使用该注解告知编译器我们正在重写一个方法。如此 一来,当父类的方法被删除或修改了,编译器会提示错 误信息;或者该方法不是重写也会提示错误。
@Deprecated:标记已过时,当我们想要让编译器知道一个方法已经被 弃用(deprecate)时,应该使用这个注解。
@SuppressWarnings:抑制编译器警告,该注解仅仅告知编译器,忽略它们产 生了特殊警告。
元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4 个标准的meta-annotation类型,它们被用来提供对其 它 annotation类型作说明。Java5.0定义的元注解有四个,这些类型和它们所支持的类在java.lang.annotation 包中可以找到。
元注解—@Target:
用于描述注解的使用范围(即:被描述的注解可以用在 什么地方)。表示支持注解的程序元素的种类,一些可能的值有TYPE, METHOD(方法), CONSTRUCTOR, FIELD(属性)等等。如 果Target元注解不存在,那么该注解就可以使用在任何 程序元素之上。
元注解—@Retention:
表示需要在什么级别保存该注释信息,用于描述注解的 生命周期(即:被描述的注解在什么范围内有效)表示 注解类型保留时间的长短。取值(RetentionPoicy)有:
- SOURCE:在源文件中有效(即源文件保留)
- CLASS:在class文件中有效(即class保留)
- RUNTIME:在运行时有效(即运行时保留)
元注解—@Document:
表示使用该注解的元素应被javadoc或类似工具文档化, 它应用于类型声明,类型声明的注解会影响客户端对注 解元素的使用。如果一个类型声明添加了Documented注 解,那么它的注解会成为被注解元素的公共API的一部 分,@Documented是一个标记注解。
元注解—@Inherited:
表示一个注解类型会被自动继承,如果用户在类声明的 时候查询注解类型,同时类声明中也没有这个类型的注 解,那么注解类型会自动查询该类的父类,这个过程将 会不停地重复,直到该类型的注解被找到为止,或是到 达类结构的顶层(Object)。
自定义注解
@interface::用来声明一个注解。注解类里的每一个方法 实际上是声明了一个配置参数。方法的名称就是参数的 名称,返回值类型就是参数的类型。可以通过default来 声明参数的默认值。
自定义注解的格式:
@interface用来声明一个注解,其中的每一个方法实际上 是声明了一个配置参数。方法的名称就是参数的名称, 返回值类型就是参数的类型(返回值类型只能是基本类 型、Class、String、enum)。可以通过default来声明参 数的默认值。
注解参数注意事项:
- 修饰符:只能用public或默认(defalut)这两个访问权限修饰符,默认为defalut;
- 注解中的方法的返回值,作为注解参数,只支持以下数据类型:
- 基本数据类型 (int,float,boolean,byte,double,char,long,shor t);
- String类型;
- Class类型;
- enum类型;
- Annotation类型;
- 以及 以上所有类型的数组
参数:注解中的方法不能存在参数
默认值:可以包含默认值,使用defalut来声明默认值
代码实例:
自定义注解代码:
package com.ysh.demo.pratise12;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Idertified {
int value() default 0;
String name() default "null";
}
对自定义注解的基本使用:
package com.ysh.demo.pratise12;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class AnnotationTest {
@Idertified
static int age;
@Idertified
String name;
int id;
@Override
public String toString() {
return "AnnotationTest{" +
"age=" + age +
", name='" + name + '\'' +
", id=" + id +
'}';
}
//
@Idertified(value = 1)
public static void test1(int a){
System.out.println("hello");
}
@Idertified(value = 0)
public static void test2(){
System.out.println("world");
}
public static void main(String[] args) throws Exception {
//获取Class对象,因为Class是一切的源头
//根据哪个类需要反射,构建其Class对象
Class<AnnotationTest> an=AnnotationTest.class;
//实例化AnnotationTest对象
AnnotationTest a=an.getConstructor().newInstance();
//获取指定的方法,并且传入向对应的参数Class<?>... parameterTypes
Method method4 = an.getDeclaredMethod("test1", int.class);
//获取所有的方法将所有的方法存储在一个数组中
Method []methods = an.getDeclaredMethods();
//增强for遍历
for (Method method:methods){
System.out.println(method);
//判断方法是否含有Idertified的注解
if (method.isAnnotationPresent(Idertified.class)){
//得到该方法上的注释内容,即得到注释接口对象
Idertified id=method.getDeclaredAnnotation(Idertified.class);
//通过对象获得对应属性的属性值
int num = id.value();
System.out.println(num);
if (num==0){
/*
第一种方法:通过对象调用方法
*/
method.invoke(a);
/*
第二种方法:通过类调用静态方法
即:method.invoke(null)
*/
}
}
}
//获取属性数组
Field[] field = an.getDeclaredFields();
for (Field f:field){
//对属性数组进行筛选,即将有注解的属性筛选出来
if (f.isAnnotationPresent(Idertified.class)){
//如果属性是String类型的,即给该属性赋值
if (f.getType()==String.class){
f.set(a,"你真的很帅");
}
//如果属性是int类型,即给该属性赋值
if (f.getType()==int.class){
f.set(null,1);
}
System.out.println(a.toString());
}
}
}
}