1.注解入门
注解 不是程序本身,但对程序可以做出解释,也可以被其他程序读取(编译器)
注解的格式: @+注解名,还可以加参数值
注解使用场合: package class method field(字段0)
2.内置注解
/* @Override 就是注解,是重写的注解
@Deprecated的程序元素是程序员不鼓励使用的程序元素,通常是因为它是危险的,或者因为存在更好的替代方法。编译器在不被弃用的代码中使用或覆盖不推荐使用的程序元素时发出警告。
@SuppressWarnings("all")表示在注释元素(以及注释元素中包含的所有程序元素)中应该抑制命名的编译器警告。请注意,给定元素中抑制的一组警告是所有包含元素中抑制的警告的超集。例如,如果您注释一个类来抑制一个警告并注释方法来抑制另一个警告,则两个警告将在该方法中被抑制。
*/
3.自定义注解,元注解
3.1元注解
- 作用:负责注解其他注解,Java中定义了四个标准的meta-annotation类型,被用来提供对其他annotation类型作说明
- 四个类分别为:
- @Target: 用于描述注解的适用范围
- @Retention 表示在什么级别保存该注释信息,用于描述注解的生命周期
- @Document:说明该注解将被包含在Javadoc中
- @Inher:说明子类可以继承父类中的注解
3.2自定义注解
package Annotation;
import java.lang.annotation.*;
@MyAnnotation(name = "Lee",schools = {"西电大"})
public class Test02 {
}
@Documented // 可以包含在JavaDoc文档中
@Inherited //子类可以继承父类的注解
@Retention(RetentionPolicy.CLASS)//保留注解到什么级别:RUNTIME>CLASS>SOURCE
@Target(ElementType.TYPE) //作用域
@interface MyAnnotation{
//注解的参数问题:类型 + 参数名 + ();
//1. 只有一个参数的话, 一般使用value作为参数名 赋值可以省略前边的“=”
//2. 可以有默认值,可以不用赋值
//3. 不分先后顺序
String[] schools();
String name();
int age() default 18;
}
4.反射概述
4.1概述
-
官方解释:
在程序运行的过程中,可以动态的创建对象,并获取对象的基本信息,包括属性、方法等;
-
虽然你可以在Java中由很多对象,但这些对象在反射面前就是裸奔的,反射可以打破Java语言的封装特性。
静态:运行时不可变的语言。如:C,C++,java
动态:运行时可以改变其结构的语言。eg:新的函数、对象甚至代码可以被引进,已有的函数可以被删除……**就是运行时代码可以根据某些条件改变自身结构。**如JavaScript、PHP、Python……
Java因为反射机制,可以获得类似动态语言的特性,Java可以称为“准动态语言”
**正常方式:**引入所需要的包类名称—>通过new实例化—>获得实例对象
**反射方式: ** 实例化对象—>getClass()方法—>得到完整的包类名称
4.2Java反射机制提供的功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
- ……
4.3Java反射的优缺点:
优点:可以实现动态的创建对象和编译,灵活性
缺点:对性能有一定的影响。使用反射基本上是一种解释操作,jvm满足我们的要求,这类操作总是慢于直接执行相同的操作
5.理解class类并获取Class实例
package reflection;
//测试Class类的几种创建方式
public class test01 {
public static void main(String[] args) throws ClassNotFoundException {
Person student = new Student();
System.out.println("这个人是--->" + student.name);
//1. 通过对象获得
Class c1 = student.getClass();
System.out.println(c1.hashCode());
//2. Class.forname()获得
Class c2 = Class.forName("reflection.Student");
System.out.println(c2.hashCode());
//3. 通过类名获得
Class c3 = Student.class;
System.out.println(c3.hashCode());
//4. 基本内置对象都有一个Type的属性
Class c4 = Integer.TYPE;
System.out.println(c4);
//5. 获得父类对象
Class c5 = c1.getSuperclass();
System.out.println(c5);
}
}
class Person{
private int id;
private int age;
String name;
public Person() {
this.name = "老师";
}
public Person(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 "Person{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name = "学生";
}
}
class Teacher extends Person{
public Teacher(){
this.name = "老师";
}
}
所有类型的class
//所有类型的class
public class test02 {
public static void main(String[] args) {
Class c1 = Object.class; //类
Class c2 = Runnable.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());
}
}
6.类的加载与ClassLoader
6.1类的加载
//类加载内存分析
public class Test03 {
public static void main(String[] args) {
A a = new A();
System.out.println(a.m);
/*
1.将A类加载到内存 , 产生该类的Class对象
2.链接 给类变量设置默认初始值 即 m=0;
3.初始化
<clinit>(){
System.out.println("A类静态代码初始化");
m = 300;
m = 100;
}
*/
}
}
class A{
static {
System.out.println("A类静态代码初始化");
m = 300;
}
static int m = 100;
public A(){
System.out.println("A类的无参构造");
}
}
6.2类的初始化
package reflection;
public class Test04 {
static {
System.out.println("main类被加载");
}
public static void main(String[] args) throws ClassNotFoundException {
//什么时候会发生类的初始化(主动引用时)
//1.new一个类的对象时
//Son son = new Son();
//2.调用静态变量和静态方法时
//System.out.println(Son.a);
//3.通过反射引用时
//Class c1 = Class.forName("reflection.Son");
//System.out.println(c1);
//不会发生类的初始化(被动引用)
//1.通过子类调用父类的静态变量 , 不会导致子类被初始化
//System.out.println(Son.b);
//2.数组定义类
Son[] sons = new Son[5];
}
}
class Father{
static {
System.out.println("父类被加载");
}
static int b = 20;
}
class Son extends Father{
static{
System.out.println("子类被加载");
}
static int a = 10;
public Son() {
System.out.println("子类的无参构造");
}
}
6.3类的加载器
package reflection;
//类的加载器
/*
根加载器-->负责Java的核心类库-->rt
拓展加载器-->负责Java类库中另一个类库-->ext
用户加载器-->
*/
public class Test05 {
public static void main(String[] args) throws ClassNotFoundException {
//获得系统类的加载器(最常用的加载器)--->用户加载器
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
System.out.println(classLoader);
//获得当前类加载器的父类--->拓展加载器
classLoader = classLoader.getParent();
System.out.println(classLoader);
//获得拓展加载器的父类--->根加载器(C/C++编写java无法直接显示)
classLoader = classLoader.getParent();
System.out.println(classLoader);
//测试当前类是哪一个加载器加载的
classLoader = Class.forName("reflection.Test05").getClassLoader();
System.out.println(classLoader);//用户加载器
//测试jdk内部类
classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);//根加载器
//获得系统类加载器的路径
System.out.println(System.getProperty("java.class.path"));
//双亲委派机制-->从用户加载器逐级向上检查 写与内置类重名类时 自动覆盖
/*
双亲委派机制,的确是防止同名包、类与 jdk 中的相冲突,实际上加载类的时候,先通知 appLoader,看 appLoader 是否已经缓存,没有的话,appLoader 又委派给他的父类加载器(extLoader)询问,看他是不是能已经缓存加载,没有的话,extLoader 又委派他的父类加载器(bootstrapLoader)询问,BootstrapLoader看是不是自己已缓存或者能加载的,有就加载,没有再返回 extLoader,extLoader 能加载就加载,不能的话再返回给 appLoader 加载,再返回的路中,谁能加载,加载的同时也加缓存里。正是由于不停的找自己父级,所以才有 Parents 加载机制,翻译过来叫 双亲委派机制。
/*
D:\JAVA\jdk\jre\lib\charsets.jar;
D:\JAVA\jdk\jre\lib\deploy.jar;
D:\JAVA\jdk\jre\lib\ext\access-bridge-64.jar;
D:\JAVA\jdk\jre\lib\ext\cldrdata.jar;
D:\JAVA\jdk\jre\lib\ext\dnsns.jar;
D:\JAVA\jdk\jre\lib\ext\jaccess.jar;
D:\JAVA\jdk\jre\lib\ext\jfxrt.jar;
D:\JAVA\jdk\jre\lib\ext\localedata.jar;
D:\JAVA\jdk\jre\lib\ext\nashorn.jar;
D:\JAVA\jdk\jre\lib\ext\sunec.jar;
D:\JAVA\jdk\jre\lib\ext\sunjce_provider.jar;
D:\JAVA\jdk\jre\lib\ext\sunmscapi.jar;
D:\JAVA\jdk\jre\lib\ext\sunpkcs11.jar;
D:\JAVA\jdk\jre\lib\ext\zipfs.jar;
D:\JAVA\jdk\jre\lib\javaws.jar;
D:\JAVA\jdk\jre\lib\jce.jar;
D:\JAVA\jdk\jre\lib\jfr.jar;
D:\JAVA\jdk\jre\lib\jfxswt.jar;
D:\JAVA\jdk\jre\lib\jsse.jar;
D:\JAVA\jdk\jre\lib\management-agent.jar;
D:\JAVA\jdk\jre\lib\plugin.jar;
D:\JAVA\jdk\jre\lib\resources.jar;
D:\JAVA\jdk\jre\lib\rt.jar;
D:\JavaEE\projects\注解与反射\out\production\注解与反射;
D:\JavaEE\idea\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar
*/
}
}
7.创建运行时类的对象
7.1通过反射获取类的信息
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@SuppressWarnings("all")
//获得类的信息
//获得指定类时,参数均为class对象
public class Test06 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("reflection.Person");
//获得类的名字
System.out.println(c1.getName());//完整的名字 包名+类名
System.out.println(c1.getSimpleName());//类名
System.out.println("====================");
//获取类的属性
Field[] fields = c1.getFields();//获取类的所有public属性
for (Field field : fields) {
System.out.println(field);
}
fields = c1.getDeclaredFields();//获取类的所有属性 包括私有
for (Field field : fields) {
System.out.println(field);
}
Field name = c1.getDeclaredField("name");//获取指定属性,同上
System.out.println(name);
System.out.println("====================");
//获取类的方法
Method[] methods = c1.getMethods();//获取当前类及其父类的所有public方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("====================");
methods = c1.getDeclaredMethods();//获取当前类的所有方法
for (Method method : methods) {
System.out.println(method);
}
System.out.println("====================");
System.out.println(c1.getMethod("getName", null));
System.out.println(c1.getDeclaredMethod("setAge", int.class));
System.out.println("====================");
//获取类的构造器
Constructor[] constructors = c1.getConstructors();//获取类的public构造器
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
//获得类的指定构造器
Constructor constructor
= c1.getConstructor(int.class,int.class,String.class);
System.out.println(constructor);
}
}
7.2动态创建类对象及操作类的信息
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//动态创建对象执行方法
/*
Method,Field,Constructor对象都有setAccessible()方法
setAccessible()为了开启或关闭安全检测
true为关闭
1.提高反射的效率
2.使得原本是私有权限的也可以被访问
*/
public class Test07 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class c1 = Class.forName("reflection.Person");
Person person = (Person) c1.newInstance();//必须要有无参构造器
System.out.println(person);
//当没有无参构造器时
/*
1.通过Class对象获取一个构造器
2.向构造器中传入参数(对象,参数值)
*/
Constructor constructor
= c1.getDeclaredConstructor(int.class, int.class, String.class);
Person person1 = (Person)constructor.newInstance(001, 18, "小明");
System.out.println(person1);
//通过反射调用普通方法
/*
1.创建一个对象
2.通过反射获取一个方法
3.得到的方法通过invoke(对象,参数值)设置参数
*/
Person person3 = (Person) c1.newInstance();
Method setName = c1.getMethod("setName", String.class);
setName.invoke(person3,"小刚");
System.out.println(person3);
//通过反射操作属性
/*
1.获取属性
2.给私有属性关闭安全检测setAccessible(true)
3.通过set(对象,参数值)操作属性
*/
Person person4 = (Person) c1.newInstance();
Field age = c1.getDeclaredField("age");
age.setAccessible(true);
age.set(person4,18);
System.out.println(person4);
}
}
7.3性能测试
package reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//测试性能
public class Test08 {
//普通方式
public static void test1(){
Person person = new Person();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10_0000_0000; i++) {
person.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式需要:"+(endTime-startTime)+"ms");
}
//反射方式
public static void test2() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class c1 = Person.class;
Person person = (Person)c1.newInstance();
Method getName = c1.getMethod("getName");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10_0000_0000; i++) {
getName.invoke(person,null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式需要:"+(endTime-startTime)+"ms");
}
//反射方式 关闭安全检测
public static void test3() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class c1 = Person.class;
Person person = (Person)c1.newInstance();
Method getName = c1.getMethod("getName");
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10_0000_0000; i++) {
getName.invoke(person,null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭检测需要:"+(endTime-startTime)+"ms");
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
test1();//3ms
test2();//2128ms
test3();//1038ms
}
}
7.4获取泛型
package reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
//通过反射获取泛型
public class Test09 {
public static void test1(Map<String,Person> map){
}
public static Map<String,Person> test2(){
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
Method method = Test09.class.getMethod("test1", Map.class);
Type[] parameterTypes = method.getGenericParameterTypes();
for (Type parameterType : parameterTypes) {
System.out.println(parameterType);
if(parameterType instanceof ParameterizedType)//是否为参数化类型
{
//如果为参数化类型,强制转换为参数化类型,获得其真实的参数类型
Type[] actualTypeArguments = ((ParameterizedType) parameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
method = Test09.class.getMethod("test2",null);
Type genericReturnType = method.getGenericReturnType();
System.out.println(genericReturnType);
if(genericReturnType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
7.5获取注解
package reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
//通过反射获取注解
public class Test10 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Student1.class;
TableAnnotation annotation = (TableAnnotation)c1.getAnnotation(TableAnnotation.class);
System.out.println(annotation);
System.out.println(annotation.value());
//获得属性的注解
Field id = c1.getDeclaredField("id");
FieldAnnotation annotation1 = id.getAnnotation(FieldAnnotation.class);
System.out.println(annotation1);
System.out.println(annotation1.column());
System.out.println(annotation1.type());
System.out.println(annotation1.length());
}
}
@TableAnnotation("db_Student")
class Student1{
@FieldAnnotation(column = "db_id",type = "int",length = 10)
private int id;
@FieldAnnotation(column = "db_age",type = "int",length = 3)
private int age;
@FieldAnnotation(column = "db_name",type = "String",length = 5)
private String name;
public Student1() {
}
public Student1(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 "Student1{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldAnnotation{
String column();
String type();
int length();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableAnnotation{
String value();
}