-----------android培训、java培训、java学习型技术博客、期待与您交流! ------------
反射的概念:
Java反射机制是在运动状态中,对于任意一个类都能知道这个类的所有属性和方法。
对于任意一个对象都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
简单说:反射就是将Java类中的各种成分映射成相应的java类。
反射的基石:Class类。
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类的类名就是Class。
获取Class对象的三种方式:
1.Object中的getClass方法。对象.getClass
例如:new Date().getClass();
2.任何数据类型都具备的静态属性。类名.class
例如:System.class
3.通过给定的类的字符串名称使用Class.forName()方法类获取该类。
例如:Class.forName("java.util.Date");
相关面试题: Class.forName()的作用。
作用是返回字节码文件,返回的方式有两种。
1.这份字节码曾经被加载过,已经在java虚拟机中,直接返回。
2.虚拟机中没有这份字节码,用类加载器加载。加载进的字节码缓存在虚拟机中。
九个预定义类型的实例对象:
基本的 Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和double
)和关键字void
也表示为Class
对象。基本类型的字节码获取方式只有一种就是类名.class。例如int.class;void.class
数组也是一种Class的实例对象。
System.out.println(String.class.isPrimitive());//false
System.out.println(int.class.isPrimitive());//true
System.out.println(int.class == Integer.class);//false
System.out.println(int.class == Integer.TYPE);//true
System.out.println(int[].class.isPrimitive());//false
System.out.println(int[].class.isArray());//true
-----------------------------------------------------------------------------------------------------------------------------------------------------
获取Class中的构造函数Constructor类:
得到某个类中所有的构造方法:
例子:Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
得到某个类中指定的构造方法:
例子:
Constructor construcor = Class.forName("java.lang.String").getConstructor(StringBuffered.class);
String str = (String)construcor.newInstance(new StringBuffered("abc"));
System.out.println(str.charAt(1));
Class.newInstance()方法。
例子:String str = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的空参构造方法,然后用该构造方法创建实例对象。
反射会导致性能下降。
---------------------------------------------------------------------------------------------------------------------------------------------------
获取Class中的字段Field类:
例:
public class reflectPoint {
public int x ;
private int y;
public reflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
public class reflect1 {
public static void main(String[] args) throws Exception {
reflectPoint pt1 = new reflectPoint(3, 5);
//通过getField()方法,获取公共的字段
Field fieldX = pt1.getClass().getField("x");
System.out.println(fieldX.get(pt1));
//通过getDeclaredField(()方法获取私有方法
Field fieldY = pt1.getClass().getDeclaredField("y");
fieldY.setAccessible(true);//对私有字段取消访问权限,暴力访问。
System.out.println(fieldY.get(pt1));
}
}
---------------------------------------------------------------------------------------------------------------------------------------------------
获取Class中的方法。Method类代表某个类中的一个成员方法。
Method[] methods = Class.forName("java.lang.String").gerMethods();//获取公有方法。
methods = Class.forName("java.lang.String").gerDeclearedMethods();//获取私有的方法
例:
String str = "abc";
Method methodcharAt = String.class.getMethod("charAt", int.class);
methodcharAt.invoke(str,1);//b
methodcharAt.invoke(str,new Object[]{2});//c
例:调用主函数
Method mainMethod = Class.forName(className).getMethod("main" String[].class);
mainMethod.invoke(null,newObject[]{new String[]{"abc","def"}});//jdk1.5为了兼容1.4会将传入的数组拆包,newObject是为了拆包后得到一个String类型的数组
mainMethod.invoke(null,(Object)new String[]{"abc","def"});//强制类型转换为Object编译器会将String类型的数组当做对象来对待。
methodcharAt.invoke(null,1);//如果调用一个方法第一个参数是null,说明这个方法是静态的。
---------------------------------------------------------------------------------------------------------------------------------------------------
数组的反射:
具有相同维数和元素类型的数组,属于同一个类型,即具有相同的Class实例对象。
代表数组的class实例对象的getSuperClass()方法返回的父类为object类对应的class。
基本类型的额一维数组可以被当做object类型使用,不能当做Object[]类型使用。
非基本类型一维数组,及可以当做Object类型使用,又可以当做Object[]类型使用。
注意:Array.asList()方法处理int[]和String[]时的差异。
---------------------------------------------------------------------------------------------------------------------------------------------------
使用反射技术开发框架的原理:
反射的作用-->实现框架功能:因为在写程序时无法知道要被调用的类名,所以在程序中无法直接new某个实例对象,要用反射方式来获取。
框架与工具类的区别,工具类被用户的类调用,而框架则是调用用户提供的类。
用类加载器的方式管理资源和配置文件:
注意:开发时要使用绝对路径,但是绝对路径不是硬编码,应该是运算出来的。
1.使用io读取流读取。
InputStream ips = new FileInputStream("路径");
2.使用类加载器加载。
InputStream ips = ReflectPoint.class.getClassLoaderAsStream("路径");//路径不能以/打头
类提供的简便方法加载: InputStream ips = ReflectPoint.class.getResourceAsStream("name");//用相对路径的话是相对于ReflectPoint包所在目录即可,也可以用绝对路径这时需要/打头。
===================================================================================
注解:
注解就是标注相当于一种标记,就像学生的胸卡,加上了注解就为程序打上了标记。
编译器,开发工具和其他程序来操作类和各种元素的时候可以根据注解做对应的处理。
JDK的内置注解:
JDK中内置了三个注解分别为:@Override、@Depressed和@SuppressWarnings。
@Override:主要用于子类在覆盖父类方法时,检测方法时候正确,如果是覆盖父类方法,没有提示,否则编译器会报错。
@Depressed:主要使用在:程序在更新升级的时候出现新方法替代了老方法,如果去掉老方法的话调用老方法的类会报错,为了兼容以前的类,同时要提醒新设计的类不建议使用老方法,这时就在老方法上加上@Depressed注解。
@SuppressWarnings:压缩警告,主要用于屏蔽警告,比如已经过时的警告。
@SuppressWarnings的取值如下:
deprecation,使用了过时的类或方法时的警告
unchecked,执行了未检查的转换时的警告
fallthrough,当 Switch 程序块直接通往下一种情况而没有 Break 时的警告
path,在类路径、源文件路径等中有不存在的路径时的警告
serial,当在可序列化的类上缺少serialVersionUID 定义时的警告
finally ,任何 finally 子句不能正常完成时的警告
all,关于以上所有情况的警告
注解的反射:
Class类中的方法isAnnotationPresent(Class<?
可通过getAnnotation(Class<?
元注解:元注解是在注解内部中使用的注解
@Retention
@Retention存活三个时期:
1.RetetionPolicy.SOURCE(源文件)
2.RetetionPolicy.CLASS(class文件)
3.RetetionPolicy.RUNTIME(内存中的字节码)
@Target用于标明标记可以加在的成分上(包,类,枚举,注解,接口,字段,方法,构造方法、方法的参数上和局部变量上)
注解属性:
结合代码和注释来说明注解属性
自定义注解类:
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,ElementType.TYPE})//注解可以加在方法上和类型上
public @interface ItcastAnnotation {
String color() default "blue";//default设置缺省值
String value();//如果只有一个value属性需要设置,value=可以省略
int[] arrayAttr() default {1,2,3};//数组类型的属性
TrafficLamp lamp() default TrafficLamp.RED;
MateAnnotation annotationAttr() default @MateAnnotation("lhm");
}
应用了注解的类,和主函数中对注解进行反射的类:
@ItcastAnnotation(color="red",value="abc",arrayAttr={3,4,5},annotationAttr=@MateAnnotation("flx"))
public class AnnotationDemo {
@ItcastAnnotation("ab")//如果注解中有一个名称为value的属性,且只想设置value属性,可以省略value=部分。
public static void main(String[] args) {
if(AnnotationDemo.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation = AnnotationDemo.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color());//red
System.out.println(annotation.value());//abc
System.out.println(annotation.arrayAttr().length);//3
System.out.println(annotation.lamp().nextLamp().name());//GREEN
System.out.println(annotation.annotationAttr().value());//flx
}
}
}
代码中用到的枚举
public enum TrafficLamp {
RED(){
@Override
public TrafficLamp nextLamp() {
return GREEN ;
}
},
GREEN{
@Override
public TrafficLamp nextLamp() {
return YELLOW;
}
},
YELLOW{
@Override
public TrafficLamp nextLamp() {
return RED;
}
};
public abstract TrafficLamp nextLamp();
}
----------- android培训 、 java培训 、java学习型技术博客、期待与您交流! ------------