反射 注解

反射

反射的介绍
“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”,如Python,Ruby是动态语言;显然C++,Java,C#不是动态语言,但是JAVA有着一个非常突出的动态相关机制:Reflection。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

/*** 入门级示例:通过对象获取 包名.类名 
* @author Administrator 
* */ 
public class Simple { 
public static void main(String[] args) { 
Simple s=new Simple(); 
System.out.println(s.2.getName()); 
} 
}

Java反射机制,可以实现以下功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理。
在这里插入图片描述
获取源头Class(重点)
所有类的对象其实都是Class的实例。这个Class实例可以理解为类的模子,就是包含了类的结构信息,类似于图纸。
获取Class对象

public class Source { 
public static void main(String[] args) { 
//第一种方式:对象.class 
Source s=new Source(); 
Class<?>c1=s.getClass(); 
//第二种方式:类.class 
Class<?>c2=Source.class; 
//第三种方式(推荐方式):Class.forName() 
Class<?>c3=null; 
try {
c3=Class.forName("com.shsxt.ref.simple.Source"); 
} catch (ClassNotFoundException e) { 
e.printStackTrace(); 
}
System.out.println(c1.getName()); 
System.out.println(c2.getName()); 
System.out.println(c3.getName()); 
} 
}

获取修饰符
获取修饰符,使用Modifier即可
在这里插入图片描述

Class<?>clz=Class.forName("com.shsxt.ref.simple.User"); 
//获得修饰符 
int n=clz.getModifiers(); 
//使用Modifier转换为相应的字符串 
System.out.println(Modifier.toString(n));

创建对象

构造器
根据Class对象,我们可以获得构造器,为实例化对象做准备。调用以下api即可
在这里插入图片描述

public class GetConstructor { 
public static void main(String[] args) { 
try {Class<?>clz=Class.forName("com.shsxt.ref.simple.User"); 
//1、获取所有的public 权限的构造器 
Constructor<?>[]con=clz.getConstructors(); 
//注意查看构造器的顺序 
for(Constructor<?> c:con){ 
System.out.println(c); 
}
//2、获取所有的构造器 
con=clz.getDeclaredConstructors(); 
System.out.println("--------------"); 
for(Constructor<?> c:con){ 
System.out.println(c); 
}
System.out.println("----------------"); 
//3、获取指定的构造器(放入具体的类型) 
Constructor<?> c=clz.getConstructor(String.class); 
System.out.println(c); 
//非public权限 
System.out.println("----------------"); c=clz.getDeclaredConstructor(String.class,String.class); 
System.out.println(c); 
} catch (ClassNotFoundException e) { 
// TODO Auto-generated catch block 
e.printStackTrace(); 
} catch (NoSuchMethodException e) { 
// TODO Auto-generated catch block 
e.printStackTrace(); 
} catch (SecurityException e) { 
// TODO Auto-generated catch block 
e.printStackTrace(); 
} 
   } 
      }

实例化对象(重点)
创建对象的方式,有new 、克隆、反序列化,再加一种,根据Class对象,使用newInstance() 或者构造器实例化对象。调用以下api即可
在这里插入图片描述

//获取源头 
Class<?> clz = Class.forName("com.shsxt.ref.simple.User"); 
//第一种:通过newInstance()创建对象 
User user=(User)clz.newInstance(); 
user.setUname("sxt"); 
user.setUpwd("good"); 
//第二种:通过getDeclaredConstructors()创建对象,取得全部构造函数(注意顺序) 
Constructor<?>[] cons=clz.getDeclaredConstructors(); 
for(Constructor<?>c:cons){ 
System.out.println(c); 
}
//注意观察上面的输出结果,再实例化,否则参数容易出错 
User u1=(User)cons[0].newInstance("shsxt","good"); 
User u2=(User)cons[1].newInstance("sxt"); 
User u3=(User)cons[2].newInstance(); 
System.out.println(u1.getUname()+u1.getUpwd());

**注意:newInstance()是调用空构造,如果空构造不存在,会出现异常。**由此可知,使用其他构造器创建对象比较麻烦,使用空构造非常简单。确保空构造存在
父类与接口
我们还可以通过api获取接口与父类
在这里插入图片描述

Class<?> clz =Class.forName("com.shsxt.ref.simple.User"); 
//获取所有接口 
Class<?>[] inters=clz.getInterfaces(); 
for(Class<?> in:inters){ 
System.out.println(in.getName()); 
}
//获取父类 
Class<?> cls=clz.getSuperclass(); 
System.out.println("继承的父类为:"+cls.getName());

