动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构
主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang
反射
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构。
这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射
四种方法获取Class类的实例:
//导入的包有:import org.junit.Test;
public class ReflectionTest1 {
@Test
public void test1() throws ClassNotFoundException {
//方式一:调用运行时类的属性:.class
Class clazz1 = String.class;
System.out.println(clazz1);//class java.lang.String
//方式二:通过运行时类的对象,调用getClass()
String s1 = new String();
Class clazz2 = s1.getClass();
System.out.println(clazz2);//class java.lang.String
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3);//class java.lang.String
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
//方式四:使用类的加载器:ClassLoader (了解)
ClassLoader classLoader = ReflectionTest1.class.getClassLoader();
Class clazz4 = classLoader.loadClass("java.lang.String");
System.out.println(clazz4);//class java.lang.String
System.out.println(clazz1 == clazz4);//true
}
}
除了类以外,接口、数组、枚举、注解基本数据类型、void也可以作为Class类的实例
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化
类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
JVM 规范定义了如下类型的类的加载器:
//导入的包有:import org.junit.Test;
public class ClassLoaderTest {
@Test
public void test1(){
//对于自定义类:使用系统类加载器进行加载
ClassLoader classLoader1 = ClassLoaderTest.class.getClassLoader();
//调用系统加载器的getParent():获取扩展类加载器
System.out.println(classLoader1);//sun.misc.Launcher$AppClassLoader@18b4aac2
ClassLoader classLoader2 = classLoader1.getParent();
//调用扩展类加载器的getParent():无法获取引导类加载器
//引导类加载器主要负责加载Java的核心类库,无法加载自定义类
System.out.println(classLoader2);//sun.misc.Launcher$ExtClassLoader@a09ee92
ClassLoader classLoader3 = classLoader2.getParent();
System.out.println(classLoader3);//null
}
}
通过反射,创建运行时类的对象
//导入的包有:import org.junit.Test;
public class ClassLoaderTest {
@Test
public void test2() throws IllegalAccessException, InstantiationException {
Class<String> clazz = String.class;
/*
* newInstance():调用此方法,创建对应的运行时类的对象,其内部调用了运行时类的空参构造器
*
* 要想此方法正常的创建运行时类的对象,要求
* 1.运行时类必须提供空参的构造器
* 2.空参的构造器的访问权限足够,通常设置为public
*/
//由于创建Class类的对象时,规定了泛型,所以此处自动转换类型
String obj = clazz.newInstance();
System.out.println(obj);
}
}
当我们创建好Class对象后,可以获得其所有属性
//导入的包有:import org.junit.Test;import java.lang.reflect.Field;import java.lang.reflect.Modifier;
public class Test1 {
@Test
public void test1(){
Class clazz = String.class;
//获取属性结构
//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
for(Field f : fields){
System.out.println(f);
}
//getDeclaredFields():获取当前运行时类中声明的所有属性,不包含父类中声明的属性
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
System.out.println(f);
}
}
@Test
public void test2(){
Class clazz = String.class;
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
//1.获取权限修饰符
int modifier = f.getModifiers();
System.out.println(Modifier.toString(modifier));
//2.获取数据类型
Class type = f.getType();
System.out.println(type.getName());
//3.获取变量名
String fName = f.getName();
System.out.println(fName);
}
}
}
当我们创建好Class对象后,可以获得其所有方法
//导入的包有:import org.junit.Test;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;
public class Test1 {
@Test
public void test3(){
Class clazz = String.class;
//getMethods():获取当前运行时类一起所有父类中声明为public权限的方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
System.out.println(m);
}
//getDeclaredMethods():获取当前运行时类中声明的所有方法,不包含父类中声明的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){
System.out.println(m);
}
}
}
我们也可以获取方法的权限修饰符,返回值类型,方法名,参数,注解,异常,由于使用不多,这里不展开叙述
当我们创建好Class对象后,可以获得其构造器
//导入的包有:import org.junit.Test;import java.lang.reflect.Constructor;
public class Test1 {
@Test
public void test4(){
//getConstructors():获取当前运行时类中声明为public的构造器
Class clazz = String.class;
Constructor[] constructors = clazz.getConstructors();
for(Constructor c : constructors){
System.out.println(c);
}
//getDeclaredConstructors():获取当前运行时类中声明的所有构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for(Constructor c : declaredConstructors){
System.out.println(c);
}
}
}
还可以获得运行时类的父类及其父类的泛型、接口、所在包、注解,这里不在一一演示
//导入的包有:import org.junit.Test;import java.lang.reflect.Field;
//现在假设有一Person类,具有一般类所具有的属性,方法,构造器
public class ReflectionTest2 {
@Test
public void test1() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//1.getDeclaredField(String name):获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//还有一种方式获取运行时类中的指定变量,但一般不使用,因为只能获得Public属性
//Field name = clazz.getFueld("name")
//2.保证当前属性时可访问的
name.setAccessible(true);
//3.获取、设置指定对象的此属性
name.set(p,"Tom");
//4.输出当前属性的值
System.out.println(name.get(p));
}
}
//导入的包有:import org.junit.Test;import java.lang.reflect.Method;
//现在假设有一Person类,具有一般类所具有的属性,方法,构造器
public class ReflectionTest2 {
@Test
public void test2() throws Exception {
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
/*
1.获取某个指定方法
getDeclaredMethod():参数1:指明获取方法的名称,参数2:指明获取的方法的形参列表
*/
Method show = clazz.getDeclaredMethod("show", String.class);
//2.保证当前方法是可访问的
show.setAccessible(true);
/*
3.调用方法的invoke():参数1:方法的调用者,参数2:给方法形参赋值的实参
invoke()的返回值即为对应类中调用的方法的返回值
若调用运行时类的静态方法,则传入的参数1为Person.class
*/
Object returnValue = show.invoke(p, "China");
}
}
还可以调用运行时类的指定构造器,但是用非常少,这里不再演示
代理设计模式的原理:
代理模式分为静态和动态:
interface ClothFactory{
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{
private ClothFactory factory;//用被代理对象进行实例化
public ProxyClothFactory(ClothFactory factory){
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做准备工作");
factory.produceCloth();
System.out.println("代理工厂做后续工作");
}
}
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void produceCloth() {
System.out.println("Nike工厂生产一批运动服");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
//创建被代理类的对象
NikeClothFactory nike = new NikeClothFactory();
//创建代理类的对象
ProxyClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
/*代理工厂做准备工作
Nike工厂生产一批运动服
代理工厂做后续工作*/