文章目录
一、注解
1.1认识注解
Annotation是从JDK5.0开始引进的新技术
1.Annotation的作用:
(1)不是程序本身,可以对程序作出解释(这一点和注释(comment)没什么区别)
(2)可以被其他程序(比如编译器)读取
2.Annotation的格式:
注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如:
@SuppressWarnibgs(value=“unchecked”)
3.Annotation在哪里使用
可以附加在package、class、method。field等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些数据的访问
@Override重写父类方法,如果重写的方法名和父类不一致,则会出现错误提示
1.2内置注解
1.Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明
2.Deprecated:定义在java.lang.Deprecated中,此注释可以修辞方法,属性,类,表示不鼓励程序员使用的元素,通常是因为它很危险或者我存在更好的选择
3.SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息,与前面两个注释不一样的是,需要添加一个参数才能正确使用,这些参数都是已经定义好了:
@SuppressWarnings(“all”)
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked”,“deprecated”})
…
/*
* author zhxd
* ClassName Car
* date 2022/12/3 13:49
*/
public class Car extends Object{
@Override
public String toString() {
return super.toString();
}
@Deprecated
public static void test01() {
System.out.println("deprecated");
}
public static void test02() {
test01();
System.out.println("Suppresswarnings");
}
}
可加上@SupperWarnings注解
抑制编译时的警告
1.3元注解
元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们是被用来提供对其他annotation类型作说明,这些类型和它们所注解的类在java.lang.annotation可以找到(
@Target、@Retention、@Document、@Inheritd
)
1.@Target
:用于描述注解的使用范围(注解在哪里可以使用,在类中还是方法或者其他地方)
2.@Retention
:表示需要在什么级别保存该注解信息,用于描述注解的声明周期(SOURCE < CLASS <RUNTIME
)
3.@Documented:说明该注解被包含在Javadoc中
4.@Inheritd:说明子类可以继承父类的注解
package com.zhxd.test;
/*
* author zhxd
* ClassName Test
* date 2022/12/3 22:55
*/
import java.lang.annotation.*;
@MyAnnotation
public class Test {
}
//定义一个注解
//Target表示我们的注解在什么地方可以使用
@Target(value = {ElementType.METHOD, ElementType.TYPE})
//Retention 表示我们在什么地方还有效
// SOURCE表示在源码中有效 CLASS表示源码编译后有效 RUNTIME在运行时还是有效 RUNTIME > CALSS > SOURCE
@Retention(value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在Javadoc中
@Documented
//Inherited 表示子类可以继承父类的注解
@Inherited
@interface MyAnnotation {
}
使用了@interface
自定义注解时,自动继承了java.lang.annotation.Annotation接口
自定义注解分析:
- @interface用来声明一个注解,格式:
[public] @interface 注解名{定义内容}
- 其中每一个方法实际上是声明了一个
配置参数
- 方法名称就是参数名称
- 返回值就是参数的类型(返回值只能是基本数据类型,Class,String,enum)
- 可以通过
default
来声明参数的默认值 - 如果只有一个参数成员,一般参数名为value
- 注解元素
必须要有值
,我们定义注解元素时,经常使用空字符串、0作为默认值
package com.zhxd.test;
/*
* author zhxd
* ClassName Test
* date 2022/12/3 22:55
*/
import java.lang.annotation.*;
@MyAnnotation(age = 18)
public class Test {
}
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation {
//注解参数 : 注解类型 + 参数名()
String name() default "";
int age();
int id() default -1;
String[] school() default {"华南师范大学", "华南理工大学"};
}
二、反射
2.1反射的概念
Reflection(反射)
是Java被视为动态语言的关键,反射机制允许程序在执行期间
借助于Reflect API取得任何类内部的信息,并能直接操作
内部属性及方法
。加载类之后,在堆内存中就会产生一个Class类型的对象(一个类只有一个Class对象),这个对象就像一面镜子,透过这个镜子看到类结构,所以我们形象的称之为:反射
2.2Class类
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口,对于每个类而言,JRE都为其保留一个不变的Class类型的对象
。一个Class对象包含了某个结构(class/interface/enum/annotation/primitive type/void/[]
)的有关信息。
1.Class本身也是一个类
2.Class对象只能由系统
建立对象
3.一个加载的类在JVM中只有一个
Class实例
4.一个Class对象对应的是一个加载到JVM中的一个.class
文件
5.每个类的实例都会记得自己是由哪个Class实例所生成
6.通过Class可以完整的得到一个类中所有
被加载的结构
7.Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有获取相应的Class对象
2.2.1获取Class对象
Class.forName(包名)
类名.class
对象.getClass()
获取父类类型:对象.getSuperClass()
package com.zhxd.test;
/*
* author zhxd
* ClassName Test02
* date 2022/12/27 15:35
*/
//测试Class类的创建方式有哪些
public class Test02 {
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()); // 1956725890
//方式二:forName获得
Class c2 = Class.forName("com.zhxd.test.Student");
System.out.println(c2.hashCode()); // 1956725890
//方式三:通过类名.class获得
Class c3 = Student.class;
System.out.println(c3.hashCode()); // 1956725890
//方式四:基本内置类型的包装类都有一个Type属性
Class c4 = Integer.TYPE;
System.out.println(c4);// int
//获得父类类型
Class c5 = c1.getSuperclass();
System.out.println(c3);// class com.zhxd.test.Student
}
}
class Person {
String name;
public Person(String name) {
this.name = name;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student() {
this.name = "学生";
}
}
class Teacher extends Person {
public Teacher() {
this.name = "老师";
}
}
2.3类加载器
类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class
对象,作为方法区中类数据的访问入口。(把类(class)装载进内存的
)
类缓存:标准的Java SE 类加载器可以按要求查找类,但一旦被加载带类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以回收这些Class对象。
JVM规范定义了如下的类加载器:
引导类加载器:用C++
编写的,是JVM自带的类加载器,负责Java平台核心库
,用来装载核心类库,该加载器无法直接获取
扩展类加载器:负责jre/lib/ext
目录下的jar包或者-D java.ext.dirs
指定目录下的jar包装入工作库
系统类加载器:负责java --classpath
或者java.class.path
所指的目录下的类与jar包装入工作,是最常用
的加载器
package com.zhxd.test;
/*
* author zhxd
* ClassName Test03
* date 2022/12/31 13:23
*/
public class Test03 {
public static void main(String[] args) throws ClassNotFoundException {
//获取系统类加载器
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@74a14482
//获取扩展类加载器的父类加载器 --> 根加载器(c/c++ 无法直接获取,返回null)
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//null
//测试当前类是哪个加载器加载的
ClassLoader classLoader = Class.forName("com.zhxd.test.Test03").getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
//测试jdk内置的类是哪个记载器加载的
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);//null
//如何获取系统加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
}
}
双亲委派机制
:检测安全性,自定义的类加载器去往父类加载器找,如果在父类中能找到,则自定义的这个类是无效
的,比如我们自己定义了一个java.lang.String,类加载器就会往父类加载器找,最终在根加载器找到了String类,自定义的String类则是无效的,不会执行,在一定程度上保证了安全性。
2.4Class对象功能
- 获取成员变量:
Field[] getFields()
:获取所有public修饰的成员变量Field getField(String name)
:获取指定名称public修饰的成员变量Field[] getDeclaredFields()
:获取所有成员变量,不考虑修饰符号Field[] getDeclaredField(String name)
::获取指定名称的成员变量,不考虑修饰符号
Fileld:成员变量- 设置值:
void set(Object obj,Object value)
- 操作值:
void get (Object obj)
- 忽略访问权限:
setAccessible(true)
package com.zhxd.test;
/*
* author zhxd
* ClassName Test01
*/
import java.lang.reflect.Field;
public class Test01 {
public static void main(String[]args) throws NoSuchFieldException, IllegalAccessException {
Class personClass = Person.class;
//01获取所有public修饰的成员变量
Field[] fields = personClass.getFields();//->public修饰的成员变量会被获取到。
Field field = personClass.getField("name");
//获取成员变量a的值
Person p = new Person("zhxd", "female", 20);
System.out.println( field.get(p));
//设置p的a变量值
field.set(p,"张三");
//获取所有的成员变量
Field[] declaredFields = personClass.getDeclaredFields();
Field d = personClass.getDeclaredField("age"); //访问私有属性会报错,但是可以忽略权限限制。
d.setAccessible(true);//暴力反射
Object value2 = d.get(p); //-->null
}
}
class Person {
public String name;
private String sex;
private int age;
Person(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 获取构造方法
Constructor<?>[] getConstructors()
:获取所有用public进行修饰的构造方法Constructor<?> getConstructor(类<? >... parameterTypes)
:获取指定参数的public修饰的构造方法Constructor<?>[] getDeclaredConstructors()
:获取所有构造方法Constructor<?> getDeclaredConstructor(类<? >... parameterTypes)
:获取指定的构造方法
Constructor:构造方法T newInstance(Object ...initargs)
Object person1 = personClass.newInstance()
:实例化对象
package com.zhxd.test;
/*
* author zhxd
* ClassName Test01
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Test01 {
public static void main(String[]args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Person> personClass = Person.class;
//1. 获取构造方法
Constructor<Person> constructor = personClass.getConstructor(String.class, String.class, int.class);
//2. 创建对象
Person person = (Person)constructor.newInstance("zhxd", "female", 20);
//空参构造简写
Person person1 = (Person)personClass.newInstance();
}
}
class Person {
public String name;
private String sex;
private int age;
public Person () {}
public Person(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 获取成员方法
Method[] getMethods()
:获取所有public修饰的成员方法Method getMethod(String name,类<? >... parameterTypes)
:获取指定名称的public修饰的成员方法Method[] getDeclaredMethods()
:获取所有*成员方法Method getDeclaredMethod(String name,类<? >... parameterTypes)
:获取指定名称的成员方法
Method:方法对象Object invoke(Object obj,Object ...args)
:执行方法String getName()
:获取方法名称
package com.zhxd.test;
/*
* author zhxd
* ClassName Test01
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test01 {
public static void main(String[]args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Person> personClass = Person.class;
//1. 获取构造方法
Constructor<Person> constructor = personClass.getConstructor(String.class, String.class, int.class);
//2. 创建对象
Person person = (Person)constructor.newInstance("zhxd", "female", 20);
//3. 获取eat方法
Method eatMethod = personClass.getMethod("eat",String.class);
//4. 执行eat方法
eatMethod.invoke(person, "水果");
}
}
class Person {
public String name;
private String sex;
private int age;
public Person () {}
public Person(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void eat(String food) {
System.out.println("The" + " "+ name + " " + "eat" + " " + food);
}
}
- 获取类名:
String getName()
public static void main(String[]args) {
Class<Person> personClass = Person.class;
String className = personClass.getName();
System.out.println(className);
}
2.5反射和普通方法创建对象性能测试:
package com.zhxd.test;
/*
* author zhxd
* ClassName Test06
* date 2022/12/31 16:10
*/
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test06 {
//普通方法
public static void test01() {
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法执行10亿次:" + (endTime - startTime) + "ms");
}
//反射
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method getName = c.getMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user, null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射执行10亿次:" + (endTime - startTime) + "ms");
}
//反射,关闭安全检测
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class c = user.getClass();
Method getName = c.getMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(user, null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭检测后执行10亿次:" + (endTime - startTime) + "ms");
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
test01();
test02();
test03();
}
}
结果:
普通方法执行10亿次:5ms
反射执行10亿次:2761ms
关闭检测后执行10亿次:1491ms
2.6通过反射操作注解
getAnnotations
:获取注解
getAnnotation
:获取指定注解
注解对象.value
:获取注解的值
package com.zhxd.test;
/*
* author zhxd
* ClassName Test07
* date 2022/12/31 16:39
*/
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Test07 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c = Class.forName("com.zhxd.test.Student2");
//通过反射获得注解
Annotation[] annotations = c.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation); //@com.zhxd.test.TableZhxd(value=db_student)
}
//获得注解的value值
TableZhxd tableZhxd = (TableZhxd) c.getAnnotation(TableZhxd.class);
String value = tableZhxd.value();
System.out.println(value);// db_student
//获取字段的注解
Field f = c.getDeclaredField("id");
FieldZhxd annotation = f.getAnnotation(FieldZhxd.class);
System.out.println(annotation.columnName());//db_id
System.out.println(annotation.type());//int
System.out.println(annotation.length());//10
}
}
@TableZhxd(value = "db_student")
class Student2 {
@FieldZhxd(columnName = "db_id", type="int", length=10)
private int id;
@FieldZhxd(columnName = "db_type", type="int", length=10)
private int age;
@FieldZhxd(columnName = "db_length", type="varchar", length=10)
private String name;
public Student2() {
}
public Student2(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 "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//类名注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableZhxd {
String value();
}
//属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldZhxd {
String columnName();
String type();
int length();
}