属性和方法

属性
获取所有属性(包括父类或接口) ,使用Field 即可操作
在这里插入图片描述

Class<?> clz = Class.forName("com.shsxt.ref.simple.User"); 
//获取属性 
System.out.println("===============本类属性=========="); 
// 取得本类的全部属性 
Field[] field = clz.getDeclaredFields(); 
for (int i = 0; i < field.length; i++) { 
// 1、权限修饰符 
int mo = field[i].getModifiers(); 
String vis = Modifier.toString(mo); 
// 2、属性类型 
Class<?> type = field[i].getType(); 
//3、名字 
String name = field[i].getName(); 
System.out.println(vis + " " + type.getName() + " "+ name + ";"); }
System.out.println("=========公开的属性包括接口或者父类属性======"); 
field = clz.getFields(); 
for (int i = 0; i < field.length; i++) { 
System.out.println(field [i]); 
}

方法
获取所有方法(包括父类或接口),使用Method即可。
在这里插入图片描述

public static void test() throws Exception { 
Class<?> clz = Class.forName("com.shsxt.ref.simple.User "); 
//获取属性 
System.out.println("===============本类方法==============="); 
// 取得全部公共方法 
Method[] methods =clz.getMethods(); 
for(Method m:methods){ 
//1、权限 
int mod=m.getModifiers(); 
System.out.print(Modifier.toString(mod)+" "); 
//2、返回类型 
Class<?> returnType=m.getReturnType(); 
System.out.print(returnType.getName()+" "); 
//3、名字 
String name =m.getName(); 
System.out.print(name +"(");
//4、参数 
Class<?>[] para=m.getParameterTypes(); 
for(int i=0;i<para.length;i++){ 
Class<?> p =para[i]; 
System.out.print(p.getName() +" arg"+i); 
if(i!=para.length-1){ 
System.out.print(","); 
} 
  } 
     }

数组
操作数组需要借助Array类

//1、创建数组 
Object obj =Array.newInstance(int.class, 5); 
//2、获取大小 
if(obj.getClass().isArray()){ 
//3、判断是否为数组 
System.out.println(Array.getLength(obj)); 
//4、设置值 
Array.set(obj,0, 100); 
//5、获取值 
System.out.println(Array.get(obj,0)); 
}

类加载器(了解)
在java中有三种类类加载器:
⑴Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
⑵Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
⑶AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。 了解即可。
了解一下类的生命周期 :
在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。
类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载一次。
链接就是把二进制数据组装为可以运行的状态。链接分为校验,准备,解析这3个阶段
1、校验一般用来确认此二进制文件是否适合当前的JVM(版本),
2、准备就是为静态成员分配内存空间。并设置默认值
3、解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。当没有任何引用指向Class对象时就会被卸载,结束类的生命周期

注解

介绍
注解是Java 1.5 引入的,目前已被广泛应用于各种Java框架,如Hibernate,Jersey,Spring。注解相当于是一种嵌入在程序中的元数据,可以使用注解解析工具或编译器对其进行解析,也可以指定注解在编译期或运行期有效。在注解诞生之前,程序的元数据存在的形式仅限于java注释或javadoc,但注解可以提供更多功能,它不仅包含元数据,还能作用于运行期,注解解析器能够使用注解决定处理流程。
Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和任何元数据 (metadata)的途径和方法。
Annotation是一个接口,程序可以通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来获取注解里面的元数据。注解API非常强大,被广泛应用于各种Java框架。
元数据:描述数据的数据
注解的分类
根据注解参数的个数:

1)、标记注解:一个没有成员定义的Annotation类型被称为标记注解。
2)、单值注解:只有一个值
3)、完整注解:拥有多个值

根据注解使用方法和用途:

1)、JDK内置系统注解
2)、元注解
3)、自定义注解

内置注解
JavaSE中内置三个标准注解,定义在java.lang中:
@Override
限定重写父类方法,若想要重写父类的一个方法时,需要使用该注解告知编译器我们正在重写一个方法。如此一来,当父类的方法被删除或修改了,编译器会提示错误信息;或者该方法不是重写也会提示错误。

public interface Car { 
void run(); 
}
class QQ implements Car{ 
@Override 
public void run() {} 
}
class Bmw implements Car{ 
@Override 
void run() {} 
}

@Deprecated
标记已过时,当我们想要让编译器知道一个方法已经被弃用(deprecate)时,应该使用这个注解。Java推荐在javadoc中提供信息,告知用户为什么这个方法被弃用了,以及替代方法是什么

/**
* Deprecated -->该方法过时(有更好的解决方案) * 
* @author Administrator */ 
public class TestDeprecated { 
@Deprecated 
 public int test(){ 
 System.out.println("TestDeprecated.test()"); 
 return 0; 
 }
 public void test(int a){ 
 System.out.println("TestDeprecated.test(int)"); 
 } 
 }

@SuppressWarnings
抑制编译器警告,该注解仅仅告知编译器,忽略它们产生了特殊警告。如:在java泛型中使用原始类型。其保持性策略(retention policy)是SOURCE,在编译器中将被丢弃。

/*** 
SuppressWarnings 压制警告 * 
@author Administrator */ 
public class TestSuppressWarnings { 
public static void main(String[] args) { 
@SuppressWarnings("unused") 
List<String> list =new ArrayList<String>(); 
}
@SuppressWarnings("rawtypes") 
//没有定义范型
public static List test(){ return new ArrayList(); } }

自定义注解

@interface:用来声明一个注解。注解类里的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型。可以通过default来声明参数的默认值。

元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。Java5.0定义的元注解有四个,这些类型和它们所支持的类在ava.lang.annotation包中可以找到。
@Target
用于描述注解的使用范围(即:被描述的注解可以用在什么地方)。表示支持注解的程序元素的种类,一些可能的
值有TYPE, METHOD, CONSTRUCTOR, FIELD等等。如果Target元注解不存在,那么该注解就可以使用在任何程序元素之上。取值(ElementType)有:

1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

@Retention
表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)表示注解类型保留时间的长短。取值(RetentionPoicy)有:

1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)

@Documented
表示使用该注解的元素应被javadoc或类似工具文档化,它应用于类型声明,类型声明的注解会影响客户端对注解
元素的使用。如果一个类型声明添加了Documented注解,那么它的注解会成为被注解元素的公共API的一部分,@Documented是一个标记注解。
@Inherited
表示一个注解类型会被自动继承,如果用户在类声明的时候查询注解类型,同时类声明中也没有这个类型的注解,那么注解类型会自动查询该类的父类,这个过程将会不停地重复,直到该类型的注解被找到为止,或是到达类结构的顶层(Object)。

深入自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。
定义注解格式:
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

注解参数(即方法)
注解里面的每一个方法实际上就是声明了一个配置参数,其规则如下: 9.2.1. 修饰符
只能用public或默认(default)这两个访问权修饰 ,默认为default
方法的类型
注解体重点方法的返回值,作为注解参数,只支持以下数据类型

基本数据类型(int,float,boolean,byte,double,char,long,short);
String类型;
Class类型;
enum类型;
Annotation类型;
以上所有类型的数组

命名(方法的名字)
对取名没有要求,如果只有一个参数成员,最好把参数名称设为"value",后加小括号。
参数
注解中的方法不能存在参数
默认值
可以包含默认值,使用default来声明默认值

/** 码农定义注解 */ 
@Target(ElementType.FIELD) 
@Retention(RetentionPolicy.RUNTIME)
@Documented 
@interface Programmer{ String value() default "马云"; }
/*** 码农类型注解 * @author peida */ 
@Target(ElementType.FIELD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented @interface ProgrammerType { 
/*** 类型枚举 程序猿 射鸡师 */ 
public enum CoderType{MONKEYS,LION,CHOOK}; 
/*** 颜色属性 */ 
CoderType type() default CoderType.MONKEYS; 
}
/*** 码农制造厂 * @author Administrator */ 
@Target(ElementType.FIELD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@interface ProgrammerProductor { 
/*** 厂家编号 * @return */ 
public int id() default -1; 
/*** 厂家名称 * @return */ 
public String name() default "shsxt"; 
/*** 厂家地址 * @return */ 
public String address() default "上海"; }
/*** 注解使用 */
class Coder{ 
@Programmer("老裴") private String coderName; 
@ProgrammerType(type=CoderType.MONKEYS) private String coderType; @ProgrammerProductor(id=1,name="程序猿乐园",address="浦东新区") 
private String coderProductor; 
public String getCoderName() { 
return coderName; 
}
public void setCoderName(String coderName) { 
this.coderName = coderName; 
}
public String getCoderType() { 
return coderType; 
}
public void setCoderType(String coderType) { 
this.coderType = coderType; 
}
public String getCoderProductor() { 
return coderProductor; 
}
public void setCoderProductor(String coderProductor) { 
this.coderProductor = coderProductor; 
} 
}
发布了22 篇原创文章 · 获赞 6 · 访问量 447

猜你喜欢

转载自blog.csdn.net/ffgyfgj/article/details/105419297