Java学习笔记--注解和反射
注解和反射
1. 注解
注解作用:
- 对程序做出解释
 - 被其他程序读取
 
注解格式:
- @注释名,还可以添加一些参数值,例如@SuppressWarnings(value="unchecked").
 
注解使用在哪里
可以附加在package,class,method,filed,上面,相当于添加了额外的辅助信息,可以通过反射机制对这些元数据进行访问
内置注解
1. @Override
该注释只用于修饰方法,表示重写超类的一个方法,可以让让编译器检查该方法是否正确地实现了覆写
2. Deprecated
该注释可以用于修饰方法、属性、类,表示不鼓励使用,因为使用存在危险或有更好的选择
3. @SuppresseWarnings("para")
告诉编译器忽略此处代码产生的警告,需要参数才能正确的使用,例如 @SuppresseWarnings("all"),
@SuppresseWarnings("unchecked"), @SuppresseWarnings(value={"unchecked","deprecation"})
package com.annotation;
import java.util.ArrayList;
import java.util.List;
public class TestAnnotation {
    //override 方法重写注解
    @Override
    public String toString() {
        return super.toString();
    }
    //Deprecated 不推荐使用,但是任然可以使用
    @Deprecated
    public static void test(){
        System.out.println("test");
    }
    //SuppressWarnings(" ")忽视警告,可以放在方法上
    @SuppressWarnings("all")
    public void test01(){
        List list = new ArrayList();
    }
}
元注解
元注解用于解释其他注解
@Target
表示注解使用范围
- 类或接口:
ElementType.TYPE; - 字段:
ElementType.FIELD; - 方法:
ElementType.METHOD; - 构造方法:
ElementType.CONSTRUCTOR; - 方法参数:
ElementType.PARAMETER。 
@Retention
Retention 定义了Annotation的生命周期
- 仅编译期:
RetentionPolicy.SOURCE; - 仅class文件:
RetentionPolicy.CLASS; - 运行期:
RetentionPolicy.RUNTIME。 
如果@Retention不存在,则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME,所以,务必要加上@Retention(RetentionPolicy.RUNTIME)这个元注解
@Inherited
使用@Inherited定义子类是否可继承父类定义的Annotation。@Inherited仅针对@Target(ElementType.TYPE)类型的annotation有效,并且仅针对class的继承,对interface的继承无效
@Documented
表明该注解将被包含于javadoc内
public class TestMetaAnnotation {
    @MyAnnotation
    public void testMetaAnnotation(){
    }
}
//定义一个元注解
//Target 表示注解使用范围
@Target(value = ElementType.METHOD)
//Retention 定义了Annotation的生命周期
// runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
//表明该注解将被包含于javadoc内
@Documented
//子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
}
自定义注解@interface
使用@interface自动继承Annotation接口

public class TestCreateAnnotation {
    @MyAnnotation02(name = "",age = 10)
    public void test(){
    }
    @MyAnnotation03("Fuck")     //只有一个参数时直接赋值
    public void test03(){
    }
}
//创建注解
@Target({ElementType.TYPE,ElementType.METHOD})
@interface MyAnnotation02{
    //注解参数 : paraType paraName() |(default value);
    String name() default "";   //如果不设置默认值,使用注解时必须给参数赋值
    int age();                  //使用时必须赋值
    int id() default -1;        //default -1 表示默认不存在
     String[] school() default {"Tsinghua","Peking"};
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation03{
String value();     //只有一个参数成员时,参数名一般为value
}
2.反射
3.1 反射机制
- 反射机制允许程序在运行期间借助与Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性以及方法
 - 加载完类后,在堆内存的方法区产生了一个Class类型的对象,这个对象包含了完整的类的结构信息,我们可以通过这个对象看到类的结构
 

- 反射实现了语言的动态创建和编译,具有很大的灵活性
 - 反射机制是一种解释型的操作,执行效率较低
 
3.2 Class类

Class类的常用方法

获取类的Class对象
对于已知的类,直接通过类的class对象获取,该方法最为可靠,性能最好
Class clz = Cls.class;
对于某个实例,调用getClass方法获取
Class clz = cls.getClass();
通过类的路径以及类名,调用Class类的静态方法forName方法获取
Class clz = forName("packegePath.className");
内置基本数据类型直接使用 className.Type获取
ClassLoader获取
//获取Class类对象
public class TestGetClassInstance {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Person();
        System.out.println("He is "+person.name);
        Person s1 = new Student();
        Class cs = s1.getClass();
        //通过类名直接获取
        Class c1 = Person.class;
        System.out.println(c1.hashCode());
        //forName 方法获取
        Class c2 = Class.forName("com.Reflection.Demo01.Person");
        System.out.println(c2.hashCode());
        //实例.getClass()方法获取
        Class c3 = person.getClass();
        System.out.println(c3.hashCode()); //c1 ~ c3 The same HashCode
        // 基本内置类型的包装类的Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);
        //获得父类类型(实际类型)
        Class c5  = cs.getSuperclass();
        System.out.println(c5);
    }
}
class Person{
    public String name;
    public Person() {
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student() {
        this.name="Student";
    }
}
class Teacher extends Person{
    public Teacher() {
        this.name = "Teacher";
    }
}
拥有Class类型的对象

public class TestClassesPossessedClassAttribute {
    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
        //alt+鼠标左键选中一列数据
        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()); //Same HashCode
        System.out.println(b.getClass().hashCode());
类加载过程


public class TestLoadClass {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.m);
        /*
        1.加载到内存,生成类的Class对象
        A.class;TestLoadClass.class;
        2.链接,为类变量分配内存和赋初值
        m=0;
        3.初始化
        执行类构造器方法<clinit>()将所有类变量赋值以及静态代码块合并形成
        <clinit>(){
            static {
            System.out.println("Static Filed");
            m = 200;
                }
            static int m= 100;
            }
         */
    }
}
class A{
    static {
        System.out.println("Static Filed");
        m = 200;
    }
    /*
    m=200;
    m=100
     */
    static int m= 100;
    public A(){
        System.out.println("A类的无参构造初始化");
    }
}
类的初始化

public class TestInitClass {
    static {
        //1.main方法所在类初始化
        System.out.println("buying a gun");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        //2.主动引用new
        //Robber robber = new Robber();
        //3.反射引用
        //Class.forName("com.Reflection.Demo01.Robber");
        //不会产生类的初始化
        //1.调用子类继承父类的静态变量和方法时
        //System.out.println(Robber.moneyBefore);
        //Robber.b();
        //2.初始化类的数组时
        Robber[] robbers = new Robber[10];
        //3.引用常量(链接阶段就存入调用类的常量池了)
        System.out.println(Robber.escapeMoney);
    }
}
//测试类初始化
class Criminal{
    static double moneyBefore = 20;
    static {
        System.out.println("Gives me your fucking money!");
    }
    static void b(){
        System.out.println("父类静态方法调用");
    }
}
class Robber extends Criminal{
    static {
        System.out.println("This is a robbery! Put your hands up!!");
        double getMoney = 292898;
    }
    static double robberMoney = 8361303.222;
    static final double escapeMoney = 1000;
}
类加载器作用


双亲委派机制
当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。

public class TestClassLoader {
    public static void main(String[] args) {
        //获取系统类加载器
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);
        // 获取系统类加载器父类---扩展类加载器
        classLoader = classLoader.getParent();
        System.out.println(classLoader);
        // 获取扩展类加载器父类---根加载器(无法获取:null)
        classLoader = classLoader.getParent();
        System.out.println(classLoader);
        //测试当前类的ClassLoader
        classLoader = TestLoadClass.class.getClassLoader();
        System.out.println(classLoader);
        //测试JDK内置类的加载器
        classLoader = String.class.getClassLoader();
        System.out.println(classLoader);
        //获得系统类加载器路径
        System.out.println(System.getProperty("java.class.path"));
    }
}
3.3 反射操作
1. 获取类的结构
package com.reflection.Demo02;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//Testing using the class object to obtain the contents of a class
public class TestGetClassInfo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        // Get the Class of a class by path
        Class c1 = Class.forName("com.reflection.Demo01.User");
        //Get ClassName
        System.out.println(c1.getName());       //package + ClassName
        System.out.println(c1.getSimpleName()); //ClassName
        System.out.println();
        //Get all public properties
        Field[] fields = c1.getFields(); //getField() only used on properties with decoration of public
        for (Field field : fields) {    //out: null ,no method decorated with public
            System.out.println(field);
        }
        //Get all properties
        fields = c1.getDeclaredFields(); //getDeclaredFields() used on all types of properties
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println();
        //Get particular property
        //only public
        //Field name = c1.getField("name"); -> NoSuchFieldException
        //out.println(name);
        Field name = c1.getDeclaredField("name");
        System.out.println(name);
        System.out.println();
        //Get methods
        Method[] methods = c1.getMethods();//all public methods include methods inherited superClass or superInterface
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println();
        methods = c1.getDeclaredMethods();
        for (Method method : methods) { //all methods exclude inherited
            System.out.println(method);
        }
        System.out.println();
        //Get particular method getMethod(name,paraType.class)
        Method method1 =c1.getMethod("getName",null);
        Method method2 =c1.getMethod("setName",String.class);
        System.out.println(method1);
        System.out.println(method2);
        System.out.println();
        //Get Constructors
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) { //public constructors
            System.out.println(constructor);
        }
        System.out.println();
        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {//all
            System.out.println(constructor);
        }
        System.out.println();
        //get particular public constructor getConstructor(para.class|null);
        Constructor constructor = c1.getConstructor(String.class);
        System.out.println(constructor);
        System.out.println();
        //get particular constructor getDeclaredConstructor(para.class|null);
        constructor = c1.getDeclaredConstructor(String.class);
        System.out.println(constructor);
        constructor = c1.getDeclaredConstructor(null);
        System.out.println(constructor);
    }
}
获取父类:getSuperclass()
获取继承的接口:getInterfaces()
如果是两个Class实例,要判断一个向上转型是否成立,可以调用isAssignableFrom():
2.反射创建对象
方法1:Class.newInstance() 方法(java9后弃用)
//获取对象
Class c1 = User.class;
//构造一个对象
User user = (User)c1.newInstance();
System.out.println(user);
局限:它只能调用该类的public无参数构造方法。
方法2:通过构造器对象newInstance()方法创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class,String.class,int.class,String.class);
User user2 = (User)constructor.newInstance("001","wang",20,"Male");
System.out.println(user2);
调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问。
3.反射调用方法
Method sN = c1.getDeclaredMethod("setName",String.class);
sN.invoke(user2,"Liu");//method.invoke(obj,value)
System.out.println(user2.getName());
method对象包含信息
getName():返回方法名称,例如:"getScore";getReturnType():返回方法返回值类型,也是一个Class实例,例如:String.class;getParameterTypes():返回方法的参数类型,是一个Class数组,例如:{String.class, int.class};getModifiers():返回方法的修饰符,它是一个int,不同的bit表示不同的含义。
如果获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null。
调用非public方法,我们通过Method.setAccessible(true)允许其调用:
4.设置字段值
Field name= c1.getDeclaredField("name");
name.setAccessible(true);   //不能直接操作私有属性,需要设置访问安全检查为true
name.set(user2,"Li");       //field.set(fieldObj,value)
System.out.println(user2.getName());
一个Field对象包含了一个字段的所有信息:
getName():返回字段名称,例如,"name";getType():返回字段类型,也是一个Class实例,例如,String.class;getModifiers():返回字段的修饰符,它是一个int,不同的bit表示不同的含义。
修改非public字段,需要首先调用setAccessible(true)
5.SetAccessible

