Java作为静态语言——>通过反射机制的引入,从而拥有了动态的存在
一类在运行时可以改变其结构的语言:例如函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化
通俗来讲就是在运行时代码可以根据某些条件改变自身结构
主要动态语言:Object-C、C#、JavaScript、PHP、Python等
与动态语言相对应的,运行时结构不可变的语言就是静态语言
例如:Java、C、C++
Java不是动态语言,但Java可以称之为“准动态语言”,即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性
Java的动态性让编程的时候更加灵活,但灵活的同时也会带来安全性的降低
Reflection(反射)是Java被视为动态语言的关建,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
Class c = Class.forNmae("java.lang.String")
加载完类以后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息,我们可以通过这个对象看到类的结构
这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称之为:反射
正常:引入需要的“包”——>new实例化——>获取实例化对象
反射:实例化对象——>getClass()方法——>得到完整的“包”名称
反射即是跟正常的反着来的
优点:
可以实现动态创建对象和编译,体现出很大的灵活性
缺点:
对性能有影响,使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求,这类操作总是慢于直接执行相同的操作
在Object类中定义了以下的方法,此方法将被所有子类继承
public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称
对象·照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口,对于每个类而言,JRE都为其保留了一个不变的Class类型的对象。一个Class对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息
public class TestReflect2 { public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("此人是“"+person.name); //方式1:通过对象获得 Class c1 = person.getClass(); System.out.println(c1.hashCode()); //方式2:forname获得 Class c2 = Class.forName("面试.Student"); System.out.println(c2.hashCode()); //方式3:通过类名.class获得 Class c3= Student.class; System.out.println(c3.hashCode()); //方式4:基本内置类型的包装类都有一个Type属性 Class c4 = Integer.TYPE; //获得父类类型 Class c5 = c1.getSuperclass(); System.out.println(c5); System.out.println(c5.hashCode()); } } class Person{ public String name; public Person() { } public Person(String name) { this.name = name; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } class Student extends Person{ public Student(){ this.name = "学生"; } } class Teacher extends Person{ public Teacher(){ this.name = "老师"; } }
可以有Class对象的类
import java.lang.annotation.ElementType; public class TestClass { public static void main(String[] args) { Class c1 = Object.class;//obj类 Class c2 = Comparable.class;//接口 Class c3 = String[].class;//一维数组 Class c4 = int[][].class;//二维数组 Class c5 = Override.class;//注解 Class c6 = ElementType.class;//枚举 Class c7 = Integer.class;//基本数据类型 Class c8 = void.class;//void Class c9 = Class.class;//class System.out.println(c1); System.out.println(c2); System.out.println(c3); System.out.println(c4); System.out.println(c5); System.out.println(c6); System.out.println(c7); System.out.println(c8); System.out.println(c9); } }
idea中,alt可以实现多行复制
int[] a= new int[10]; int[] b= new int[100]; System.out.println(a.getClass().hashCode()); System.out.println(b.getClass().hashCode());
只要元素类型和维度一样,则就是同一个Class
Java内存:
- 堆
- 栈
- 方法区
当长须主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对改类进行初始化
发生类初始化的时机
class Father{ static int b= 2; static{ System.out.println("父类被加载"); } } class Son extends Father{ static{ System.out.println("子类被加载"); m = 300; } static int m = 100; static final int M = 3; }
主动引用:Son son = new Son();//Main类被加载 父类被加载 子类被加载
反射的方式:Class.forName("面试.注解反射.Son");//Main类被加载 父类被加载 子类被加载
System.out.println(Son.b);//Main类被加载 父类被加载 2
Son[] arr = new Son[5];//Main类被加载
System.out.println(Son.M);//Main类被加载 3
类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象
类加载器作用是用来把类(class)装在进内存的。JVM规范定义了如下类型的类加载器
引导类加载器:用C++编写,是JVM自带的类加载其,负责Java平台核心库,用来装载核心类库。该加载器无法直接获取
扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库
系统类加载器:负责java -classpath 或 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器
public class Test2 { public static void main(String[] args) throws ClassNotFoundException { //获取系统类的加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println(systemClassLoader); //获取系统类加载器的父类加载器——>扩展类加载器 ClassLoader parent = systemClassLoader.getParent(); System.out.println(parent); //获取扩展类加载器的父类加载器——>根加载器 ClassLoader grandparent = parent.getParent(); System.out.println(grandparent); //测试当前类是那个加载器jiazaide ClassLoader classLoader = Class.forName("面试.注解反射.Test2").getClassLoader(); System.out.println(classLoader); //测试JDK内置的类是谁加载的 classLoader = Class.forName("java.lang.Object").getClassLoader(); System.out.println(classLoader); //如何获得系统类加载器可以加载的路径 System.out.println(System.getProperty("java.class.path")); } }
通过反射获取运行时类的完整结构
Field、Method、Constructor、Superclass、Interface、Annotation
import java.lang.reflect.Field; import java.lang.reflect.Method; //获得类信息 public class Test3 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { // Class c1 = Class.forName("面试.注解反射.User"); User user = new User(); Class c1 = user.getClass(); //获得类的名字 System.out.println(c1.getName()); System.out.println(c1.getSimpleName()); //获得类的属性 // Field[] fields = c1.getFields(); Field[] fields = c1.getDeclaredFields(); for (Field field:fields) { System.out.println(field); } //获得指定属性的值 /* Field name = c1.getField("name");//java.lang.NoSuchFieldException System.out.println(name);*/ Field name = c1.getDeclaredField("name"); System.out.println(name); System.out.println("====================="); //获得类的方法 Method[] methods = c1.getMethods(); for (Method method:methods ) { System.out.println("正常的:" + method); } methods = c1.getDeclaredMethods(); for (Method method:methods) { System.out.println("getDeclaredMethodes:" + method); } //获得指定方法 Method getName = c1.getMethod("getName",null); Method setName = c1.getMethod("setName",String.class); System.out.println(getName); System.out.println(setName); System.out.println("====================="); //获得指定构造器 Constructor[] constructors = c1.getConstructors(); for (Constructor constructor:constructors) { System.out.println(constructor); } constructors = c1.getDeclaredConstructors(); for (Constructor constructor:constructors) { System.out.println(constructor); } //获得指定的构造器 Constructor con = c1.getDeclaredConstructor(String.class,int.class,int.class); System.out.println(con); } }
Method和Field、Constructor对象都有setAccessible()方法
setAccessible作用:
启动和进用访问安全检查的开关
参数值为true则只是反射的对象在使用时应该取消Java语言访问检查
提高反射的效率,如果代码中必须用反射,而该句代码需要频繁的被调用,那么设置为true
使得原本无法访问的私有成员也可以访问
参数值为false则指示反射的对象应该实施Java语言访问检查
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test4 { //普通方法调用 public static void test11() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { user.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方法执行10000000次:" + (endTime - startTime)); } //反射方式调用 public static void test22() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getMethod("getName", null); long startTime = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式调用执行10000000次:" + (endTime - startTime)); } //反射方式调用,关闭检测 public static void test33() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { User user = new User(); Class c1 = user.getClass(); Method getName = c1.getMethod("getName", null); getName.setAccessible(true); long startTime = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { getName.invoke(user, null); } long endTime = System.currentTimeMillis(); System.out.println("反射方式调用,关闭检测执行10000000次:" + (endTime - startTime)); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test11(); test22(); test33(); } }
.
如果反射调用量级很大的话,可以选择关闭检测
Java采用泛型打出的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是一旦编译完成,所有和泛型有关的类型全部擦除
为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型
import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; //通过反射获取泛型 public class Test5 { public void test01(Map<String,User> map, List<User> list){ System.out.println("test01"); } public Map<String,User> test02(){ System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = Test5.class.getMethod("test01", Map.class, List.class); Type[] genericParameterTypes = method.getGenericExceptionTypes(); for (Type genericParameterType:genericParameterTypes) { System.out.println("#" + genericParameterType); if(genericParameterType instanceof ParameterizedType){ Type[] actualTypeArguments = ((ParameterizedType)genericParameterType).getActualTypeArguments(); for (Type actualTypeArgument:actualTypeArguments) { System.out.println(actualTypeArgument); } } } method = Test5.class.getMethod("test02",null); Type genericReturnType = method.getGenericReturnType(); if(genericReturnType instanceof ParameterizedType){ Type[] actualTypeArguments =((ParameterizedType)genericReturnType).getActualTypeArguments(); for (Type actualTypeArgument:actualTypeArguments ) { System.out.println(actualTypeArgument); } } } }
ORM是什么?
Object relationship Mapping——>对象关系映射
import java.lang.annotation.*; import java.lang.reflect.Field; //联系反射操作类 public class Test6 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 =Class.forName("Student"); //通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation:annotations) { System.out.println(annotation); } //获得注解的Val的值 TableStu tableStu = (TableStu) c1.getAnnotation(TableStu.class); String value = tableStu.value(); System.out.println(value); //获得类指定的注解 Field field = c1.getDeclaredField("name"); FieldStu annotation = field.getAnnotation(FieldStu.class); System.out.println(annotation.columnName()); System.out.println(annotation.length()); System.out.println(annotation.type()); } } @TableStu("db_student") class Student{ @FieldStu(columnName = "db_id",type = "int",length = 10) private int id; @FieldStu(columnName = "db_age",type = "int",length = 10) private int age; @FieldStu(columnName = "db_name",type = "varchar",length = 10) private String name; public Student() { } public Student(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } } //类名的注解 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @interface TableStu{ String value(); } //属性的注解 @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @interface FieldStu{ String columnName(); String type(); int length(); }
注意:对于private定义,需要用方法getDeclaredField,仅仅使用getField获取不到
@Target
@Retention
静态语言VS动态语言
Class类——>常用方法——>类加载
ClassLoader过程(加载、链接、初始化)
类加载器——>双亲委派
运行时类的对象——>获取——>创建
newInstance
Object invoke——>权限接触
反射操作泛型(了解)
ORM相当于一个例子
https://www.bilibili.com/video/BV1p4411P7V3?p=17