反射,终极手段,规则的破坏者。
1.是JAVA API,是JAVA提供的现成的类!!
- 接收API提供的功能!
2.是Java提供的动态执行机制,动态加载类,动态创建对象,
动态访问属性,动态调用方法。
3.可以调用加载类中的私有方法,但是一般情况下不能访问方法中的参数名
(eclipse使用特殊的方式编译,使得编译出来的字节码文件可以访问参数名)
静态与动态
静态:事先约定的规则,执行期间按照固定规则执行。
动态:事先没有约定,在执行期间动态确定执行规则。
Java中的静态执行:编译已经就确定执行规则(执行次序),
在运行期间按照编译结果顺序执行。
Foo foo = new Foo();
foo.hello();
Java中的动态执行:运行期间才能确定加载哪些类,创建哪些
对象,执行哪些方法····
动态加载类
Java提供了动态加载类的API
Class cls = Class.forName(类名);
如:
Class cls = Class.forNmme("demo.foo");
动态创建对象
语法-->执行cls引用的类信息中的无参数构造器,动态创建实例,
如果类没有无参数构造器,则抛出异常!
-->提示:反射可以调用有参数构造器。
cls.newInstance();
Class
Class类,是类的描述符。
Modifier
修饰符,判断是否含有指定的修饰符的。
Modifier.isStatic(method.getModifier());
实例
package demo;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Demo1{
public static void main(String[] args) throws Exception {
Scanner in = new Scanner(System.in);
System.out.println("请输入类型:");
String className = in.nextLine();
* 动态加载类
Class cls = Class.forName(className);
System.out.println(cls);
* 动态创建对象
Object obj = cls.newInstance();
System.out.println(obj);
* 动态获取类的信息
* 从cls代表的类信息中获取全部的方法信息
Method[] ary = cls.getDeclaredMethods();
* 每一个Method代表一个方法的信息,方法的所有要素都在这个对象中
for(Method method:ary) {
System.out.println(method);
System.out.println("方法名:" + method.getName());
System.out.println("返回值类型:" + method.getReturnType());
}
}
}
打印:
请输入类型:
demo.Foo
class demo.Foo
demo.Foo@3d24753a
public void demo.Foo.test1()
方法名:test1
返回值类型:void
public void demo.Foo.hello()
方法名:hello
返回值类型:void
执行所加载类的方法
method.invoke(执行方法的对象,传递的参数)
必须在对象上执行一个非静态方法,调用方法时候必须有对象。
在invoke方法执行时候,必须传递包含当前方法的对象!!!
使用invoke
Object obj = method.invoke(对象,参数1,参数2)
invoke方法有返回值,返回被调用方法执行的结果,对象后面参数是执行方法时候传递的参数。
invoke可以调用私有方法
invoke执行方法例子
package demo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Demo2 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
Scanner scan = new Scanner(System.in);
System.out.println("请输入类名:");
Class cls = Class.forName(scan.nextLine());
Method[] methods = cls.getDeclaredMethods();
for(Method method : methods) {
if(method.getName().startsWith("test")) { --筛选方法名以test开头的
System.out.println("调用方法:" + method);
method.invoke(cls.newInstance()); -- 要传入所调用方法的对象
}
}
}
}
打印:
请输入类名:
demo.Foo
调用方法:public void demo.Foo.test2()
test2()
调用方法:public void demo.Foo.test1()
test1()
invoke调用私有方法
package demo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Demo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
Scanner scan = new Scanner(System.in);
System.out.print("请输入类名:");
Class cls = Class.forName(scan.nextLine());
* 1.找到demo方法
* Class 提供了根据方法签名找到指定方法信息的API
String name = "demo";
* 类型列表 Class[]
* String.class 表示字符串类型
* int.class 表示int类型
* 任何.class 表示任何的类型
Class[] types = {String.class, int.class};
* 根据方法签名在cls查找方法信息
Method method = cls.getDeclaredMethod(name, types);
System.out.println(method);
* 打开方法的执行权限!!!违反封装
method.setAccessible(true);
Object obj = method.invoke(cls.newInstance(), "libai", 22);
System.out.println(obj);
}
}
反射调用Person类中特定的构造方法来创建对象,要用构造函数的传参类型来指定
@Test
public void test2() throws Exception {
Class<Person> clazz = Person.class;
System.out.println(clazz);
System.out.println(clazz.getName());
System.out.println(clazz.getSimpleName());
//通过反射创建对象
Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class, int.class);
Person p = constructor.newInstance("libai", 22); 调用Person类中特定的构造方法来创建对象
System.out.println(p);
Method[] methods = clazz.getMethods();
for(Method method : methods) {
System.out.println(method);
}
}
得到方法的修饰符总和,来确定该方法的类型
@Test
public void test6() throws Exception {
Class<Person> clazz = Person.class;
Method method = clazz.getDeclaredMethod("setName", String.class);
* 得到方法的修饰符总和
int modifier = method.getModifiers();
System.out.println(modifier);
System.out.println(Modifier.isStatic(modifier));
System.out.println(Modifier.isPublic(modifier));
System.out.println(Modifier.isPrivate(modifier));
}
打印结果:
1
false
true
false
得到指定包下所有的类
* 得到指定包下所有的类
@Test
public void test7() throws Exception{
Class clazz = Person.class;
ClassLoader loader = clazz.getClassLoader();
Enumeration<URL> dir = loader.getResources("myreflect");
while(dir.hasMoreElements()) {
URL url = dir.nextElement();
System.out.println(url.getPath());
File file = new File(url.toURI());
File[] files = file.listFiles();
System.out.println("该路径下的所有类:");
for(File f : files) {
if(!f.getName().endsWith(".class")) {
continue;
}
System.out.println(f.getPath() + ",类名称:" + f.getName());
System.out.println(Class.forName("myreflect." + f.getName().substring(0, f.getName().lastIndexOf("."))));
}
}
System.out.println("over");
}
用反射来获取资源
* 搜索类路径来获取资源
@Test
public void test6() throws Exception {
ClassLoader loader = ClassLoader.getSystemClassLoader();
InputStream in = loader.getResourceAsStream("myreflect/demo.jpg");
}
* 得到java包的资源流
@Test
public void test7() throws Exception {
InputStream in = ClassLoader.getSystemResourceAsStream("java/lang/String.class");
System.out.println(in.available());
in.close();
}
注解反射原型
下面这个是定义的注解
package demo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Demo {
}
使用注解
package demo;
* 执行一个类中全部以@Demo标注的方法
public class TestCase {
@Demo
public void hello() {
System.out.println("hello");
}
@Demo
public void helloTom() {
System.out.println("helloTom");
}
public void boring() {
System.out.println("boring");
}
}
执行上面含有注解的方法
package demo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;
* 动态执行一个类中全部以@Demo注解标注的方法
public class Demo4 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
Scanner scan = new Scanner(System.in);
System.out.println("请输入类名:");
Class cls = Class.forName(scan.nextLine());
Method[] methods = cls.getDeclaredMethods();
Object instance = cls.newInstance();
for(Method method : methods) {
* 检查一个方法的注解信息
* method.getAnnotation(被检查的注解类型)
* 返回注解类型对象,如果为空表示没有注解,不为空表示找到了被检查的注解
Demo ann = method.getAnnotation(Demo.class);
if(ann != null) {
System.out.println(method + ", " + ann);
method.invoke(instance);
}
}
}
spring注解原型
首先在resource文件夹中创建一个demo-beans.xml文件,模拟spring的xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="foo" class="demo.Foo"></bean>
<bean id="date" class="java.util.Date"></bean>
<bean id="boo" class="demo.Boo"></bean>
<bean id="testCase" class="demo.TestCase"></bean>
<bean id="hashMap" class="java.util.HashMap"></bean>
</beans>
DemoApplicationContext文件,读取上面的xml文件,取到其中的id和class对应的值
package demo;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class DemoApplicationContext {
* 缓存spring容器的Bean对象
Map<String, Object> beans = new HashMap<String, Object>();
* 利用配置文件初始化当前容器
* 利用xml配置文件,初始化全部的Bean对象
* Dom4j,读取xml文件,解析xml文件内容,得到Bean的类名和ID
* 根据类名动态加载并且创建对象,将对象和对应的ID添加到map中
public DemoApplicationContext(String xml) throws Exception {
SAXReader reader = new SAXReader();
Document doc = null;
* 从Resource(classpath)中读取流
InputStream in = getClass().getClassLoader().getResourceAsStream(xml);
doc = reader.read(in);
in.close();
Element root = doc.getRootElement();
List<Element> elements = root.elements("bean");
for(Element element : elements) {
String id = element.attributeValue("id");
String className = element.attributeValue("class");
Class cls = Class.forName(className);
Object bean = cls.newInstance();
beans.put(id, bean);
}
}
* 根据id在map查找对象,并返回对象
public Object getBean(String id) {
return beans.get(id);
}
* 泛型方法:优点是可以减少一次类型转换
public <T> T getBean(String id, Class<T> cls) {
return (T)beans.get(id);
}
}
调用上面的DemoApplicationContext来动态获取对象
package demo;
public class Demo6 {
public static void main(String[] args) throws Exception {
DemoApplicationContext ac = new DemoApplicationContext("demo-beans.xml");
Foo foo = ac.getBean("foo", Foo.class);
foo.hello();
System.out.println(foo);
}
}
打印:--调用成功
hello()
demo.Foo@4f063c0a
反射用途
1. eclipse中解析类的结构使用了反射
2. JUnit识别被测试方法使用了反射
- JUnit3利用反射查找test开头的方法
- JUnit4利用反射解析@Test查找测试方法
3. Spring管理Bean对象,注入Bean属性使用了反射
- 利用反射创建Bean对象实例
- 利用 反射注入Bean的属性
4. 注解的解析使用了反射
- 利用反射API支持注解
5. 强行执行私有方法(访问私有属性)
动态代理
它的作用就是不必修改本来就已经存在的类,用反射调用的方式在调用类或对象的方法之前或之后对代码添加一些操作进行处理。
例子如下,首先预先定义两个接口,分别是PersonDao1和PersonDao2,下面的Person只是一个空类
package myproxy;
import myreflect.Person;
public interface PersonDao1 {
public String insert(Person p);
public void update(Person p);
}
interface PersonDao2{
public void insert2(Person p);
public void update2(Person p);
}
PersonDaoImpl实现上面的两个接口
package myproxy;
import myreflect.Person;
public class PersonDaoImpl implements PersonDao1,PersonDao2{
@Override
public String insert(Person p) {
System.out.println("my insert function");
return "libai";
}
@Override
public void update(Person p) {
System.out.println("my update function");
}
@Override
public void insert2(Person p) {
System.out.println("my insert2 function");
}
@Override
public void update2(Person p) {
System.out.println("my update2 function");
}
}
构建一个InvocationHandler来对PerSonDaoImpl的调用进行处理,添加上所需要的处理代码
package myproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler{
* 目标对象
private Object target;
* 传入目标对象
public MyInvocationHandler(PersonDao1 target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
* 运行前添加的处理代码
System.out.println("hello world!!!");
Object res = method.invoke(target, args);
* 运行后添加的处理代码
System.out.println("over");
return res;
}
}
最终的调用入口则如下
package myproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import myreflect.Person;
public class App {
public static void main(String[] args) {
* 得到系统ClassLoader
ClassLoader loader = ClassLoader.getSystemClassLoader();
* 接口数组
Class[] clazzs = {PersonDao1.class, PersonDao2.class};
* 目标对象
PersonDao1 dao = new PersonDaoImpl();
* 处理器
InvocationHandler handler = new MyInvocationHandler(dao);
* 动态创建Proxy对象
Object proxy = Proxy.newProxyInstance(loader, clazzs, handler);
String str = ((PersonDao1)proxy).insert(new Person());
System.out.println("back:" + str);
((PersonDao2)proxy).insert2(new Person());
}
}
打印结果:
hello world!!!
my insert function
over
back:libai
hello world!!!
my insert2 function
over
Java的设计模式
设计模式:
1.单例模式
* 饿汉式--线程安全
class GarbageBox {
private static GarbageBox instance = new GarbageBox();
public static GarbageBox getInstance() {
return instance;
}
}
* 懒汉式--线程安全
class GarbageBoxLazy {
private static GarbageBoxLazy instance;
public static GarbageBoxLazy getInstance() {
if(instance == null) {
synchronized (GarbageBoxLazy.class) {
if(instance == null) {
instance = new GarbageBoxLazy();
}
}
}
return instance;
}
}
2.工厂模式
TvFactory{
public static Tv productTV(){
TV tv = new TV();
tv.setxxx(...);
...
return tv;
}
}
}
3.适配器
4.装饰模式
class MyConnectionWrapper extends Connection{
private Connection conn;
public MyConnectionWrapper(Connection conn){
this.conn = conn;
}
public void close(){
...
conn.xxx();
...
}
}
5.池化模式
6.builder模式
new Person().setName("libai").setAge(23);
7.适配器
7.代理模式
动态代理
JVM内存划分

JVM
Runtime data area,运行时数据区
1.method are
在所有线程间共享
2.heap
在所有线程间共享
3.java stack
不共享
每个线程对应一个stack,线程栈 == 方法栈
跳转栈空间:java -Xss1m
OOM:out of memory,内存溢出
4.native method stack
不共享
5.program counter register
不共享
6.通过jvisualvn查看jvm结构
OOP
OOP: oriented object program编程
OOA: oriented object analyze分析
OOD: oriented object design设计
OOP特点:封装、继承、多态
网友评论