标签:end field类 反射 导致 完成 白求恩 创建对象 作用 tco
通过反射技术对象类进行了解剖得到了类的所有成员。
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。)语言的一个关键性质。
要获得该类字节码文件对象,就是Class对象
* 开发IDE(集成开发环境),比如IDEA,Eclipse
* 各种框架的设计和学习 比如Spring,Hibernate,Struct,Mybaits....
//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
// 类型的对象,而我不知道你具体是什么类,用这种方法
Person p1 = new Person();
Class c1 = p1.getClass();
//2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
// 这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = Person.class;
//3、通过 Class 对象的 forName("类的全名") 静态方法来获取,用的最多,
// 但可能抛出 ClassNotFoundException 异常
Class c3 = Class.forName("com.ys.reflex.Person");
需要注意的是:一个类在 JVM 中只会有一个 Class 实例,即我们对上面获取的 c1,c2,c3进行 equals 比较,发现都是true
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
//获得类完整的名字
String className = c2.getName();
System.out.println(className);//输出com.ys.reflex.Person
//获得类的public类型的属性。
Field[] fields = c2.getFields();
for(Field field : fields){
System.out.println(field.getName());//age
}
//获得类的所有属性。包括私有的
Field [] allFields = c2.getDeclaredFields();
for(Field field : allFields){
System.out.println(field.getName());//name age
}
//获得类的public类型的方法。这里包括 Object 类的一些方法
Method [] methods = c2.getMethods();
for(Method method : methods){
System.out.println(method.getName());//work waid equls toString hashCode等
}
//获得类的所有方法。
Method [] allMethods = c2.getDeclaredMethods();
for(Method method : allMethods){
System.out.println(method.getName());//work say
}
//获得指定的属性
Field f1 = c2.getField("age");
System.out.println(f1);
//获得指定的私有属性
Field f2 = c2.getDeclaredField("name");
//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
f2.setAccessible(true);
System.out.println(f2);
//创建这个类的一个对象
Object p2 = c2.newInstance();
//将 p2 对象的 f2 属性赋值为 Bob,f2 属性即为 私有属性 name
f2.set(p2,"Bob");
//使用反射机制可以打破封装性,导致了java对象的属性不安全。
System.out.println(f2.get(p2)); //Bob
//获取构造方法
Constructor [] constructors = c2.getConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor.toString());//public com.ys.reflex.Person()
}
反射之操作构造方法的目的
* 获得Constructor对象来创建类的对象。
Constructor类概述
* 类中的每一个构造方法都是一个Constructor类的对象
1. Constructor getConstructor(Class... parameterTypes)
* 根据参数类型获得对应的Constructor对象。
* 只能获得public修饰的构造方法
2. Constructor getDeclaredConstructor(Class... parameterTypes)
* 根据参数类型获得对应的Constructor对象,包括private
3. Constructor[] getConstructors()
获得类中的所有构造方法对象,只能获得public的
4. Constructor[] getDeclaredConstructors()
获得类中的所有构造方法对象,包括private修饰的
1. T newInstance(Object... initargs)
根据指定的参数创建对象
2. void setAccessible(true)
设置是否取消权限检查,true取消权限检查,false表示不取消(暴力反射)
public class ReflectDemo03 {
/*
Constructor[] getConstructors()
获得类中的所有构造方法对象,只能获得public的
Constructor[] getDeclaredConstructors()
获得类中的所有构造方法对象,包括private修饰的
*/
@Test
public void test03() throws Exception {
// 获得Class对象
Class c = Student.class;
// 获得类中的所有构造方法对象,只能获得public的
// Constructor[] cons = c.getConstructors();
Constructor[] cons = c.getDeclaredConstructors();
for (Constructor con:cons) {
System.out.println(con);
}
}
/*
Constructor getDeclaredConstructor(Class... parameterTypes)
根据参数类型获得对应的Constructor对象
*/
@Test
public void test02() throws Exception {
// 获得Class对象
Class c = Student.class;
// 获得两个参数构造方法对象
Constructor con = c.getDeclaredConstructor(String.class,String.class);
// 取消权限检查(暴力反射)
con.setAccessible(true);
// 根据构造方法创建对象
Object obj = con.newInstance("rose","女");
System.out.println(obj);
}
/*
Constructor getConstructor(Class... parameterTypes)
根据参数类型获得对应的Constructor对象
*/
@Test
public void test01() throws Exception {
// 获得Class对象
Class c = Student.class;
// 获得无参数构造方法对象
Constructor con = c.getConstructor();
// 根据构造方法创建对象
Object obj = con.newInstance();
System.out.println(obj);
// 获得有参数的构造方法对象
Constructor con2 = c.getConstructor(String.class, String.class,int.class);
// 创建对象
Object obj2 = con2.newInstance("jack", "男",18);
System.out.println(obj2);
}
}
反射之操作成员方法的目的
* 操作Method对象来调用成员方法
Method类概述
* 每一个成员方法都是一个Method类的对象。
* Method getMethod(String name,Class...args);
* 根据方法名和参数类型获得对应的构造方法对象,只能获得public的
* Method getDeclaredMethod(String name,Class...args);
* 根据方法名和参数类型获得对应的构造方法对象,包括private的
* Method[] getMethods();
* 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
* Method[] getDeclaredMethods();
* 获得类中的所有成员方法对象,返回数组,只获得本类的,包含private修饰的
* Object invoke(Object obj, Object... args)
* 调用指定对象obj的该方法
* args:调用方法时传递的参数
* void setAccessible(true)
设置是否取消权限检查,true取消权限检查,false表示不取消(暴力反射)
public class ReflectDemo04 {
// 反射操作静态方法
@Test
public void test04() throws Exception {
// 获得Class对象
Class c = Student.class;
// 根据方法名获得对应的成员方法对象
Method method = c.getDeclaredMethod("eat",String.class);
// 通过method执行对应的方法
method.invoke(null,"蛋炒饭");
}
/*
* Method[] getMethods();
* 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
* Method[] getDeclaredMethods();
* 获得类中的所有成员方法对象,返回数组,只获得本类的,包含private修饰的
*/
@Test
public void test03() throws Exception {
// 获得Class对象
Class c = Student.class;
// 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的
// Method[] methods = c.getMethods();
// 获得类中的所有成员方法对象,返回数组,只获得本类的,包含private修饰的
Method[] methods = c.getDeclaredMethods();
for (Method m: methods) {
System.out.println(m);
}
}
/*
Method getDeclaredMethod(String name,Class...args);
* 根据方法名和参数类型获得对应的构造方法对象,
*/
@Test
public void test02() throws Exception {
// 获得Class对象
Class c = Student.class;
// 根据Class对象创建学生对象
Student stu = (Student) c.newInstance();
// 获得sleep方法对应的Method对象
Method m = c.getDeclaredMethod("sleep");
// 暴力反射
m.setAccessible(true);
// 通过m对象执行stuy方法
m.invoke(stu);
}
/*
Method getMethod(String name,Class...args);
* 根据方法名和参数类型获得对应的构造方法对象,
*/
@Test
public void test01() throws Exception {
// 获得Class对象
Class c = Student.class;
// 根据Class对象创建学生对象
Student stu = (Student) c.newInstance();
// 获得study方法对应的Method对象
Method m = c.getMethod("study");
// 通过m对象执行stuy方法
m.invoke(stu);
/// 获得study方法对应的Method对象
Method m2 = c.getMethod("study", int.class);
// 通过m2对象执行stuy方法
m2.invoke(stu,8);
}
}
反射之操作成员变量的目的
* 通过Field对象给对应的成员变量赋值和取值
Field类概述
* 每一个成员变量都是一个Field类的对象。
* Field getField(String name);
* 根据成员变量名获得对应Field对象,只能获得public修饰
* Field getDeclaredField(String name);
* 根据成员变量名获得对应Field对象,包含private修饰的
* Field[] getFields();
* 获得所有的成员变量对应的Field对象,只能获得public的
* Field[] getDeclaredFields();
* 获得所有的成员变量对应的Field对象,包含private的
void set(Object obj, Object value)
void setInt(Object obj, int i)
void setLong(Object obj, long l)
void setBoolean(Object obj, boolean z)
void setDouble(Object obj, double d)
Object get(Object obj)
int getInt(Object obj)
long getLong(Object obj)
boolean getBoolean(Object ob)
double getDouble(Object obj)
void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。
Class getType(); 获取属性的类型,返回Class对象。
setXxx方法都是给对象obj的属性设置使用,针对不同的类型选取不同的方法。
getXxx方法是获取对象obj对应的属性值的,针对不同的类型选取不同的方法。
public class ReflectDemo05 {
/*
Field[] getFields();
* 获得所有的成员变量对应的Field对象,只能获得public的
Field[] getDeclaredFields();
* 获得所有的成员变量对应的Field对象,包含private的
*/
@Test
public void test02() throws Exception {
// 获得Class对象
Class c = Student.class;
// 获得所有的成员变量对应的Field对象
// Field[] fields = c.getFields();
// 获得所有的成员变量对应的Field对象,包括private
Field[] fields = c.getDeclaredFields();
for (Field f: fields) {
System.out.println(f);
}
}
/*
Field getField(String name);
根据成员变量名获得对应Field对象,只能获得public修饰
Field getDeclaredField(String name);
* 根据成员变量名获得对应Field对象,包含private修饰的
*/
@Test
public void test01() throws Exception {
// 获得Class对象
Class c = Student.class;
// 创建对象
Object obj = c.newInstance();
// 获得成员变量name对应的Field对象
Field f = c.getField("name");
// 给成员变量name赋值
// 给指定对象obj的name属性赋值为jack
f.set(obj,"jack");
// 获得指定对象obj成员变量name的值
System.out.println(f.get(obj)); // jack
// 获得成员变量的名字
System.out.println(f.getName()); // name
// 给成员变量gender赋值
// 获得成员变量gender对应的Field对象
Field f1 = c.getDeclaredField("gender");
// 暴力反射
f1.setAccessible(true);
// 给指定对象obj的gender属性赋值为男
f1.set(obj,"男");
System.out.println(obj);
}
}
注解是JDK1.5的新特性。
注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
标记(注解)可以加在包,类,字段,方法,方法参数以及局部变量上。
注解是给编译器或JVM看的,编译器或JVM可以根据注解来完成对应的功能。
注解的作用就是给程序带入参数。
以下几个常用操作中都使用到了注解:
生成帮助文档:@author和@version
@author:用来标识作者姓名。
@version:用于标识对象的版本号,适用范围:文件、类、方法。
使用@author和@version注解就是告诉Javadoc工具在生成帮助文档时把作者姓名和版本号也标记在文档中。如下图:
编译检查:@Override
@Override:用来修饰方法声明。
框架的配置(框架=代码+配置)
public @interface 注解名{
}
如:定义一个名为Student的注解
public @interface Student {
}
属性的格式
属性定义示例
// 姓名
String name();
// 年龄
int age() default 18;
// 爱好
String[] hobby();
属性适用的数据类型
* 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
* String,Class,注解类型,枚举类
* 以上类型的数组形式
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String value();
double price() default 100;
String[] authros();
}
/**
特殊属性value
* 如果注解中只有一个属性且名字叫value,则在使用该注解时可以直接给该属性赋值,而不需要给出属性名。
* 如果注解中除了value属性之外还有其他属性且只要有一个属性没有默认值,则在给属性赋值时
value属性名也不能省略了。
小结:如果注解中只有一个属性时,一般都会将该属性名命名为value
*/
@interface TestA{
String[] value();
int age() default 100;
String name();
}
@interface TestB{
String name();
}
@TestB(name = "zzz")
@TestA(name = "yyy",value = {"xxx","xxx"})
public class AnnotationDemo02 {
}
元注解概述
* Java官方提供的注解
* 用来定义注解的注解
* 任何官方提供的非元注解的定义都使用到了元注解。
常用的元注解
* @Target
* 作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
* 可使用的值定义在ElementType枚举类中,常用值如下
TYPE,类,接口
FIELD, 成员变量
METHOD, 成员方法
PARAMETER, 方法参数
CONSTRUCTOR, 构造方法
LOCAL_VARIABLE, 局部变量
* @Retention
* 作用:用来标识注解的生命周期(有效范围)
* 可使用的值定义在RetentionPolicy枚举类中,常用值如下
* SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
* CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
* RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段
什么是注解解析
* 使用Java技术获得注解上数据的过程则称为注解解析。
与注解解析相关的接口
* Annotation: 注解类,该类是所有注解的父类。
* AnnotatedElement:该接口定义了与注解解析相关的方法
T getAnnotation(Class<T> annotationClass) 根据注解类型获得对应注解对象
Annotation[] getAnnotations()
* 获得当前对象上使用的所有注解,返回注解数组,包含父类继承的
Annotation[] getDeclaredAnnotations()
* 获得当前对象上使用的所有注解,返回注解数组,只包含本类的
boolean isAnnotationPresent(Class<Annotation> annotationClass)
* 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
获取注解数据的原理
* 注解作用在哪个成员上就会得该成员对应的对象来获得注解
* 比如注解作用成员方法,则要获得该成员方法对应的Method对象
* 比如注解作用在类上,则要该类的Class对象
* 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
* Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String value();
double price() default 100;
String[] authros();
}
@Book(value = "红楼梦",authros = {"曹雪芹"})
public class BookShelf {
@Book(value = "西游记",authros = {"吴承恩","白求恩"},price = 200)
public void showBook(){
}
}
/**
什么是注解解析
* 使用Java技术获得注解上数据的过程则称为注解解析。
与注解解析相关的接口
* Annotation: 注解类,该类是所有注解的父类。
* AnnotatedElement:该接口定义了与注解解析相关的方法
T getAnnotation(Class<T> annotationClass) 根据注解类型获得对应注解对象
Annotation[] getAnnotations()
* 获得当前对象上使用的所有注解,返回注解数组,包含父类继承的
Annotation[] getDeclaredAnnotations()
* 获得当前对象上使用的所有注解,返回注解数组,只包含本类的
boolean isAnnotationPresent(Class<Annotation> annotationClass)
* 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
获取注解数据的原理
* 注解作用在哪个成员上就会得该成员对应的对象来获得注解
* 比如注解作用成员方法,则要获得该成员方法对应的Method对象
* 比如注解作用在类上,则要该类的Class对象
* 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
* Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口
*/
public class AnnotationDemo04 {
/*
获得类上使用的注解数据
*/
@Test
public void test02() throws Exception {
// 获得Class对象
Class c = BookShelf.class;
// 判断类上是否使用Book注解
if(c.isAnnotationPresent(Book.class)){
// 根据注解的Class对象获得对应的注解对象
Book annotation = (Book) c.getAnnotation(Book.class);
// 获得书名
System.out.println(annotation.value());
// 获得作者
System.out.println(Arrays.toString(annotation.authros()));
// 获得价格
System.out.println(annotation.price());
}
// 获得当前对象上使用的所有注解,返回注解数组
// Annotation[] annotations = c.getAnnotations();
Annotation[] annotations = c.getDeclaredAnnotations();
System.out.println(Arrays.toString(annotations));
}
/*
获得成员方法上注解的数据
*/
@Test
public void test01() throws Exception {
// 获得Class对象
Class c = BookShelf.class;
// 获得成员方法对应的Method对象
Method m = c.getMethod("showBook");
// 根据注解的Class对象获得对应的注解对象
Book annotation = m.getAnnotation(Book.class);
// 获得书名
System.out.println(annotation.value());
// 获得作者
System.out.println(Arrays.toString(annotation.authros()));
// 获得价格
System.out.println(annotation.price());
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
}
public class TestMyTest {
@MyTest
public void tests01(){
System.out.println("test01");
}
public void tests02(){
System.out.println("test02");
}
@MyTest
public void tests03(){
System.out.println("test03");
}
}
/**
* @author pkxing
* @version 1.0
* @Package com.itheima
* @date 2018/6/23 下午9:10
*/
public class AnnotationDemo05 {
public static void main(String[] args) throws Exception {
// 获得Class对象
Class c = TestMyTest.class;
Object obj = c.newInstance();
// 获得所有成员方法
Method[] methods = c.getMethods();
for(Method m:methods){
// 判断m方法是否使用了MyTest注解
if(m.isAnnotationPresent(MyTest.class)){
// 调用方法
m.invoke(obj);
}
}
}
}
标签:end field类 反射 导致 完成 白求恩 创建对象 作用 tco
原文地址:https://www.cnblogs.com/Constantin/p/14327339.html