您的位置:首页 > 其它

反射

2015-10-31 13:31 381 查看
反射(类的加载概述和加载时机)

* A:类的加载概述

* 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

* 加载

* 就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。

* 连接

* 验证 是否有正确的内部结构,并和其他类协调一致

* 准备 负责为类的静态成员分配内存,并设置默认初始化值

* 解析 将类的二进制数据中的符号引用替换为直接引用

* 初始化 就是我们以前讲过的初始化步骤

* B:加载时机

* 创建类的实例

* 访问类的静态变量,或者为静态变量赋值

* 调用类的静态方法

* 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

* 初始化某个类的子类

* 直接使用java.exe命令来运行某个主类

_反射(类加载器的概述和分类)

* A:类加载器的概述
* 负责将.class文件加载到内存中,并为之生成对应的Class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
* B:类加载器的分类
* Bootstrap ClassLoader 根类加载器
* Extension ClassLoader 扩展类加载器
* Sysetm ClassLoader 系统类加载器
* C:类加载器的作用
* Bootstrap ClassLoader 根类加载器
* 也被称为引导类加载器,负责Java核心类的加载
* 比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
* Extension ClassLoader 扩展类加载器
* 负责JRE的扩展目录中jar包的加载。
* 在JDK中JRE的lib目录下ext目录
* Sysetm ClassLoader 系统类加载器
* 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

* A:反射概述
* JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
* 对于任意一个对象,都能够调用它的任意一个方法和属性;
* 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
* 要想解剖一个类,必须先要获取到该类的字节码文件对象。
* 而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

* B:三种方式
* a:Object类的getClass()方法,判断两个对象是否是同一个字节码文件
* b:静态属性class,锁对象
* c:Class类中静态方法forName(),读取配置文件
实体类:
package com.bean;


public
class Person
{

private
String name;

private
int age;

public
Person()
{

super();


}

public
Person(String name,
int age)
{

super();

this.name
= name;

this.age
= age;

}

public
String getName()
{

return name;

}

public
void setName(String name)
{

this.name
= name;

}

public
int getAge()
{

return age;

}

public
void setAge(int age)
{

this.age
= age;

}

@Override

public
int hashCode()
{

final
int prime =
31;

int result
= 1;

result
= prime * result
+ age;

result
= prime * result
+ ((name
== null)
? 0
: name.hashCode());

return result;

}

@Override

public
boolean equals(Object obj)
{

if
(this
== obj)

return
true;

if
(obj ==
null)

return
false;

if
(this.getClass()
!= obj.getClass())
//判断调用对象和传入对象的字节码文件是否是同一个字节码文件

return
false;

Person other
= (Person) obj;

if
(age != other.age)

return
false;

if
(name ==
null)
{

if
(other.name
!= null)

return
false;

}
else if
(!name.equals(other.name))

return
false;

return
true;

}

@Override

public
String toString()
{

return
"Person [name=" + name
+ ", age="
+ age +
"]";

}



public
void eat()
{
System.out.println("今天吃了一锅饺子");

}



}

测试类:




import com.bean.Person;


public
class Demo1_Reflect
{


/**

* @param args

* @throws ClassNotFoundException

*/

public
static void main(String[] args)
throws ClassNotFoundException
{

Class clazz1
= Class.forName("com.heima.bean.Person");

Class clazz2
= Person.class;


Person p
= new
Person();

Class clazz3
= p.getClass();


System.out.println(clazz1
== clazz2);

System.out.println(clazz2
== clazz3);

}


}

反射(通过反射获取带参构造方法并使用)

* Constructor
* Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance("君威",20)方法创建对象
编写程序:

package com.heima.reflect;


import java.lang.reflect.Constructor;


import com.heima.bean.Person;


public
class Demo3_Constructor
{


public
static void main(String[] args)
throws Exception
{

Class clazz
= Class.forName("com.heima.bean.Person");

//Person p = (Person) clazz.newInstance(); 通过无参构造创建对象

//System.out.println(p);

Constructor c
= clazz.getConstructor(String.class,int.class);
//获取有参构造

Person p
= (Person) c.newInstance("君威",23);
//通过有参构造创建对象

System.out.println(p);

}


}

反射(通过反射获取成员变量并使用)


* Field
* Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值


import java.lang.reflect.Constructor;

import java.lang.reflect.Field;


import com.bean.Person;


public
class Demo4_Field
{



public
static void main(String[] args)
throws Exception
{

Class clazz
= Class.forName("com.bean.Person");

Constructor c
= clazz.getConstructor(String.class,int.class);
//获取有参构造

Person p
= (Person) c.newInstance("张三",23);
//通过有参构造创建对象


//因为name属性为私有的,用下面注释掉的代码无法获取

//Field f = clazz.getField("name"); //获取姓名字段

//f.set(p, "君威"); //修改姓名的值

Field f
= clazz.getDeclaredField("name");
//暴力反射获取字段

f.setAccessible(true);
//去除私有权限

f.set(p,
"君威");


System.out.println(p);

}


}

反射(通过反射获取方法并使用)


* Method
* Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,调用invoke(Object, Object...)可以调用该方法,Class.getMethod("eat") invoke(obj) Class.getMethod("eat",int.class) invoke(obj,10)


import java.lang.reflect.Constructor;

import java.lang.reflect.Method;


import com.bean.Person;


public
class Demo5_Method
{



public
static void main(String[] args)
throws Exception
{

Class clazz
= Class.forName("com.bean.Person");

Constructor c
= clazz.getConstructor(String.class,int.class);
//获取有参构造

Person p
= (Person) c.newInstance("君威",23);
//通过有参构造创建对象


Method m
= clazz.getMethod("eat");
//获取eat方法

m.invoke(p);


Method m2
= clazz.getMethod("eat",
int.class);
//获取有参的eat方法

m2.invoke(p,
10);

}


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: