Annotation的格式:
idea 编译器中黄色的代码(@注释名)
Annotation的作用:
不是程序本身,可以对程序作出解释。(这一点和注释相同)
可以被其他程序读取。
Annotation在那里使用:
可以附加在包、类、方法上,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元素据的访问
内置注解
@Overide //重写一个类的方法
@Deprecated //不推荐使用此方法,有更好的方法或替代
@SuppressWarnings //用来抑制编译时的警告信息
//要有参数(all) (unchecked) (value={"unchecked","depreciation"})
元注解
作用就是负责注解其他注解(@Target,@Retention,@Documented,@Inherited)
@MyAnnotation
public class Test01 {
public void test(){
}
}
//定义一个注解
//Target 表示我们的注解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Rectention 表示我们的注解在什么地方有效
//runtime > class > sources(Java源码中)
@Retention(value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在Javadoc中
@Documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{//自定义注解
}
自定义注解
使用@interface 自定义注解
//自定义注解
public class Test02 {
@MyAnnotation2(age=18,name="xzh")
public void test(){}
@MyAnnotation3("xzh")//value可以不写出
public void test2(){}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
//注解参数:参数类型 + 参数名();
String name() default "";
int age();
int id() default -1;//如默认值是-1,代表不存在
String[] schools() default {"西华大学","清华大学"};
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
String value();//只有一个值时,
// 用value可以在方法上面不加value直接赋值
}
反射机制
Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。
优点:
可以实现动态创建对象和编译,体现出很大的灵活性
缺点:
对性能有影响。使用反射基本上是一种解释操作,告诉JVM,我们希望做什么并且它满足我们的需求。总是慢于 直接执行相同的操作
认识反射
//什么叫反射
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的class对象
Class c1 = Class.forName("reflection.User");
System.out.println(c1);
Class c2 = Class.forName("reflection.User");
Class c3 = Class.forName("reflection.User");
Class c4 = Class.forName("reflection.User");
//一个类在内存中只有一个Class对象
//一个类被加载后,类的整个结构都会被封装在Class对象中
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
}
}
//实体类:pojo ,entity
class User{
private String name;
private int id;
private int age;
}
获取class对象
//4种方式
public static void main(String[] args) throws ClassNotFoundException {
Person person=new Student();
System.out.println("这个人是:"+person.name);
//方式一:通过对象获得
Class c1=person.getClass();
System.out.println(c1.hashCode());
//方式二:forname获得
Class c2 = Class.forName("reflection.Student");
System.out.println(c2.hashCode());
//方式三:通过类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//方式四:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);
//获得父类类型
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
/*
这个人是:学生
1163157884
1163157884
1163157884
int
class reflection.Person
*/
哪些类型可以有Class对象
几乎所有类型都有Class对象
public static void main(String[] args) {
Class c1 = Object.class;//类
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);
//只要元素类型与维度一样,就是同一个CLass
int[] a=new int[10];
int[] b=new int[100];
System.out.println(a.getClass().hashCode());
System.out.println(b.getClass().hashCode());
}
/*
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class
1163157884
1163157884
*/
类加载内存分析
/*
1.加载到内存,会产生一个类对应的Class对象
2.链接,链接结束后 变量赋值默认为m=0
3.初始化
<clinit>(){
}//使用clinit方法初始化static代码,将static代码放入此方法中
*/
类初始化
Main类->父类->子类
类的初始化还要分类的主动引用和被动引用
类加载器
作用是用来把类class装载进内存的。JVM规范定义了如下类型的类的加载器。
引导加载器:JVM自带的类加载器
扩展类加载器:jre/lib/ext下单jar包的加载
系统类加载器:负责 Java -classpath所指目录下的类与jar包装入工作,最常用
双亲委派机制:查找包,如果自己创建的与系统的包同名,只执行系统的包,保证安全性。
获取运行时类的完整结构
通过反射获取运行时类的完整结构
Field、Method、Constructor、Superclass、Interface、Annotation
直接调用Class的方法就OK