public class TestSetAcc {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        User user = new User();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1_000_000_000; i++) {
            user.getName();
        }
        long end = System.currentTimeMillis();
        System.out.println("普通方式调用方法十亿次"+(end-start)+"ms");
        //反射方式
        TestSetAcc.test();
        TestSetAcc.test01();
    }
    public static void test() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class c1 = User.class;
        User user = new User();
        Method method= c1.getDeclaredMethod("getName",null);
        method.setAccessible(true);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1_000_000_000; i++) {
            method.invoke(user,null);
        }
        long end = System.currentTimeMillis();
        System.out.println("关闭检测方式调用十亿次"+(end-start)+"ms");
    }
    public static void test01() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class c1 = User.class;
        User user = new User();
        Method method= c1.getDeclaredMethod("getName",null);
        method.setAccessible(false);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1_000_000_000; i++) {
            method.invoke(user,null);
        }
        long end = System.currentTimeMillis();
        System.out.println("检测方式调用十亿次"+(end-start)+"ms");
    }
}
6.反射操作泛型

//反射获取泛型
public class TestReflectionGeneric {
    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 = TestReflectionGeneric.class.getDeclaredMethod("test01",Map.class,List.class);
        Type[] genericParameterTypes= method.getGenericParameterTypes();
        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);
                }
            }
        }
        System.out.println();
        Method method01 = TestReflectionGeneric.class.getDeclaredMethod("test02",null);
        Type genericReturnTypeType = method01.getGenericReturnType();
        if(genericReturnTypeType instanceof ParameterizedType){
            Type[] actualTypeArguments= ((ParameterizedType) genericReturnTypeType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
            }
        }
}
7.反射操作注解
//反射操作注解
public class TestReflectionAnnotation {
    public static void main(String[] args) throws NoSuchFieldException {
        //反射获得类的注解
        Class c1 = Student.class;
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        //获得注解的value
        Table table = (Table) c1.getAnnotation(Table.class);
        System.out.println(table.value());
        //获得指定注解
        Field field = c1.getDeclaredField("id");
        FieldAnn annotation = field.getAnnotation(FieldAnn.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.type());
        System.out.println(annotation.length());
    }
}
@Table("TableStudent")
class Student{
    @FieldAnn(type = "varchar",length = 10,columnName = "db_id")
    private String id;
    @FieldAnn(type = "db_int",length = 10,columnName = "db_age")
    private int age ;
    @FieldAnn(type = "varchar",length = 10,columnName = "dn_name")
    private  String name;
    public Student() {
    }
    public String getId() {
        return id;
    }
    public void setId(String 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;
    }
}
//class annotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
}
//field annotation
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnn{
    String columnName();
    String type();
    int length();
}
												
											Java学习笔记--注解和反射的更多相关文章
