反射是框架设计的灵魂。
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))
把类的字节码文件加载到JVM的内存中,并且生成一个Class类型的对象,ClassLoader加载的
- 验证:字节码文件格式是否正确
- 准备:为类变量(静态)分配空间,并且默认初始化
- 解析:把符号引用替换(转换)为直接引用(指针:指向某个内存地址)
为类进行声明处和静态块处初始化(静态块在加载类时就加载了,不需要创建对象)
当虚拟机java命令运行启动类
- 当一个类被主动使用时:
- 当创建某个类的新实例时
- 当调用某个类的静态成员;
- 当初始化某个子类时,该子类的所有父类都会被初始化。
- 当使用反射方法强制创建某个类或接口的对象时
- 当虚拟机java命令运行启动类
- 注意:static final 类型的不能导致初始化的情况
/**类初始化示例*/
class Demo{
static int sn = 44;
//在编译期 sa的值 能确定,不会引起类的 初始化
// static final int sa = 54;
//在编译期 sa的值不能确定 ,会引起类的初始化
static final int sa = 54 + sn;
static {
System.out.println("static_demo");
}
}
class SubDemo extends Demo{
}
public class TestDemo {
/* static int sn = 34;
static{
sn = 66;
System.out.println("静态块"+sn);
}*/
public static void main(String[] args) throws Exception {
System.out.println(Demo.sa);
//当创建某个类的新实例时
// Demo d = new Demo();
//当调用某个类的静态成员;
// System.out.println(Demo.sa);
//当初始化某个子类时,该子类的所有父类都会被初始化。
// SubDemo subdemo = new SubDemo();//子类对象
//当使用反射方法强制创建某个类或接口的对象时
// Demo.class.newInstance();
}
}
Student.class系统类加载器加载
1. 查找此类是否已经加载过,已经加载过,则返回Class对象
package day26;
/**
* 自己写类加载器
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
class MyClassLoader1 extends ClassLoader{
//自己要加载的路径
String path;
MyClassLoader1(String path){
this.path = path;
}
@Override
protected Class findClass(String name) throws ClassNotFoundException {
Class c = null;
//用流把Hello.class文件都出来 d:/data/Hello.class
//路径path = d:/data/ + Hello.class
path = path + name.replace(".", "/").concat(".class");
File f = new File(path);
FileInputStream fin = null;
try {
fin = new FileInputStream(f);
byte [] b = new byte [fin.available()];
int len = fin.read(b);
//解析成方法取数据结构
c = this.defineClass(name, b, 0, len);
} catch ( IOException e) {
e.printStackTrace();
}finally{
if(fin != null){
try {
fin.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return c;
}
}
public class MyClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
//创建一个自定义类加载器 d:/data/ hello.class
MyClassLoader1 mc = new MyClassLoader1("d:/data/");
Class c = Class.forName("Hello",true,mc);
System.out.println(c.getClassLoader());
}
}
/**加载器示例*/
class Exam{
static{
System.out.println(10);
}
}
public class TestClassLoader {
public static void main(String[] args) throws ClassNotFoundException {
// 查看所有的类加载器
// ClassLoader c = Exam.class.getClassLoader();
// //sun.misc.Launcher$AppClassLoader@73d16e93 系统类加载器(应用类加载器)
// System.out.println(c);
// //sun.misc.Launcher$ExtClassLoader@15db9742 扩展类加载器
// System.out.println(c.getParent());
// //null:不是java写的,不能展示 根类加载器
// System.out.println(c.getParent().getParent());
//怎么加载?
//方法1
//获得系统类加载器
//可以加载类,但不能引起类的初始化 javac Exam.java 加载类:java Exam
ClassLoader.getSystemClassLoader().loadClass("day26.Exam");
//方法2 加载并且初始化 true进行初始化 指定初始化
Class.forName("day26.Exam",true,ClassLoader.getSystemClassLoader());
Class.forName("day26.Exam");
}
}
从 方法区的字节码中动态的获得类中的信息
属性:getDeclaredFields()获得所有属性、getName()获得名字、getType()获得类型、getModifiers()获得访问修饰符、get()给属性赋值、set()获得属性值
方法:getDeclaredMethods()获得所有方法、getName()获得名字、getReturnType()获得返回类型、getParameterTypes()
构造器:getDeclaredConstructors()获得所有构造器、newInstance() 调用构造器
注解:getAnnotations()、getDeclaredField()、(注解的反射见后一部分注解详解)
/**反射示例代码*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
class Student{
private int no;
private String name;
public Student(int no, String name) {
super();
this.no = no;
this.name = name;
System.out.println("带参构造" + no + name);
}
public Student() {
super();
System.out.println("无参构造器" );
}
public void show(){
System.out.println("show");
}
public String f (String s ,int n){
return "连接" + s + n;
}
}
public class TestStudent {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
//获得Student.class 对应的对象
//方法一:
Class c = Class.forName("day26.Student");
//方法二:
//Class c = Student.class;
//方法三:/
//Class c = new Student().getClass();
//没有源码,要获得属性:
System.out.println("----------属性-----------");
//获得所有属性,不包括私有的
//Field [] fs = c.getFields();
//获得所有属性,包括私有的
Field [] fs = c.getDeclaredFields();
for(Field f : fs){
System.out.println(f.getName());
System.out.println(f.getType());
System.out.println(Modifier.toString(f.getModifiers()));
}
//访问对属性赋值
Field f = c.getDeclaredField("no");
//设置安全管理器 对安全进行管理,就不能访问
//System.setSecurityManager(new SecurityManager());
f.setAccessible(true);//设置访问权限
Object obj = c.newInstance();//创建实例对象
f.set(obj, 22);//给属性赋值
System.out.println(f.get(obj));//访问属性值
//访问方法:
System.out.println("----------方法-----------");
Method [] ms = c.getDeclaredMethods();
for(Method m : ms){
System.out.println(m.getName());
System.out.println(m.getReturnType());//返回值类型
System.out.println(Arrays.toString(m.getParameterTypes()));//数组返回所有参数
}
//调用方法
Method m1 = c.getDeclaredMethod("f", String.class,int.class);
System.out.println(m1.invoke(obj, "abc",111));
Method m2 = c.getDeclaredMethod("show");
m2.invoke(obj);
System.out.println("----------构造器-----------");
Constructor [] crs = c.getDeclaredConstructors();//所有构造器
for(Constructor cr : crs){
System.out.println(Arrays.toString(cr.getParameterTypes()));//参数类型
}
//调用构造器
Constructor cr1 = c.getDeclaredConstructor(int.class,String.class);
cr1.newInstance(21,"张三");
Constructor cr2 = c.getDeclaredConstructor();
cr2.newInstance();
}
}
从JDK5开始,Java增加了对元数据(MetaData)的支持, 就是注解Annotation;注解是指代码里的特殊标记,这些标记可以 在编译、类加载、运行时被读取,并执行相应的处理。
/**常用注解*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
@FunctionalInterface
interface Info{
void af();
}
class Base{
public void s(){}
}
class Sub extends Base{
@Override
public void s() {
// TODO Auto-generated method stub
super.s();
}
}
//版本号
@SuppressWarnings("serial")
class Demo12 implements Serializable{
}
class Demo11{
//此方法已过期,已过时
@Deprecated
public void ss(){}
//没有进行 类型检查
@SuppressWarnings("unchecked")
public void sf(){
//镇压警告:原生类型,变量声明了没有使用
@SuppressWarnings({"rawtypes","unused"})
List list = new ArrayList();
list.add(33);
}
}
public class TestAnno1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
@interface 注解名{
//成员变量,类型参数
public 类型 成员名()
public 类型 名 default 默认值;
……
}
/**自定义注解 */
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
@Target(ElementType.TYPE)//范围;此注解一定要写
@Retention(RetentionPolicy.RUNTIME)//设置生命周期;此注解一定要写
@Inherited()//子类可以继承类,类型声明时的注解;此注解可写可不写
@Documented//在生成了javadoc命令的API文档中是否显示注解信息,加上就是显示;此注解可写可不写
@interface FruitAnno{
public String value() default "apple";
}
@Target(ElementType.FIELD) //用的范围时属性
@Retention(RetentionPolicy.RUNTIME)//声明周期在反射时能用
@interface ColorAnno{
public Color color() default Color.RED;
}
@FruitAnno(value = "apple水果类")
class Fruit{
private String name;
private int size;
}
class Apple extends Fruit{
@ColorAnno(color = Color.GREEN)
private Color colorname;
}
enum Color{
RED,GREEN,YELLO;
}
public class TestAnno2 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
//获得字节码对应的Class对象
//父类的
Class cf = Fruit.class;
Annotation [] ans = cf.getDeclaredAnnotations();
Arrays.stream(ans).forEach(System.out :: println);
//子类的
System.out.println("---------------------------------");
Class ca = Apple.class;
Annotation [] as = ca.getAnnotations(); //用反射获得继续的父类注解
Arrays.stream(as).forEach(System.out :: println);
//获得子类属性的注解
as = ca.getDeclaredField("colorname").getDeclaredAnnotations();//子属性的所有注解
Arrays.stream(as).forEach(System.out :: println);
}
}
/**自定义安全管理器*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
//自定义安全管理器
class MySecurity extends SecurityManager{
@Override
public void checkRead(String file) {
if(file.endsWith("txt")){
throw new SecurityException("不允许读取txt文件");
}
}
}
public class TestFileInputStream {
public static void main(String[] args) throws IOException {
File f = new File("d:/data/a.txt");
//设置权限
System.setSecurityManager(new MySecurity());
FileInputStream fin = new FileInputStream(f);
char c = (char)fin.read();
System.out.println(c);
fin.close();
}
}