学习视频来自于:秦疆(遇见狂神说)Bilibili地址
他的自学网站:kuangstudy
唯有热爱,能抵岁月漫长
JDK1.5
及以后版本引入的新技术。使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口。
自动继承
public interface MyAnno extends java.lang.annotation.Annotation {}
自定义注解代码
// 自定义注解
@Target(value = {ElementType.METHOD})// 使用范围:方法
@Retention(RetentionPolicy.RUNTIME)// 作用域:运行时有效
@Documented // 可以被抽取到API文档中
@Inherited // 可以被子类继承。
@interface MyAnnotation {
// 注解的参数:参数类型 + 参数名();
String name() default "";// 需要输入一个String类型,不输入默认空字符串。
int age() default 0;// 需要输入一个int类型,不输入默认0。
int id() default -1;// 默认值-1,代表不存在。
String[] schools();// 需要一个String类型数组
}
动态语言
在运行时可以改变其结构的语言:例如新的函数、对象、代码都可以被引进,已有的函数可以被删除或者其它结构上的变化。
主要动态语言:Object-C、C#、JavaScript、PHP、Python等。
静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言,如Java、C、C++。
Java不是动态语言,但是Java可以称之为“准动态语言”。Java有一定的动态性,可以利用反射机制获得类似动态语言的特性,Java的动态性让编程更加灵活。
Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并且直接操作任意对象的内部属性及方法。
Class c = Class.forName("java.lang.String")
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类结构信息。我们可以通过这个对象看到类的结构,这个对象就像一个镜子,通过这个镜子看到类的结构,我们形象的称之为:反射。
正常方式:
引入需要的“包类”名称->通过new实例化->取得实例化对象
反射方式:
实例化对象->getClass()方法->得到完整的“包类”名称
优点
可以实现动态创建对象和编译,体现出很大的灵活性。
缺点
对性能有影响,使用反射基本上是一种解释操作,我们可以告诉JVM,希望做什么并且满足我们的要求,这类操作总是慢于直接执行相同操作。
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器
概述
对象照镜子后可以得到一个信息:某个类的属性、方法和构造器,某个类到底实现了哪些接口。
对于每个类而言,JRE都为其保留一个不变的Class类型的对象,一个Class对象包含了特定某个结构的有关信息。
class/interface/enum/annotation/primitive type/void[]
Class类的常用方法
class:外部类、成员(成员内部类、静态内部类)、局部内部类、匿名内部类
interface:接口
[]:数组
enum:枚举
annotation:注解@interface
primitive type:基本数据类型
void:空类型
当程序主动使用某个类时,如果该类还未加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。
() 方法的过程。类构造器
()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
()方法在多线程环境中被正确加锁和同步。public class Application {
public static void main(String[] args) throws Exception {
A a = new A();
System.out.println(A.m);
/*
执行过程
1.加载到内存,会产生一个类对应Class对象
2.链接,连接结束后分配内存设置初始值 m=0
3.初始化
(){ //将静态代码块合并执行
System.out.println("A类静态代码块初始化");
m=300
m=100
*/
}
}
class A{
static {
System.out.println("A类静态代码块初始化");
m = 300;
}
static int m = 100;
public A(){
System.out.println("A类的无参构造初始化");
}
}
执行结果
A类静态代码块初始化
A类的无参构造初始化
100
类加载的作用:
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
类缓存:
标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象。
类加载器的分类
引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库
,用来装载核心类库,该加载器无法直接获取。
扩展类加载器:负责jre/lib/ext目录下的jar包或-D Java.ext.dirs指定目录下的jar包装入工作库
系统类加载器:负责java -classpath或 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器
// 获取系统类的加载器
// 获取系统类的加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
// 获取系统类加载器的父类加载器-->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@4554617c
// 获取扩展类加载器的父类加载器-->根加载器(c/c++)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//null
// 测试当前类是哪个加载器加载的
ClassLoader classLoader = Application.class.getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
// 测试Object类是哪个加载器加载的
ClassLoader loader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(loader);//null 是由根加载器加载的核心包
// 获取系统加载器可以加载那些路径
System.out.println(System.getProperty("java.class.path"));
/* 不在这些路径内,系统加载器是加载不到了
D:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;
D:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;
D:\IdeaProjects\基础练习\out\production\基础语法;
D:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.3.1\lib\idea_rt.jar
*/
防止同名包、类与 jdk 中的相冲突,实际上加载类的时候,先通知 appLoader,看 appLoader 是否已经缓存,没有的话,appLoader 又委派给他的父类加载器(extLoader)询问,看他是不是能已经缓存加载,没有的话,extLoader 又委派他的父类加载器(bootstrapLoader)询问,BootstrapLoader看是不是自己已缓存或者能加载的,有就加载,没有再返回 extLoader,extLoader 能加载就加载,不能的话再返回给 appLoader 加载,再返回的路中,谁能加载,加载的同时也加缓存里。正是由于不停的找自己父级,所以才有 Parents 加载机制,翻译过来叫 双亲委派机制。
通过反射获取运行时类的完整结构
Field、Method、Constructor、Superclass、Interface、Annotation
Class application = Class.forName("User");
// 获得类的名字
System.out.println(application.getName());// 获得包名+类型
System.out.println(application.getSimpleName());// 获得类名
// 获得所有属性(因为属性全部私有,所有一个都没有被获得)
for (Field field : application.getFields()) {
System.out.println(field);
}
// 获取全部属性
System.out.println("==================================");
for (Field field : application.getDeclaredFields()) {
System.out.println(field);
}
// 获取指定属性指
System.out.println("==================================");
System.out.println(application.getDeclaredField("name"));
// 获取类的方法(本类和父类)
System.out.println("==================================");
for (Method method : application.getMethods()) {
System.out.println(method);
}
// 获取类的方法(本类)
System.out.println("==================================");
for (Method method : application.getDeclaredMethods()) {
System.out.println(method);
}
// 获取类的指定方法(Java有重载,需要参数判断)
System.out.println("==================================");
Method getAge = application.getMethod("getAge");
Method setAge = application.getMethod("setAge",int.class);
System.out.println(getAge);
System.out.println(setAge);
// 获取类的指定构造器
System.out.println("==================================");
for (Constructor constructor : application.getConstructors()) {
System.out.println("getConstructors:"+ constructor);// 获得public修饰的
}
for (Constructor constructor : application.getDeclaredConstructors()) {
System.out.println("getDeclaredConstructors:"+constructor);// 获得全部
}
// 获取指定的构造器
System.out.println("==================================");
System.out.println(application.getConstructor(null));
创建对象
调用Class对象的newInstance()方法
//获取class对象
Class c1 = Class.forName("User");
// 构造一个对象
//Object user = c1.newInstance();
//System.out.println(user);
调用指定方法
通过Method类调用,使用Object invoke(Object obj,Object[] args)调用
// 通过反射调用普通方法 invoke(对象,方法需要的值)激活
Method getName = c1.getMethod("getName");
System.out.println(getName.invoke(user,null));// 输出要调用的方法的返回值
setAccessible
// 通过反射调用属性
Field name = c1.getDeclaredField("name");
// 因为是private修饰,关闭权限检测,true关闭
name.setAccessible(true);
name.set(user,"四");
System.out.println(user.getName());
测试代码
// 普通方式调用
User user = new User();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行10亿次:" + (endTime - start) + "ms");
// 反射方式调用
Class c1 = Class.forName("User");
User u1 = (User)c1.newInstance();
Method getName = c1.getMethod("getName", null);
start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(u1,null);
}
endTime = System.currentTimeMillis();
System.out.println("反射方式执行10亿次:" + (endTime - start) + "ms");
// 反射方式调用 关闭检查
Class c2 = Class.forName("User");
User u2 = (User)c2.newInstance();
Method method = c2.getMethod("getName",null);
start = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
method.setAccessible(true);
method.invoke(u2,null);
}
endTime = System.currentTimeMillis();
System.out.println("反射方式,关闭检查执行10亿次:" + (endTime - start) + "ms");
结果
普通方式执行10亿次:4ms
反射方式执行10亿次:2377ms
反射方式,关闭检查执行10亿次:1132ms
Collection
。// 参数泛型
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 Exception {
// 获得Class对象
Class c1 = Application.class;
// 获得方法test01
Method test01 = c1.getMethod("test01", Map.class, List.class);
// 获得参数类型
for (Type genericParameterType : test01.getGenericParameterTypes()) {
System.out.println("参数类型:" + genericParameterType);
// 属于参数化类型,就可以获得真实类型(结构化参数类型)
if (genericParameterType instanceof ParameterizedType) {
// 获得泛型参数类型
for (Type actualTypeArgument : ((ParameterizedType) genericParameterType).getActualTypeArguments()) {
System.out.println("真实类型:" + actualTypeArgument);
}
}
}
// 获得方法test02
Method test02 = c1.getMethod("test02", null);
// 获得返回值类型
Type genericReturnType = test02.getGenericReturnType();
System.out.println("返回值类型:" + genericReturnType);
// 属于参数化类型,就可以获得真实类型(结构化参数类型)
if (genericReturnType instanceof ParameterizedType) {
// 获得泛型参数类型
for (Type actualTypeArgument : ((ParameterizedType) genericReturnType).getActualTypeArguments()) {
System.out.println("真实类型:" + actualTypeArgument);
}
}
@Table("db_student")
class User {
@Field(Columname = "db_id", type = "int", length = 10)
private int id;
private int age;
private String name;
public User() {
}
public User(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 "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
注解类
// 类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}
// 属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Field {
String Columname();
String type();
int length();
}
调用
Class c1 = Class.forName("User");
// 获取类注解
Table annotation = (Table)c1.getAnnotation(Table.class);
// 获取value
System.out.println(annotation.value());
// 获取属性注解
java.lang.reflect.Field id = c1.getDeclaredField("id");
Field annotation1 = id.getAnnotation(Field.class);
// 获取Columname值
System.out.println(annotation1.Columname());