- 0035 Java学习笔记-注解
		
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
 - Java学习笔记之使用反射+泛型构建通用DAO
		
PS:最近简单的学了学后台Servlet+JSP.也就只能学到这里了.没那么多精力去学SSH了,毕竟Android还有很多东西都没学完.. 学习内容: 1.如何使用反射+泛型构建通用DAO. 1.使用 ...
 - Java学习笔记54(反射详解)
		
反射概念: java反射机制是在运行状态中,对于任意一个类,都能知道所有属性和方法 对于任意一个对象都能调用它的任意一个方法和属性,这种动态获取和调用的功能称为java的反射机制 实际作用: 已经完成 ...
 - Java学习笔记八(反射)
		
1.介绍 反射为Java程序在执行时提供了动态的能力.利用反射能够在执行时对程序进行动态的控制.本篇博客着重解说一下Java中的反射. 2.Class类的使用 在Java执行过程中,每一个类被载入后都 ...
 - Java学习笔记--注解
		
注解的使用与实例:http://www.cnblogs.com/pepcod/archive/2013/02/16/2913474.html 注解的作用及使用方法:http://wenku.baidu ...
 - Java学习:注解,反射,动态编译
		
狂神声明 : 文章均为自己的学习笔记 , 转载一定注明出处 ; 编辑不易 , 防君子不防小人~共勉 ! Java学习:注解,反射,动态编译 Annotation 注解 什么是注解 ? Annotat ...
 - JAVA学习笔记—review基本知识[反射与异常]
		
JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...
 - 《Java学习笔记(第8版)》学习指导
		
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
 - 0032 Java学习笔记-类加载机制-初步
		
JVM虚拟机 Java虚拟机有自己完善的硬件架构(处理器.堆栈.寄存器等)和指令系统 Java虚拟机是一种能运行Java bytecode的虚拟机 JVM并非专属于Java语言,只要生成的编译文件能匹 ...
 
随机推荐
- Android 9.0 BufferSlot注解
			
源码位置 /frameworks/native/libs/gui/include/gui/BufferSlot.h 源码 struct BufferSlot { BufferSlot() : mGra ...
 - Golang语言系列-04-运算符
			
运算符 Go语言内置的运算符有 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 算术运算符 package main import "fmt" func main() { ...
 - SpringBoot开发八-会话管理
			
需求介绍-会话管理 利用Cookie和Seesion使得HTTP变成有会话的连接,写几个实例演示一下 代码实现 先写个例子,表示客户端第一次访问服务器,服务器端创建一个Cookie发送给客户端. 不管 ...
 - idea自定义 tags 删除
			
idea custom tags 添加后 如何去除 如何去除 custom tags 随便@一些字符串,这时候alt+enter弹出 Add xxx to custom tags, 这时候按有方向键进 ...
 - Longhorn,企业级云原生容器分布式存储 - 监控(Prometheus+AlertManager+Grafana)
			
内容来源于官方 Longhorn 1.1.2 英文技术手册. 系列 Longhorn 是什么? Longhorn 企业级云原生容器分布式存储解决方案设计架构和概念 Longhorn 企业级云原生容器分 ...
 - SQL 练习19
			
统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] SELECT Course.CId,Course.Cname ,t.[0-60],t.[6 ...
 - docker部署mysql5-7-31
			
快速开始 docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql docker-compo ...
 - virtualenv 创建python虚拟环境
			
为什么要创建python虚拟环境 在开发Python应用程序的时候,系统安装的Python3只有一个版本:3.4.所有第三方的包都会被pip安装到Python3的site-packages目录下. 如 ...
 - asp.net core 知识点总结
 - ASP net core面试题汇总及答案
			
在dot net core中,我们不需要关心如何释放这些服务, 因为系统会帮我们释放掉.有三种服务的生命周期. 单实例服务, 通过add singleton方法来添加.在注册时即创建服务, 在随后的请 ...