内置注解:
@Override:表示一个方法打算重写
@Deprecated:表示不鼓励程序员使用这样的元素
@SuppressWarnings:用来抑制编译时的警告信息
元注解:
Target 表示我们的注解可以用在那些地方
Retention 表示我们的注解在什么地方还有效(runtime>class>sources)
Documented 表示是否将我们的注解生成在JAVAdoc中
Inherited 子类可以继承父类的注解
自定义注解:
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
格式:public @interface 注解名 {定义内容}
public class test{
//注解可以显示赋值,如果没有默认值的default,我们就必须给注解赋值
@MyAnnotation(age = 18)
public void test(){}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
//注解的参数: 参数类型 + 参数名();
String name() default "";
int age();
int id() default -1;//如果默认值为-1,代表不存在
String[] schools() default{"重庆城市科技学院"}
}
注意:当参数只有一个时,参数名用value
反射:
获取Class类的实例
1)若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz = Person.class
2)已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class clazz = person.getClass
3)已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz = Class.forName("com.mysql.jdbc.Driver")
4)内置基本数据类型可以直接用类名.Type
5)可以利用ClassLoader
注意:也可以获得父类类型
Clazz clazz1 = clazz.getSuperclass();
那些类型可以有Class对象
class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
interface:接口
[]:数组
enum:枚举
annotation:注解@interface
primittive type:基本数据类型
void
Class clazz = Object.class;//类
Class clazz = Comparable.class;//接口
Class clazz = String[].class;//数组
Class clazz = int[][].class;//二维数组
Class clazz = override.class;//注解
Class clazz = ElementType.class;//枚举
Class clazz = Interger.class; //基本数据类型
Class clazz = Class.class;//Class
Class clazz = void.class;//void
注意:只要是元素类型与维度一样,就是同一个Class.
int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());//与下列值一致
System.out.println(b.getClass().hashCode());
什么时候会发生类的初始化
类的主动引用(一定会发生类的初始化)
当虚拟机启动,先初始化main方法所在的类
new 一个类的对象
调用类的静态成员(除了final常量)和静态方法
使用Java.lang.reflect包的方法对类进行反射调用
当初始化一个类,如果其父类没有被初始化,则先会初始化他的父类
类的被动引用(不会发生类的初始化)
当访问一个静态域时,只有真正申明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
通过数组定义类的引用,不会触发此类的初始化
引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
类加载器
作用:是用来把(class)装载进内存的
类型:引导类加载器:负责Java平台核心库 lib/rt.jat。该加载器无法直接获取
扩展类加载器:负责jre/lib/ext目录下的jar包或-D Java.ext.dirs指定目录下的jar包装入工作室
系统类加载器:Java -classpath 或 -D java.class.path所指的目录下的类与jar包装入工作,是最常见的加载器
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@73d16e93
//获取系统类加载器的父类加载器-->扩展类加载器
ClassLoader parent = systemClassLoader.getParent();
System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@15db9742
//获取扩展类加载器的父类加载器-->根加载器
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//null
//测试当前类是哪个加载器加载的
ClassLoader classLoader = Class.forName("com.mysql.jdbc.Driver").getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@73d16e93
//测试JDK内置的类是谁加载的
ClassLoader classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);//null
//如何获取系统类加载器可以加载的路径
System.out.println("java.class.path")
//双亲委派机制
如果定义了和JDK中相同路径的包 那一定是运行JDK中的
获得类中的信息
//一般通过Class类的静态方法forName()获取Class对象(当然也可以用其他两种)
Class.forName("com.reflection.User")
//获得类的名字
System.out.println(c1.getName());//获得包名+类名
System.out.println(c1.getSimpleName());//类名
//获取类的属性
File[] fields = c1.getFileds();//只能找到public属性的
File[] fields = c1.getDeclaredFileds();//找到全部的属性
//获得指定属性的值
File[] fields = c1.getFiled("name");//要确保name为public才能获得
File[] fields = c1.getDeclaredFiled("name");
/*
获得类的方法
getMethods(); //获得本类及其父类的全部public方法
getDeclaredMethods();//获得本类的所有方法(不包括其父类)
//获取指定的方法
Method getName = c1.getMethod( name: "getName",...parameterTypes: null);
Method setName = cl.getMethod( name: "setName",..parameterTypes: string.class);
system.out.println(getName) ;
system.out. println(setName) ;
//获得构造器
getConstructors();//pubic
getDeclaredConstructors();//全部
/获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
system.out.println("指定: "+declaredconstructor ) ;
*/
创建类的对象:调用class对象的newInstance()方法
1)类必须有一个无参数的构造器
2)类的构造器的访问权限需要足够
注意:并不是没有无参的构造器就不能创建对象,只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,就可以实例化操作
//获取class对象
Class c1 = Class.forName("com.reflection.User");
//创造一个对象
User user = (User)c1.newInstance();//本质上是调用了类的无参构造
System.out.println(user)
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
User user2 = (User)constructor.newInstance( ...initargs:"秦疆",001,18);
System.out.println(user2);
//通过反射调用普通方法
User user3 = (User)c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod( name: "setName",string.class);
//invoke :激活的意思
//(对象,"方法的值")
setName.invoke(user3,"狂神")
system.out.println(user3.getName());
//通过反射操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField( name: "name" );
//不能直接操作私有属性,我们需要设置可访问权限为true
name.setAccessible(true); //setAccessible-设置可访问的(设置访问性) true可访问 false不可访问
name.set(user4, "狂神2");
system.out.println(user4.getName());
性能对比
普通方法>反射方式(设置可访问权限)>一般反射方式
获取泛型信息https://www.bilibili.com/video/BV1p4411P7V3?p=15&spm_id_from=pageDriver
获取注解信息https://www.bilibili.com/video/BV1p4411P7V3?p=16&spm_id_from=pageDriver