内置注解
- @override :表示一个方法声明打算重写超类的另一个方法声明
- @Deprecated: 表示不鼓励程序员使用这样的元素
- @suppressWarnings: 用来抑制编译时的警告信息
元注解
- @target: 用于描述注解的使用范围(类,方法)
- @Retention:表示需要在什么级别保存该注解信息,用于描述注解的生命周期(source < class <runtime)
- @Document:说明该注解将被包含在javadoc中
- @Inherited: 说明子类可以继承父类中的该注解
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author by whs
* @date 2020/12/21.
*/
@Annotationtest
public class MyAnnotation {
public static void main(String[] args) {
}
@Annotationtest
public void test(){}
}
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface Annotationtest{
}
自定义注解
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author by whs
* @date 2020/12/21.
*/
public class Test03 {
@MyAnnotation03(age = 18)
public void test04(){ }
@MyAnnotation04("hello")
public void test05(){}
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation03{
//注解的参数:参数类型 + 参数名 ();
String name() default "";
int age();
int id() default -1;
String[] schools() default {"西北大学","清华大学"};
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation04{
//当使用value时,可以省略
String value();
}
反射(Reflection)
- 反射机制允许程序在执行期借助于ReflectionApi 取得任何类的内部信息,并能直接操作任意对象内部信息及方法。
- Class c = Class.forName(“java.lang.String”)
- 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。
- 正常的方式:引入需要的“包类”名称 -->通过new实例化–>获取实例化对象
- 反射方式:实例化对象–>getClass()方法–>得到完整的“包类”对象
- 优点:
- 可以实现动态创建对象和编译,体现出很大的灵活性
- 缺点:
- 对性能影响很大。使用反射基本上是一种解释操作,这类操作总是慢于直接执行相同的操作
第一个反射代码
package Reflection;
/**
* @author by whs
* @date 2020/12/21.
*/
public class test01 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("Reflection.User");
Class c2 = Class.forName("Reflection.User");
Class c3 = Class.forName("Reflection.User");
Class c4 = Class.forName("Reflection.User");
System.out.println(c1);
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
}
}
//实体类 {pojo,entity}
class User {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
Class 类
- 在Object类中定义了以下的方法,以此方法被所有子类继承
- public final Class getClass()
- 以上的方法返回值的类型是一个Class类,此类是Java反射的源头。
常用方法
- Static Class.forName(String name) 指定类名name的Class对象
- Object NewInstance() 调用缺省的构造方法,返回Class对象的一个实例
- getName() 返回此Class对象所表示的实体(类、接口、数组类、或void)的名称
- Class getSuperClass() 返回当前Class对象的父类的Class对象
- Class[] getinterfaces() 获取当前Class对象的接口
- ClassLoader getClassLoader() 返回该类的类加载器
- Constuctor[] getConstuctors() 返回一个包含某些Constuctor对象的数组
- Method getMethod(String name ,Class… T) 返回一个Method对象,此对象的形参类型为ParamType
- Field[] getDeclaredFields() 返回Field对象的一个数组(属性)
- Field[] getFields() 返回Field对象的一个数组(public属性)
class类的创建方式有哪些
package Reflection;
import java.lang.annotation.Target;
/**
* @author by whs
* @date 2020/12/21.
*/
public class test02 {
public static void main(String[] args) throws ClassNotFoundException {
Person person = new Stuent();
System.out.println("这个人是:"+person.name);
//1.通过对象获取
Class c1 = person.getClass();
System.out.println(c1.hashCode());
//2.通过forname获得
Class<?> c2 = Class.forName("Reflection.Stuent");
System.out.println(c2.hashCode());
//3.通过类名.Class获得
Class<Stuent> c3 = Stuent.class;
System.out.println(c3.hashCode());
//4.基本内置类型的包装类都有一个Type操作
Class<Integer> c4 = Integer.TYPE;
System.out.println(c4);
}
}
//Person类
class Person{
String name;
public Person(){}
public Person(String name){
this.name =name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
//学生类
class Stuent extends Person{
public Stuent(){
this.name = "学生";
}
}
//老师类
class Teacher extends Person{
public Teacher(){
this.name = "老师";
}
}
类的加载
- 加载: 将Class文件字节码内容加载到内存中,并将这些静态数据转换成方法区运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
- 链接:将java类的二进制代码合并到jvm的运行状态之中的过程
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区进行分配
- 解析:虚拟机常量池内的符合引用(常量名)替换为直接引用(地址)的过程
- 初始化:
- 执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中所有类变量的赋值动作和静态变量代码块的语句合并产生的,(类构造器是构造信息的,不是构造该类对象的构造器)
- 当初始化一个类的时候,如果发现器父类没有初始化,则需要先触发其父类的初始化
- 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步
加载过程
package Reflection;
/**
* @author by whs
* @date 2020/12/21.
*/
public class LoaderTest {
public static void main(String[] args) {
A a = new A();
System.out.println(a.num);
}
}
class A{
static {
num = 30;
System.out.println("静态代码块执行了");
}
static int num = 10;
public A(){
System.out.println("无参构造初始化");
}
}
//结果
静态代码块执行了
无参构造初始化
10
什么时候会发生类初始化
- 类的主动引用(一定会发生类的初始化)
- 当虚拟机启动,先初始化main方法所在的类
- new 一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
- 类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
加载过程
package Reflection;
/**
* @author by whs
* @date 2020/12/21.
*/
public class test03 {
static {
System.out.println("main被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//主动引用
//Son son = new Son();
//反射也会主动引用
//Class aClass = Class.forName("Reflection.Son");
//不会产生类的引用方法
//System.out.println(Son.b);
//Son[] array = new Son[5];
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;
}
类加载器
- 引导类加载器:是JVM自带的类加载器,负责JAVA平台核心库,用来装载核心类库。该加载器无法直接获取
- 扩展加载器:负责jre/lib/ext目录下的jar包或者-D java.ext.dirs指定目录下的jar包装入工作库
- 系统加载器:负责java -classpath或 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器。
反射方法
package Reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author by whs
* @date 2020/12/21.
*/
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class c1 = Class.forName("Reflection.User");
//使用无参构造器
User user1 = (User)c1.newInstance();
System.out.println(user1);
//通过构造器创建对象
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
User user = (User)declaredConstructor.newInstance("张三",001,18);
System.out.println(user);
//通过属性操作方法
User user3 = (User)c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke:激活的意思
setName.invoke(user3,"三哥");
System.out.println(user3.getName());
//通过反射操作属性
System.out.println("===========");
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,关闭程序的安全检测
name.setAccessible(true);
name.set(user4,"三哥二");
System.out.println(user4.getName());
}
}
反射操作泛型
package Reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* @author by whs
* @date 2020/12/21.
*/
public class Test006 {
public void test1(Map<String,User> map, List<User>list){
System.out.println("test1");
}
public Map<String,User> test2(){
System.out.println("test2");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method test1 = Test006.class.getMethod("test1", Map.class, List.class);
//test1
Type[] genericParameterTypes = test1.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("test2");
//test2
Method test2 = Test006.class.getMethod("test2", null);
Type genericReturnType = test2.getGenericReturnType();
if(genericReturnType instanceof ParameterizedType){
//获取真实的参数
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("~~~~~"+actualTypeArgument);
}
}
}
}
- ParameterizedType :表示一种参数化类型,比如Collection
- GenericArrayType: 表示一种元素类型是参数化类型或者类型变量的数组类型
- TypeVariable: 是各种类型变量的公共接口
- WildcardType:代表一种通配符类型表达式