文章目录
注解(Java.Annotation)
1. 作用
可以被其他程序(比如:编译器)读取
2. 内置注解
//Override 表示:重写
@Override
//Deprecated 表示:不推荐使用
@Deprecated
//SuppressWarnings 表示:抑制编译器警告
@SuppressWarnings("rawtypes")
@SuppressWarnings(value={"unchecked", "rawtypes"})
@SuppressWarnings("all")
3. 元注解
注解其他注解
//保留期,能设定注解的存活时间
//RUNTIME > CLASS > SOURCE
@Retention(RententionPolicy:SOURCE)
RententionPolicy:SOURCE //源代码阶段
RententionPolicy:CLASS //到编译阶段
RententionPolicy:RUNTIME //到运行阶段
//将注解中的元素包含到Javadoc中
@Documented
//限定注解能运用的地方
@Target(ElementType.ANNOTATION_TYPE)
ElementType.ANNOTATION_TYPE //注解
ElementType.COUNSTRUCTOR //构造方法
ElementType.FIELD //属性
ElementType.METHOD //属性
//标明注解是能被继承的,例如B继承了A,A添加了注解,那么B也会继承同样的注解
@Inherited
4. 自定义注解
语法: public @interface xxx{}
使用:@xxx
注解只有成员变量,没有方法
public @interface MyAnnotation{
//注解的参数:参数类型+参数名
String name();
int age() default 0; //默认值
}
//使用
@MyAnnotation(name="hh")
反射(Java.Reflection)
1. 概述
-
动态和静态语言
动态语言:运行时才确定数据类型的语言,变量在使用之前无需申明类型,通常变量的值是被赋值的那个值的类型。比如Php、Asp、JavaScript、Python、Perl等等。
静态语言:是编译时变量的数据类型就可以确定的语言,大多数静态语言要求在使用变量之前必须生命数据类型。比如Java、C、C++、C#等。
-
Reflection(反射)是java被视为动态语言的关键,允许程序在执行器利用Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。
-
注意:
一个类在内存中只有一个Class对象
一个类被加载后,类的整个结构都会被封装在Class对象中
2. 理解class类并获取Class实例
-
正常:引入需要的“包类”、new实例化、取得实例化对象
反射:实例化对象、getClass()方法、得到完整的“包类”
-
反射主要API
Java.lang.Class | 代表一个类 |
---|---|
java.lang.reflect.Method | 代表类的方法 |
java.lang.reflect.Field | 代表类的成员变量 |
java.lang.reflect.Constructor | 代表类的构造器 |
-
Class类常用方法
Class.forName(“ClassName”) 返回类名name的Class对象
Class.newInstance() 调用缺省构造函数,返回Class对象的一个实例。(有点像new)
Class.getName() 返回Class对象所表示的实体的,名称(类、接口);
Class.CanonicalName() 返回不包含包名的全限定名;
Class.getSimpleName() 返回不包含包名的类名;
Class.getInterface() 返回Class对象,表示在感兴趣的Class对象中所包含的接口;Class.getSuperclass() 返回所选类基类;
ClassLoader getClassLoader() :返回该类的加载器
-
获取Class实例的创建方式
– 通过类名获得(推荐):Class cl = User.class;
– 通过对象获得:Class cl = user.getClass();
– Class cl = Class.forName(“com.JAVASE.User”);
//什么是反射 public class TestReflection extends Object{ public static void main(String[] args) throws ClassNotFoundException { //通过反射获取类的Class对象 Class c1 = Class.forName("com.JAVASE.User"); System.out.println(c1); Class c2 = Class.forName("com.JAVASE.User"); Class c3 = Class.forName("com.JAVASE.User"); Class c4 = Class.forName("com.JAVASE.User"); //hashcode一样 //一个类在内存中只有一个Class对象 //一个类被加载后,类的整个结构都会被封装在Class对象中 System.out.println(c2.hashCode()); System.out.println(c3.hashCode()); System.out.println(c4.hashCode()); } }
-
包含Class对象的类型
class、interface、数组、枚举、注解、基本数据类型、void
3. JAVA内存分析
- java内存分析
方法区是特殊的堆
-
类的初始化过程
- 加载:class文件字节码内容加载到内存中,将静态数据转换为运行时数据结构,然后生成一个代码这个类的java.lang.Class对象
- 链接:将java类的二进制代码合并到JVM的运行状态之中【验证(是否符合JVM规范)、准备(为类变量分配内存并设置类变量默认初始值)、解析(符号引用替换为直接引用)】
- 初始化:JVM执行类构造器()方法
4. 类的加载
-
代码演示
public class TestClassLoad { public static void main(String[] args) { A a = new A(); System.out.println(A.m); /* 1. 加载到内存,会产生一个类对应Class对象 2. 链接,链接结束后m = 0(默认值) 3. 初始化 <clinit>(){ System.out.println("A类静态代码块初始化"); m = 300; m = 100; } m = 100; */ } } class A{ //静态代码在类的初始化阶段被初始化 //非静态代码在类的使用阶段被初始化 //静态方法在内存中只有一份 static{ System.out.println("A类静态代码块初始化"); m = 300; } static int m = 100; public A(){ System.out.println("A类无参构造初始化"); } }
5. 类的初始化
-
发生条件:
类的主动引用会产生初始化【new、调用类的静态成员和方法、反射、父类没有被初始化会先初始化父类】
类的被动引用不会引发类的初始化【通过子类引用父类的静态变量、数组定义类引用、常量(在链接阶段)】
-
代码演示
public class TestInit { static{ System.out.println("main类被加载"); } public static void main(String[] args) throws ClassNotFoundException { //1. new主动引用 // Son son = new Son(); //反射产生的主动引用 // Class.forName("com.JAVASE.Son"); //不会产生类的引用的方法(main father) // System.out.println(Son.b); //(main) // Son[] array = new Son[5]; //(main) System.out.println(Son.M); } } 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 = 1; }
6. 类加载器(ClassLoader)
-
作用:ClassLoader负责通过各种方式将Class信息的二进制数据流读入JVM内部,转换为一个于目标类对应的java.lang.Class对象实例。
-
分类:
– 启动类加载器(JAVA_HOME/jre/lib/rt.jar或sun.boot.class.path路径下的内容)
– 扩展类加载器(父类加载器为启动类加载器)
– 系统类加载器(父类加载器为启动类加载器,它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库) -
代码
public class TestLoader { 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 parent1 = parent.getParent(); System.out.println(parent1); //测试当前类是哪个加载器加载的 ClassLoader classLoader = Class.forName("com.JAVASE.TestLoader").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")); //双亲委派机制:存在原来的包会用原来的包 //java.lang.String } }
7. 获取类的运行时结构
获取类的属性、方法、构造器、修饰符、注解
public class TestClassInformation {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("com.JAVASE.User");
// User user = new User();
// Class c1 = user.getClass();
//获得类的名字
System.out.println(c1.getName()); //获得包名+类名
System.out.println(c1.getSimpleName()); //获得类名
//获得类的属性
Field[] fields = c1.getFields();//只能都找到public 属性
for (Field field : fields) { //可以找到全部属性
System.out.println(field);
}
//获得指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name);
//获得类的方法
System.out.println("====");
//获得奔雷及其父类的全部public方法
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获得本类的所有方法,包含private
Method[] declaredMethods = c1.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
//获得指定方法
//重载
Method getName = c1.getMethod("getName",null);
Method setName = c1.getMethod("setName",String.class);
System.out.println(getName);
System.out.println(setName);
//获得指定构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor);
}
//获得指定构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println(declaredConstructor);
}
}
8. 动态创建对象执行方法
public class TestObject {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得class对象
Class c1 = Class.forName("com.JAVASE.User");
//构造一个对象
User user = (User)c1.newInstance(); //本质调用了类的无参构造器
System.out.println(user);
//通过构造器创建对象,有参数通过这种方式进行创建
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user2 = (User)declaredConstructor.newInstance("xrz",001,18);
System.out.println(user2);
//通过反射调用普通方法
User user3 = (User)c1.newInstance();
//通过反射获取方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//激活(对象,方法的值),相当于执行
//调用指定的方法
setName.invoke(user3,"xrz");
System.out.println(user3.getName());
//通过反射操作属性
//这样方法获取不到,权限不够,因为name是private
// User user4 = (User)c1.newInstance();
// Field name = c1.getDeclaredField("name");
// name.set(user4,"xrz2");
// System.out.println(user4.getName());
//取消安全检测就可以访问私有属性
User user5 = (User)c1.newInstance();
Field name5 = c1.getDeclaredField("name");
name5.setAccessible(true);
name5.set(user5,"xrz2");
System.out.println(user5.getName());
}
}
注意:
取消安全检测就可以访问私有属性setAccessible(true);
调用指定的方法:setName.invoke(user3,“xrz”);
9. 反射操作泛型
-
ParameterizedType:表示一种参数化类型,比如Collection
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable:是各种类型变量的公共父接口
WildcardType:代表一种通配符类型表达式
10. 反射操作注解
-
ORM对象关系映射
-
代码:利用注解和反射完成类和表结构的映射关系
//练习反射操作注解 public class TestFAndA { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c1 = Class.forName("com.JAVASE.Student"); //通过反射获得注解 Annotation[] annotations = c1.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } //获得注解的value的值 Table table = (Table)c1.getAnnotation(Table.class); String value = table.value(); System.out.println(value); //获得类指定的注解 Field f = c1.getDeclaredField("name"); FieldTable annotation = f.getAnnotation(FieldTable.class); System.out.println(annotation.columnName()); System.out.println(annotation.type()); System.out.println(annotation.length()); } } @Table("db_stu") class Student{ @FieldTable(columnName = "db_id",type="int",length=10) private int id; @FieldTable(columnName = "db_age",type="int",length=10) private int age; @FieldTable(columnName = "db_name",type="int",length=3) 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 Table{ String value(); } //属性的注解 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface FieldTable{ String columnName(); String type(); int length(); }
``
本文是参考B站遇见狂神说的相关视频进行学习记录的,如有问题也欢迎大家一起交流~