文章目录
注解
1.什么是注解
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和
Javadoc
不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。
2.常用的注解
@Deprecated -- @Deprecated 所标注内容,不再被建议使用。
@SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
@Override -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
//元注解
@Documented -- @Documented 所标注内容,可以出现在javadoc中。
@Inherited -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
@Retention -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
@Target -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
3.自定义注解
// Target 表示我们的注解可以用在哪些地方,TYPE:类、接口(包括注解类型)或枚举声明
@Target(value = {ElementType.TYPE, ElementType.METHOD})
// Retention 表示我们的注解保留多长时间 runtime>class>sources
@Retention(value = RetentionPolicy.RUNTIME)
// Documented 是否将我们的注解生成在java Doc中
@Documented
// Inherited 子类可以继承父类的注解
@Inherited
public @interface MyAnnotation {
// 注解的参数:参数类型+参数名();
// 注解可以显式赋值,如果没有默认值,我们必须给注解赋值
// 如果只有一个参数,一般参数名为value,使用注解时可以不写value,默认给value赋值
String name() default "";
// 如果默认值为-1,代表不存在
int id() default -1;
}
public class Test {
@MyAnnotation(name="李泽玉")
public void test() {
}
}
使用
@interface
自定义注解时,自动继承了java.lang.annotation.Annotation
接口
反射
Reflection
(反射)是java
被视为动态语言的关键,反射机制允许程序在执行期取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
正常方式:引入需要的“包类”名称->通过
new
实例化->取得实例化对象反射方式:实例化对象->
getClass()
方法->得到完整的“包类”名称
1.Class类的常用方法
public static Class<?> forName(String className)//传入完整的“包.类”名称实例化Class对象
public Object newInstance() //根据Class定义的类实例化对象
public Constructor[] getContructors() //得到一个类的全部的构造方法
public Field[] getDeclaredFields()//得到本类中单独定义的全部属性
public Field[] getFields()//得到本类继承而来的全部属性
public Method[] getMethods()//得到一个类的全部方法
public Method getMethod(String name,Class..parameterType)//返回一个Method对象,并设置一个方法中的所有参数类型
public Class[] getInterfaces() //得到一个类中锁实现的全部接口
public String getName() //得到一个类完整的“包.类”名称
public Package getPackage() //得到一个类的包
public Class getSuperclass() //得到一个类的父类
public Class<?> getComponentType() //返回表示数组类型的Class
public boolean isArray() //判断此class是否是一个数组
测试通过反射获取类的对象
/**
* Created by nanfeng on 2021/08/04
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 一个类在内存中只有一个Class对象
//一个类被加载后,类的整个结构都会被封装在Class对象中
User user = new Student();
System.out.println("这个人是:" + user.name);
//方式一:通过forName获取类的class对象
Class c1 = Class.forName("Student");
System.out.println(c1.hashCode());
//方式二:通过对象获得
Class c2 = user.getClass();
System.out.println(c2.hashCode());
//方式三:通过类名.class获得
Class<Student> c3 = Student.class;
System.out.println(c3.hashCode());
/**
* 结果:
* 这个人是:学生
* 1163157884
* 1163157884
* 1163157884
*/
//获得父类类型
Class c4 = c1.getSuperclass();
System.out.println(c4);
}
}
class User{
protected String name;
private int id;
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
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;
}
}
class Student extends User {
public Student() {
this.name = "学生";
}
}
class Teacher extends User {
public Teacher() {
this.name = "老师";
}
}
2.类的加载与ClassLoader的理解
3.什么时候会发生类的初始化
- 类的主动引用(一定会发生类的初始化)
- 当JVM虚拟机启动,先初始化main方法所在的类
- new 一个类的对象
- 调用类的静态成员(final常量除外)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则会先初始化他的父类
- 类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正申明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化。
- 通过数组定义类引用,不会触发此类的初始化。
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
4.类加载器
具体请参考狂神说jvm入门教学:https://www.bilibili.com/video/BV1iJ411d7jS
笔记请参考:https://blog.csdn.net/weixin_42248256/article/details/114582083
5.获取运行时类的完整结构
提供User
类及其属性和方法
package reflection;
/**
* Created by nanfeng on 2021/08/05
*/
public class User{
protected String name;
private int id;
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
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 static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
//获取类的信息
Class c1 = Class.forName("reflection.User");
//1.获取类的名字
//获得包名 + 类名 reflection.User
System.out.println(c1.getName());
//获得类名 User
System.out.println(c1.getSimpleName());
//2.获得类的属性
//只能找到public属性 “”
Field[] fields = c1.getFields();
for (Field field : fields) {
System.out.println(field);
}
//找到全部的属性
/**
* protected java.lang.String reflection.User.name
* private int reflection.User.id
* private int reflection.User.age
*/
fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//获得指定的属性
//private int reflection.User.age
System.out.println(c1.getDeclaredField("age"));
//3.获得类的方法
//获取本类及其父类全部的public方法
/**
* public java.lang.String reflection.User.toString()
* public java.lang.String reflection.User.getName()
* public int reflection.User.getId()
* public void reflection.User.setName(java.lang.String)
* public void reflection.User.setId(int)
* public void reflection.User.setAge(int)
* public int reflection.User.getAge()
* public final void java.lang.Object.wait() throws java.lang.InterruptedException
* public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
* public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
* public boolean java.lang.Object.equals(java.lang.Object)
* public native int java.lang.Object.hashCode()
* public final native java.lang.Class java.lang.Object.getClass()
* public final native void java.lang.Object.notify()
* public final native void java.lang.Object.notifyAll()
*/
for (Method method : c1.getMethods()) {
System.out.println(method);
}
//获取本类的所有方法
/**
* public java.lang.String reflection.User.toString()
* public java.lang.String reflection.User.getName()
* public int reflection.User.getId()
* public void reflection.User.setName(java.lang.String)
* public int reflection.User.getAge()
* public void reflection.User.setAge(int)
* public void reflection.User.setId(int)
*/
for (Method method : c1.getDeclaredMethods()) {
System.out.println(method);
}
//获得指定方法
/**
* public java.lang.String reflection.User.getName()
* public void reflection.User.setName(java.lang.String)
*/
System.out.println(c1.getMethod("getName", null));
System.out.println(c1.getMethod("setName", String.class));
//4.获取类的构造器
/**
* public reflection.User()
* public reflection.User(java.lang.String,int,int)
*/
for (Constructor constructor : c1.getDeclaredConstructors()) {
System.out.println(constructor);
}
}
6.动态创建对象,通过反射
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//获取Class对象
Class c1 = Class.forName("reflection.User");
//1.构建一个对象
//本质上是调用了类的无参构造器
User user = (User) c1.newInstance();
/**
* User{name='null', id=0, age=0}
*/
System.out.println(user);
//2.通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User lizeyu = (User) constructor.newInstance("lizeyu", 100, 23);
/**
* User{name='lizeyu', id=100, age=23}
*/
System.out.println(lizeyu);
//3.通过反射调用方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke:激活,(对象,“参数的值”)
setName.invoke(lizeyu, "李泽玉");
/**
* User{name='李泽玉', id=100, age=23}
*/
System.out.println(lizeyu);
//4.通过反射操作属性
Field name = c1.getDeclaredField("name");
/**
* 不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true)
*/
name.setAccessible(true);
name.set(lizeyu, "nanfeng");
System.out.println(lizeyu);
}
7.反射操作注解
定义一个类、两个注解
import java.lang.annotation.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by nanfeng on 2021/08/04
*/
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<User> c1 = User.class;
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
/**
* 结果:@Table(value=db_user)
*/
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的value值
Table table = c1.getAnnotation(Table.class);
//结果:@包名 + Table(value=db_user)
System.out.println(table.value());
//获得属性指定的注解
Field f = c1.getDeclaredField("name");
Para annotation= f.getAnnotation(Para.class);
/**
* name
* 10
* String
*/
System.out.println(annotation.columnName());
System.out.println(annotation.length());
System.out.println(annotation.type());
}
}
@Table("db_user")
class User{
@Para(columnName = "name",type = "String",length = 10)
private String name;
@Para(columnName = "id",type = "int",length = 10)
private int id;
@Para(columnName = "age",type = "int",length = 10)
private int age;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
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;
}
}
//类名的注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
String value();
}
//属性的注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Para {
String columnName();
String type();
int length();
}