------ android培训、java培训、期待与您交流! ----------
一 JAVA反射机制:
什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射有什么作用?
反射可以在我们运行时,加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields(成员属性)设值、或唤起其methods成员方法。
反射可以程序运行时,改变程序结构或变量类型,比如为一个Integer集合添加String元素
也可以改变或获取成员属性(字段),获取构造方法,获取并调用成员方法,
反射怎么用?
1. 获取字节码对象的三种方法:
方式一:
* 1,Object类中的getClass()方法的。
* 想要用这种方式,必须要明确具体的类,并创建对象。
* 缺点:不够简单
public static void getClassObject_1(){
Person p = new Person();
Class clazz = p.getClass();
方式二:
* 2,任何数据类型都具备一个静态的属性.class来获取其对应的Class对象。
* 相对简单,但是还是要明确用到类中的静态成员。
* 缺点:不够扩展。
public static void getClassObject_2() {
Class clazz = Person.class;
方式三:最常用
* 只要通过给定的类的 字符串名称就可以获取该类,更为扩展。
* 可是用Class类中的方法完成。
* 该方法就是forName.
* 这种方式只要有名称即可,可以将名称写在配置文件中,同时给定一个引用名,用forName与引用名关联,
到时候对象名有更改,那么只需要修改引用所对应的类名字符串就可以. 更为方便,扩展性更强。
String className = "cn.itcast.bean.Person";(这里要注意:是包名.类名的字符串表现形式,这与导不导包没有关系)
Class clazz = Class.forName(className);
2. 获取构造方法得到对象
关健字:Construtor
获取对象方法.newInstance
1.当只需要获得无参构造成的对象时
String name = "cn.itcast.bean.Person";
//找寻该名称类文件,并加载进内存,并产生Class对象。
Class clazz = Class.forName(name);
//如何产生该类的对象呢?
Object obj = clazz.newInstance();
2.当想获取有参构造的对象.
String name = "cn.itcast.bean.Person";
//找寻该名称类文件,并加载进内存,并产生Class对象。
Class clazz = Class.forName(name);
//获取到了指定的构造函数对象。
Constructor constructor = clazz.getConstructor(String.class,int.class);(这里传构造方法参数类型的字节码对象)
这里可以用可变参数,也就是用一个数组也可实现:
或:Constructor constructor = clazz.getConstructor(new Class[]{String.class,int.class});
//通过该构造器对象的newInstance方法进行对象的初始化。
Object obj = constructor.newInstance("小明",38);(直接传构造方法参数)
或:Object obj = constructor.newInstance(Object[]{"小明",38});(直接传构造方法参数)
Constructor[] constructor = clazz.getConstructors();
这是获取包含所有按由上至下的构造方法的,一个数组
3. 获取和改变成员属性(字段)
这有两种,
一是公共(public )字段:Field field = null;//clazz.getField("age");//只能获取公有的,
二是非公共字段:
Class clazz = Class.forName("cn.itcast.bean.Person");
field = clazz.getDeclaredField("age");//只获取本类,但包含私有。
//对私有字段的访问取消权限检查。暴力访问。
field.setAccessible(true);
Object obj = clazz.newInstance();
field.set(obj, 89);(里面的参数是,对象+想要设制的值)
Object o = field.get(obj);获得改字段的
4. 获取和运行成员方法
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("paramMethod", String.class,int.class);
参数(方法名字符串表现形式,方法参数1的字节码对象1,方法参数2的字节码对象)
Object obj = clazz.newInstance();
method.invoke(obj, "小强",89);(本类对象,方法参数1,方法参数二)
Method[] methods = clazz.getMethods();//获取的都是公有的方法的数组。
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
Method[] methods = clazz.getDeclaredMethods();//只获取本类中所有方法,包含私有的数组。
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
运行方法:
反射什么时候用?
经典的就是xml或者properties里面写上了配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射,根据这个字符串获得某个类的实例,这样就可以动态配置一些东西,不用每一次都要在代码里面去new或者做其他的事情,以后要改的话直接改配置文件,代码维护起来就很方便了,同时有时候要适应某些需求,Java类里面不一定能直接调用另外的方法,这时候也可以通过反射机制来实现。
总的来说,自己写的很少,具体什么时候要用那要看需求,楼上说得对,无非就是根据一个String来得到你要的实体对象,然后调用它原来的东西。但是如果是要自己写框架的话,那就会用得比较多了。
二 Annotation(注解)
一、Annotation是什么?
Annotation注解是代码里的特殊标记,是java5.0后的一个新特性,
二、Annotation有什么用?
注解的主要作用是对类或类的成员进行功能的解释及限制.
二是可以用注解替换配置文件,也就是说可以在注解里定义一些配置信息,然后通过反射技术去得到类里的注解,以决定怎么去运行类。
三、Annotation怎么用?
(一)三个基本的注解:
1. @Override: 限定重写父类方法,
该注解只能用于方法,意思就是说这个方法只能是父类中存在的,子类是在重写.否则就报错.
@Override
public String toString() {
return "";
}
2. @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
但是仍然可以用..只是不推荐用.
@Deprecated
public List<Object> findAll(){
return null;
}
3. @SuppressWarnings: 抑制编译器警告. ,
用了后,一些泛型类的警告就不会出现.
@SuppressWarnings("rawtypes")
public List findRecords(){
return null;
}
(二)元Annotation(注解)
元注解就是jdk定义的只能修饰注解的的注解
有发下三个:
1. @Retention: 元注解
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留的域,
@Rentention 包含一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域,指示该注解存在的范围是什么
RetentionPolicy.CLASS: 编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注释. 这是默认值
RetentionPolicy.RUNTIME:编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注释. 程序可以通过反射获取该注释
RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释
@Retention(RetentionPolicy.RUNTIME)
2. @Target: 元注解
指定注解用于修饰类的哪个成员. @Target 包含了一个名为 value 的成员变量.
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
@Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
@Target(ElementType.METHOD)
(三)特殊属性:
注解中的属性名称为value的。在使用时直接传入值即可。
注解中的属性名称为value数组。在使用时直接传入值即可,传一个用"",多个{"",""}。
(四)使用注解
在类上或方法或字段上用@注解名(参数)后面不要分号
如果是用java已提供的注解,那么直接使用.
1. 自定义注解
① 注解用@interface关健字
② 声名注解属性:
注解属性只有8种基本数据类型,及String class 注解类型,emum枚举类型及以上类型的一维数组
数据类型 属性名();
@Annotation1(name="mingyue",age=1,gender=Gender.FEMALE,a=@Annotation2(name2="bbb"))
@Annotation2(name="bbb",value="vvv")
@Annotation3(name="ccc",value={"ddd","eee","ffff"})
③ 定义属性的默认值:在()后用default标识
String name() default "";
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DbInfo {
String url() default "";
String username() default "root";
String password() default "sorry";
}
2. 在类上引用自定好的注解
public class JdbcUtils {
@DbInfo(url="jdbc:mysql://localhost:3306/day21",username="root",password="sorry")
public static Connection getConnection(String url,String username,String password){
System.out.println(url);
System.out.println(username);
System.out.println(password);
return null;
}
}
3. 通过反射引用注解在方法中运用
public static void main(String[] args) throws Exception {
//通过反射获得类的方法对象
Class<?> clazz=Class.forName("com.itheima.JdbcUtils");
Method mt=clazz.getMethod("getConnection", String.class,String.class,String.class);
//通过方法过象获得注解
DbInfo di =mt.getAnnotation(DbInfo.class);
//通过注解去获得其属性
String url=di.url();
String usename=di.username();
String password=di.password();
//用方法对象运行方法
mt.invoke(clazz.newInstance(), url,usename,password);
//因为getConnection是静态的,所以也可以不传对象参数,另外参数也有两种写法,如下:
mt.invoke(clazz.newInstance(), new Object[]{url,usename,password});
mt.invoke(null,new String[]{url,usename,password});
mt.invoke(null, url,usename,password);
}
四、Annotation什么时候用?
当要对代码进行解释的时候,或者在servlet中实现一个都没有.
五、Annotation有什么特点?
注解在servlet3.0中的运用,可以替换配置文件的功能.