A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© ApePlanet 中级黑马   /  2017-4-5 23:50  /  1088 人查看  /  2 人回复  /   3 人收藏 转载请遵从CC协议 禁止商业使用本文

反射:reflection

JAVA提供了一种反射机制,反射也称为反省。
java程序运行以后内存中就是一堆对象,除了对象什么都没有。
找对象
拉关系
瞎折腾

对象在运行过程中能否有一种机制查看自身的状态,属性和行为。这就是反射机制。
每一个运行中的类,都会有一个class对象,表示这个类的类对象。

获取class对象的方法:
1.引用名.getClass()
2.类名.getClass()
3.Class.forName()

//方法一 引用.getClass()

People p=new People();
System.out.println(p.getClass().getName()); //包括包名
System.out.println(p.getClass().getSimpleName());//不包括包名

//方法二 类名.getClass()
Class<People> cla=People.class;
System.out.println(cla.getName());
System.out.println(cla.getSimpleName());

//方法三
try {
Class<People> claa=(Class<People>)Class.forName("com.java.reflection.People");
System.out.println(claa.getName());
System.out.println(claa.getSimpleName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

Java已经为我们提供了这样一个类:java.lang.Class,我们无需自己定义Class类,通过Class对象我们可以得到:
类继承自哪个类
实现了哪些接口
有哪些属性
有哪些方法
有哪些构造方法

getName(): 获得类的名称,包括包名
getSimpleName(): 获得类的名称,不包括包名
getSuperClass(): 获得本类的父类的class对象
getInterfaces():获得本类所实现的所有接口的class对象

class对象的作用:
public Method[] getDeclaredMethods() throws SecurityException
取得所有当前类声明的方法,包括public,protected,默认,private四种访问权限的方法,但是不包括继承的方法
public Method[] getMethods() throws SecurityException
取得所有public的方法,包括继承的,接口中声明的和自己定义的

获得所有的公开方法:
Class<Student> clazStudent = Student.class;

Method[] publicMethods = clazStudent.getMethods();
System.out.println("===========所有public方法===========");
for (Method method : publicMethods) {
System.out.println(method.getName());
}

获得所以的本类中定义的方法:
Class<Student> c = Student.class;

Method[] declaredMethods = c.getDeclaredMethods();
System.out.println("===========所有当前的类自己定义的方法===========");
for (Method m : declaredMethods) {
System.out.println(m.getName());
}

Field[] getDeclaredFields()
取得所有当前类自己定义的属性,包括四种访问权限的
Field[] getFields()
取得所有public的属性,包括继承的,接口中声明的和自己定义的

获得所以的公开属性:
Class<Student> c = Student.class;

Field[] publicMethods = c.getFields();
System.out.println("============所有public属性============");
for (Field field : publicMethods) {
System.out.println(field.getName());
}

获得本类中定义的属性:
Class<Student> clazStudent = Student.class;
Field[] declaredFields = clazStudent.getDeclaredFields();
System.out.println("==========获取当前类自己定义的属性==========");
for (Field field : declaredFields) {
System.out.println(field.getName());
}

java.lang.reflect.Field类
通过Class对象的如下方法可以获得Field对象
Field getDeclaredField(String name)
Field getField(String name)
Field[] getDeclaredFields()
Field[] getFields()

每个Java程序执行前都必须经过编译、加载、连接、和初始化这几个阶段
加载:查找并加载类的二进制数据
连接:1.验证:确保被加载的类的正确性
2.准备:为类的静态变量分配内存,并将其初始化为默认值
3.解析:把类中的符号引用转换为直接引用
初始化:为类的静态变量赋予正确的初始值

i、加载是指将编译后的java类文件(也就是.class文件)中的二进制数据读入内存,并将其放在
运行时数据区的方法区内,然后再堆区创建一个Java.lang.Class对象,用来封装类在方法区的数据结构。
即加载后最终得到的是Class对象,并且更加值得注意的是:该Java.lang.Class对象是单实例的,
无论这个类创建了多少个对象,他的Class对象是唯一的!!!!。
而 加载并获取该Class对象可以通过三种途径:
Class.forName(类的全路径)、实例对象.class(属性)、实例对象getClass()。

在连接和初始化阶段,其实静态变量经过了两次赋值:
第一次是静态变量类型的默认值;
第二次是我们真正赋给静态变量的值。
Java对类的使用分为两种方式:主动使用和被动使用
主动使用:
1.创建类的实例
2.访问某个类或接口的静态变量,或者对该静态变量赋值
3.调用类的静态方法
4.反射:Class.forName("com.java.reflection.Person"),即:Class.forName("包名.类名")
5.初始化一个类的子类
6.Java虚拟机启东市被标明为启动类的类
而类的初始化时机正是java程序对类的首次主动使用,除了以上6中方式,
其他对类的使用都是被动使用,都不会导致类的初始化。 并且应该注意以下几个方面:
调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化

当Java虚拟机初始化一个类时,要求它的所有父类都已经被初始化,但是这条规则并不适用于接口。
在初始化一个类时,并不会先初始化它所实现的接口。
在初始化一个接口时,并不会先初始化它的父接口。
因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的
静态变量时,才会导致该接口的初始化。
接口的两重性:可以把接口当做类(因为在接口中有静态变量时,他可以被初始化);
接口就是接口,和类无关(接口中 没有构造方法,所以不能被初始化)

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是
使用Class对象的newInstance()方法的时候,就必须保证:1、这个类已经加载;
2、这个类已经连接了。而完成上面两个步骤的正是Class的静态方法forName()所完成的,
这个静态方法调用了启动类加载器,即加载 java API的那个加载器。

现在可以看出,Class对象的newInstance()(这种用法和Java中的工厂模式有着异曲同工之妙)
实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。
这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,
提供给了一种降耦的手段。

最后用最简单的描述来区分new关键字和newInstance()方法的区别:
newInstance: 弱类型。低效率。只能调用无参构造。
new: 强类型。相对高效。能调用任何public构造。

使用反射的好处:
1.创建的对象不用new
2.可以动态创建对象(把要创建的对象的类型写在配置文件中,每次程序启动读取配置文件,再自动创建对象)


来自宇宙超级黑马专属苹果客户端来自宇宙超级黑马专属苹果客户端

2 个回复

倒序浏览
回复 使用道具 举报
虽然现在看不懂,但还是收藏吧,估计以后用得着
来自宇宙超级黑马专属苹果客户端来自宇宙超级黑马专属苹果客户端
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马